diff options
Diffstat (limited to 'linux/drivers/media/common/saa7146_core.c')
-rw-r--r-- | linux/drivers/media/common/saa7146_core.c | 284 |
1 files changed, 79 insertions, 205 deletions
diff --git a/linux/drivers/media/common/saa7146_core.c b/linux/drivers/media/common/saa7146_core.c index f45830613..67f2d3734 100644 --- a/linux/drivers/media/common/saa7146_core.c +++ b/linux/drivers/media/common/saa7146_core.c @@ -193,153 +193,18 @@ static void interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) } /*********************************************************************************/ -/* extension handling functions */ - -void try_attach_extension_and_device(struct saa7146_dev *dev, struct saa7146_extension *ext) -{ - int i = 0; - int found = 0; - - DEB_EE(("dev:%p, ext:%p, num:%d\n",dev,ext,saa7146_num)); - - /* check if already handled by extension */ - if( 0 != dev->ext ) { - return; - } - - DEB_S(("Trying device %p...\n",dev)); - - /* first check the subvendor and subdevice ids */ - for(i = 0;;i++) { - if( 0xffff == ext->devices[i].subvendor - && 0xffff == ext->devices[i].subdevice ) { - break; - } - if( ext->devices[i].subvendor == dev->pci->subsystem_vendor - && ext->devices[i].subdevice == dev->pci->subsystem_device ) { - found = 1; - break; - } - } - if( 0 == found ) { - DEB_S(("extension %p does not handle this device. skipping.\n",ext)); - return; - } - - dev->ext = ext; - if( 0 != ext->probe) { - if( 0 != ext->probe(dev, dev->pci->subsystem_vendor, dev->pci->subsystem_device) ) { - DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); - dev->ext = NULL; - return; - } - } - - if( 0 != ext->attach(dev, &ext->devices[i]) ) { - DEB_D(("ext->attach() failed for %p. skipping device.\n",dev)); - dev->ext = NULL; - return; - } -} - -static int try_match_device_to_extension(struct saa7146_dev *dev) -{ - struct list_head *list = NULL; - - DEB_EE(("dev:%p\n",dev)); - - if (down_interruptible(&saa7146_devices_lock)) - return -ERESTARTSYS; - - list_for_each(list,&extensions) { - struct saa7146_extension *ext = list_entry(list, struct saa7146_extension, item); - try_attach_extension_and_device(dev,ext); - } - - up(&saa7146_devices_lock); - return 0; -} - -static int try_match_extension_to_device(struct saa7146_extension *ext) -{ - struct list_head *list = NULL; - struct saa7146_dev *dev = NULL; - - DEB_EE(("ext:%p, num:%d\n",ext,saa7146_num)); - - if( 0 == saa7146_num ) { - return 0; - } - - if (down_interruptible(&saa7146_devices_lock)) - return -ERESTARTSYS; - - list_for_each(list,&saa7146_devices) { - dev = list_entry(list, struct saa7146_dev, item); - try_attach_extension_and_device(dev,ext); - } - - up(&saa7146_devices_lock); - return 0; -} - -int saa7146_register_extension(struct saa7146_extension* ext) -{ - DEB_EE(("ext:%p\n",ext)); - - if( 0 == initialized ) { - INIT_LIST_HEAD(&saa7146_devices); - init_MUTEX(&saa7146_devices_lock); - INIT_LIST_HEAD(&extensions); - initialized = 1; - } - - INIT_LIST_HEAD(&ext->item); - list_add_tail(&ext->item,&extensions); - - return try_match_extension_to_device(ext); -} - -int saa7146_unregister_extension(struct saa7146_extension* ext) -{ - struct saa7146_dev *dev = NULL; - struct list_head *list = NULL;; - - DEB_EE(("ext:%p\n",ext)); - - down(&saa7146_devices_lock); - - list_for_each(list,&saa7146_devices) { - dev = list_entry(list, struct saa7146_dev, item); - - /* check if handled by this extension */ - if( ext != dev->ext ) { - continue; - } - - if( 0 != ext->detach(dev) ) { - DEB_D(("ext->detach() failed. ignoring.\n")); - } - - dump_registers(dev); - dev->ext = NULL; - - } - list_del(&ext->item); - - up(&saa7146_devices_lock); - - return 0; -} - -/*********************************************************************************/ /* configuration-functions */ -static int config_a_device(struct pci_dev *pci) +static +int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent) { unsigned long adr = 0, len = 0; struct saa7146_dev* dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL); - + + struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data; + struct saa7146_extension* ext = pci_ext->ext; + int err = 0; + if (!(dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL))) { ERR(("out of memory.\n")); return -ENOMEM; @@ -352,8 +217,8 @@ static int config_a_device(struct pci_dev *pci) if (pci_enable_device(pci)) { ERR(("pci_enable_device() failed.\n")); - kfree(dev); - return -EIO; + err = -EIO; + goto pci_error; } /* enable bus-mastering */ @@ -363,8 +228,8 @@ static int config_a_device(struct pci_dev *pci) /* get chip-revision; this is needed to enable bug-fixes */ if( 0 > pci_read_config_dword(dev->pci, PCI_CLASS_REVISION, &dev->revision)) { ERR(("pci_read_config_dword() failed.\n")); - kfree(dev); - return -ENODEV; + err = -ENODEV; + goto pci_error; } dev->revision &= 0xf; @@ -374,15 +239,14 @@ static int config_a_device(struct pci_dev *pci) if (!request_mem_region(pci_resource_start(pci,0), pci_resource_len(pci,0), "saa7146")) { ERR(("request_mem_region() failed.\n")); - kfree(dev); - return -ENODEV; + err = -ENODEV; + goto pci_error; } if (!(dev->mem = ioremap(adr,len))) { ERR(("ioremap() failed.\n")); - release_mem_region(adr,len); - kfree(dev); - return -ENODEV; + err = -ENODEV; + goto ioremap_error; } /* we don't do a master reset here anymore, it screws up @@ -406,26 +270,30 @@ static int config_a_device(struct pci_dev *pci) dev->name, dev)) { ERR(("request_irq() failed.\n")); - iounmap(dev->mem); - release_mem_region(adr,len); - kfree(dev); - return -EINVAL; + err = -ENODEV; + goto irq_error; } /* get memory for various stuff */ dev->rps0 = (u32*)kmalloc(SAA7146_RPS_MEM, GFP_KERNEL); - if( NULL == dev->rps0 ) + if( NULL == dev->rps0 ) { + err = -ENOMEM; goto kmalloc_error_1; + } memset(dev->rps0, 0x0, SAA7146_RPS_MEM); dev->rps1 = (u32*)kmalloc(SAA7146_RPS_MEM, GFP_KERNEL); - if( NULL == dev->rps1 ) + if( NULL == dev->rps1 ) { + err = -ENOMEM; goto kmalloc_error_2; + } memset(dev->rps1, 0x0, SAA7146_RPS_MEM); dev->i2c_mem = (u32*)kmalloc(SAA7146_I2C_MEM, GFP_KERNEL); - if( NULL == dev->i2c_mem ) + if( NULL == dev->i2c_mem ) { + err = -ENOMEM; goto kmalloc_error_3; + } memset(dev->i2c_mem, 0x00, SAA7146_I2C_MEM); /* the rest + print status message */ @@ -434,7 +302,7 @@ static int config_a_device(struct pci_dev *pci) sprintf(&dev->name[0], "saa7146 (%d)",saa7146_num); INFO(("found saa7146 @ mem 0x%08x (revision %d, irq %d) (0x%04x,0x%04x).\n", (unsigned int)dev->mem, dev->revision,dev->pci->irq,dev->pci->subsystem_vendor,dev->pci->subsystem_device)); - dev->ext = NULL; + dev->ext = ext; pci_set_drvdata(pci,dev); @@ -451,25 +319,49 @@ static int config_a_device(struct pci_dev *pci) dev->module = THIS_MODULE; init_waitqueue_head(&dev->i2c_wq); - return try_match_device_to_extension(dev); + if( 0 != ext->probe) { + if( 0 != ext->probe(dev) ) { + DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); + err = -ENODEV; + goto probe_error; + } + } + if( 0 != ext->attach(dev,pci_ext) ) { + DEB_D(("ext->attach() failed for %p. skipping device.\n",dev)); + err = -ENODEV; + goto attach_error; + } + err = 0; + goto out; +attach_error: +probe_error: + pci_set_drvdata(pci,NULL); + kfree( dev->i2c_mem ); kmalloc_error_3: kfree( dev->rps1 ); kmalloc_error_2: kfree( dev->rps0 ); kmalloc_error_1: - ERR(("kmalloc() failed.\n")); + free_irq(dev->pci->irq, (void *)dev); +irq_error: iounmap(dev->mem); +ioremap_error: release_mem_region(adr,len); +pci_error: kfree(dev); - - return -ENOMEM; +out: + return err; } -static void unconfig_a_device(struct saa7146_dev* dev) +static +void saa7146_remove_one(struct pci_dev *pdev) { + struct saa7146_dev* dev = (struct saa7146_dev*) pci_get_drvdata(pdev); DEB_EE(("dev:%p\n",dev)); + dev->ext->detach(dev); + /* shut down all video dma transfers */ saa7146_write(dev, MC1, 0x00ff0000); @@ -492,68 +384,51 @@ static void unconfig_a_device(struct saa7146_dev* dev) saa7146_num--; } +/*********************************************************************************/ +/* extension handling functions */ -static -int __devinit saa7146_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +int saa7146_register_extension(struct saa7146_extension* ext) { - DEB_EE(("pdev:%p\n",pdev)); + DEB_EE(("ext:%p\n",ext)); - if (config_a_device(pdev)) - return -EINVAL; + if( 0 == initialized ) { + INIT_LIST_HEAD(&saa7146_devices); + init_MUTEX(&saa7146_devices_lock); + INIT_LIST_HEAD(&extensions); + initialized = 1; + } - return 0; + ext->driver.name = "saa7146"; + ext->driver.id_table = ext->pci_tbl; + ext->driver.probe = saa7146_init_one; + ext->driver.remove = saa7146_remove_one; + + return pci_module_init(&ext->driver); } - -static -void __devexit saa7146_remove_one(struct pci_dev *pdev) +int saa7146_unregister_extension(struct saa7146_extension* ext) { - struct saa7146_dev* dev = (struct saa7146_dev*) pci_get_drvdata(pdev); - - DEB_EE(("pdev:%p\n",pdev)); - unconfig_a_device(dev); + DEB_EE(("ext:%p\n",ext)); + pci_unregister_driver(&ext->driver); + return 0; } - -static -struct pci_device_id saa7146_pci_tbl[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - } , { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, saa7146_pci_tbl); - -static -struct pci_driver saa7146_driver = { - .name = "saa7146", - .id_table = saa7146_pci_tbl, - .probe = saa7146_init_one, - .remove = __devexit_p(saa7146_remove_one) -}; - - static -int __init saa7146_init_module(void) +int saa7146_init_module(void) { + printk("saa7146_init_module()\n"); if( 0 == initialized ) { INIT_LIST_HEAD(&saa7146_devices); init_MUTEX(&saa7146_devices_lock); INIT_LIST_HEAD(&extensions); initialized = 1; } - - return pci_module_init(&saa7146_driver); + return 0; } - static void __exit saa7146_cleanup_module(void) { - pci_unregister_driver(&saa7146_driver); } module_init(saa7146_init_module); @@ -579,4 +454,3 @@ EXPORT_SYMBOL_GPL(saa7146_devices_lock); MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); MODULE_DESCRIPTION("driver for generic saa7146-based hardware"); MODULE_LICENSE("GPL"); - |