summaryrefslogtreecommitdiff
path: root/linux/drivers/media/common/saa7146_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/common/saa7146_core.c')
-rw-r--r--linux/drivers/media/common/saa7146_core.c284
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");
-