diff options
-rw-r--r-- | drivers/media/video/cx88/cx88-blackbird.c | 178 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-cards.c | 2 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-dvb.c | 197 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-mpeg.c | 344 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88.h | 46 |
5 files changed, 591 insertions, 176 deletions
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 4673832..0037188 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -50,7 +50,6 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); #define dprintk(level,fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg) -static LIST_HEAD(cx8802_devlist); /* ------------------------------------------------------------------ */ @@ -882,7 +881,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE); - cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); + cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook); blackbird_initialize_codec(dev); cx88_set_scale(dev->core, dev->width, dev->height, @@ -914,11 +913,15 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, } default: - return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); + return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook); } return 0; } +int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +unsigned int (*cx88_ioctl_translator)(unsigned int cmd); + static unsigned int mpeg_translate_ioctl(unsigned int cmd) { return cmd; @@ -927,33 +930,48 @@ static unsigned int mpeg_translate_ioctl(unsigned int cmd) static int mpeg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - cmd = mpeg_translate_ioctl( cmd ); - return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl); + cmd = cx88_ioctl_translator( cmd ); + return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook); } static int mpeg_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct cx8802_dev *h,*dev = NULL; + struct cx8802_dev *dev = NULL; struct cx8802_fh *fh; - struct list_head *list; + struct cx8802_driver *drv = NULL; + int err; - list_for_each(list,&cx8802_devlist) { - h = list_entry(list, struct cx8802_dev, devlist); - if (h->mpeg_dev->minor == minor) - dev = h; - } - if (NULL == dev) + dprintk( 1, "%s\n", __FUNCTION__); + + dev = cx8802_get_device(inode); + if (dev == NULL) return -ENODEV; - if (blackbird_initialize_codec(dev) < 0) + /* Make sure we can acquire the hardware */ + drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); + if (drv) { + err = drv->request_acquire(drv); + if(err != 0) { + dprintk(1,"%s: Unable to acquire hardware, %d\n", __FUNCTION__, err); + return err; + } + } + + if (blackbird_initialize_codec(dev) < 0) { + if (drv) + drv->request_release(drv); return -EINVAL; + } dprintk(1,"open minor=%d\n",minor); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) + if (NULL == fh) { + if (drv) + drv->request_release(drv); return -ENOMEM; + } file->private_data = fh; fh->dev = dev; @@ -974,6 +992,8 @@ static int mpeg_open(struct inode *inode, struct file *file) static int mpeg_release(struct inode *inode, struct file *file) { struct cx8802_fh *fh = file->private_data; + struct cx8802_dev *dev = NULL; + struct cx8802_driver *drv = NULL; /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, @@ -992,6 +1012,16 @@ static int mpeg_release(struct inode *inode, struct file *file) videobuf_mmap_free(&fh->mpegq); file->private_data = NULL; kfree(fh); + + /* Make sure we release the hardware */ + dev = cx8802_get_device(inode); + if (dev == NULL) + return -ENODEV; + + drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); + if (drv) + drv->request_release(drv); + return 0; } @@ -1043,6 +1073,44 @@ static struct video_device cx8802_mpeg_template = /* ------------------------------------------------------------------ */ +/* The CX8802 MPEG API will call this when we can use the hardware */ +static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + + switch (core->board) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* By default, core setup will leave the cx22702 out of reset, on the bus. + * We left the hardware on power up with the cx22702 active. + * We're being given access to re-arrange the GPIOs. + * Take the bus off the cx22702 and put the cx23416 on it. + */ + cx_clear(MO_GP0_IO, 0x00000080); /* cx22702 in reset */ + cx_set(MO_GP0_IO, 0x00000004); /* Disable the cx22702 */ + break; + default: + err = -ENODEV; + } + return err; +} + +/* The CX8802 MPEG API will call this when we need to release the hardware */ +static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + + switch (core->board) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* Exit leaving the cx23416 on the bus */ + break; + default: + err = -ENODEV; + } + return err; +} + static void blackbird_unregister_video(struct cx8802_dev *dev) { if (dev->mpeg_dev) { @@ -1073,28 +1141,23 @@ static int blackbird_register_video(struct cx8802_dev *dev) /* ----------------------------------------------------------- */ -static int __devinit blackbird_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +static int cx8802_blackbird_probe(struct cx8802_driver *drv) { - struct cx8802_dev *dev; - struct cx88_core *core; + struct cx88_core *core = drv->core; + struct cx8802_dev *dev = core->dvbdev; int err; - /* general setup */ - core = cx88_core_get(pci_dev); - if (NULL == core) - return -EINVAL; + dprintk( 1, "%s\n", __FUNCTION__); + dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + core->board, + core->name, + core->pci_bus, + core->pci_slot); err = -ENODEV; if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD)) goto fail_core; - err = -ENOMEM; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) - goto fail_core; - dev->pci = pci_dev; - dev->core = core; dev->width = 720; dev->height = 576; cx2341x_fill_defaults(&dev->params); @@ -1106,64 +1169,36 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev, dev->height = 576; } - err = cx8802_init_common(dev); - if (0 != err) - goto fail_free; - /* blackbird stuff */ printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n", core->name); host_setup(dev->core); - list_add_tail(&dev->devlist,&cx8802_devlist); blackbird_register_video(dev); /* initial device configuration: needed ? */ return 0; - fail_free: - kfree(dev); fail_core: - cx88_core_put(core,pci_dev); return err; } -static void __devexit blackbird_remove(struct pci_dev *pci_dev) +static int cx8802_blackbird_remove(struct cx8802_driver *drv) { - struct cx8802_dev *dev = pci_get_drvdata(pci_dev); - /* blackbird */ - blackbird_unregister_video(dev); - list_del(&dev->devlist); + blackbird_unregister_video(drv->core->dvbdev); - /* common */ - cx8802_fini_common(dev); - cx88_core_put(dev->core,dev->pci); - kfree(dev); + return 0; } -static struct pci_device_id cx8802_pci_tbl[] = { - { - .vendor = 0x14f1, - .device = 0x8802, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - },{ - /* --- end of list --- */ - } -}; -MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); - -static struct pci_driver blackbird_pci_driver = { - .name = "cx88-blackbird", - .id_table = cx8802_pci_tbl, - .probe = blackbird_probe, - .remove = __devexit_p(blackbird_remove), -#ifdef CONFIG_PM - .suspend = cx8802_suspend_common, - .resume = cx8802_resume_common, -#endif +static struct cx8802_driver cx8802_blackbird_driver = { + .type_id = CX88_MPEG_BLACKBIRD, + .hw_access = CX8802_DRVCTL_SHARED, + .probe = cx8802_blackbird_probe, + .remove = cx8802_blackbird_remove, + .advise_acquire = cx8802_blackbird_advise_acquire, + .advise_release = cx8802_blackbird_advise_release, }; static int blackbird_init(void) @@ -1176,17 +1211,22 @@ static int blackbird_init(void) printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif - return pci_register_driver(&blackbird_pci_driver); + cx88_ioctl_hook = mpeg_do_ioctl; + cx88_ioctl_translator = mpeg_translate_ioctl; + return cx8802_register_driver(&cx8802_blackbird_driver); } static void blackbird_fini(void) { - pci_unregister_driver(&blackbird_pci_driver); + cx8802_unregister_driver(&cx8802_blackbird_driver); } module_init(blackbird_init); module_exit(blackbird_fini); +EXPORT_SYMBOL(cx88_ioctl_hook); +EXPORT_SYMBOL(cx88_ioctl_translator); + /* ----------------------------------------------------------- */ /* * Local variables: diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index f764a57..1c5db20 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1303,7 +1303,7 @@ struct cx88_board cx88_boards[] = { .gpio0 = 0xe780, }}, /* fixme: Add radio support */ - .mpeg = CX88_MPEG_DVB, + .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 0ef13e7..8150c09 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -57,7 +57,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug,"enable debug messages [dvb]"); #define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->core->name , ## arg) + printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg) /* ------------------------------------------------------------------ */ @@ -315,20 +315,36 @@ static struct cx22702_config hauppauge_novat_config = { .demod_address = 0x43, .output_mode = CX22702_SERIAL_OUTPUT, }; - static struct cx22702_config hauppauge_hvr1100_config = { .demod_address = 0x63, .output_mode = CX22702_SERIAL_OUTPUT, }; - -static struct cx22702_config hauppauge_hvr1300_config = { +static struct cx22702_config hauppauge_hvr3000_config = { .demod_address = 0x63, .output_mode = CX22702_SERIAL_OUTPUT, }; -static struct cx22702_config hauppauge_hvr3000_config = { +static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, + int acquire) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_driver *drv = NULL; + int ret = 0; + + drv = cx8802_get_driver(dev, CX88_MPEG_DVB); + if (drv) { + if(acquire) + ret = drv->request_acquire(drv); + else + ret = drv->request_release(drv); + } + + return ret; +} + +static struct cx22702_config hauppauge_hvr1300_config = { .demod_address = 0x63, - .output_mode = CX22702_SERIAL_OUTPUT, + .output_mode = CX22702_SERIAL_OUTPUT, }; static int or51132_set_ts_param(struct dvb_frontend* fe, @@ -555,26 +571,6 @@ static int dvb_register(struct cx8802_dev *dev) &dvb_pll_fmd1216me); } break; - case CX88_BOARD_HAUPPAUGE_HVR1300: - dev->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr1300_config, - &dev->core->i2c_adap); - if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - &dvb_pll_fmd1216me); - } - break; - case CX88_BOARD_HAUPPAUGE_HVR3000: - dev->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr3000_config, - &dev->core->i2c_adap); - if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - &dvb_pll_fmd1216me); - } - break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: dev->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, @@ -782,6 +778,26 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; } break; + case CX88_BOARD_HAUPPAUGE_HVR1300: + dev->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr1300_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, + &dvb_pll_fmd1216me); + } + break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + dev->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr3000_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, + &dvb_pll_fmd1216me); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); @@ -796,6 +812,8 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min; dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max; } + /* Ensure all frontends negotiate bus access */ + dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; /* Put the analog decoder in standby to keep it quiet */ cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); @@ -806,37 +824,67 @@ static int dvb_register(struct cx8802_dev *dev) /* ----------------------------------------------------------- */ -static int __devinit dvb_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +/* CX8802 MPEG -> mini driver - We have been given the hardware */ +static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) { - struct cx8802_dev *dev; - struct cx88_core *core; + struct cx88_core *core = drv->core; + int err = 0; + dprintk( 1, "%s\n", __FUNCTION__); + + switch (core->board) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* We arrive here with either the cx23416 or the cx22702 + * on the bus. Take the bus from the cx23416 and enable the + * cx22702 demod + */ + cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset and enable */ + cx_clear(MO_GP0_IO, 0x00000004); + udelay(1000); + break; + default: + err = -ENODEV; + } + return err; +} + +/* CX8802 MPEG -> mini driver - We no longer have the hardware */ +static int cx8802_dvb_advise_release(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + dprintk( 1, "%s\n", __FUNCTION__); + + switch (core->board) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* Do Nothing, leave the cx22702 on the bus. */ + break; + default: + err = -ENODEV; + } + return err; +} + +static int cx8802_dvb_probe(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + struct cx8802_dev *dev = drv->core->dvbdev; int err; - /* general setup */ - core = cx88_core_get(pci_dev); - if (NULL == core) - return -EINVAL; + dprintk( 1, "%s\n", __FUNCTION__); + dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + core->board, + core->name, + core->pci_bus, + core->pci_slot); err = -ENODEV; if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB)) goto fail_core; - err = -ENOMEM; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) - goto fail_core; - dev->pci = pci_dev; - dev->core = core; - - err = cx8802_init_common(dev); - if (0 != err) - goto fail_free; - #ifdef HAVE_VP3054_I2C err = vp3054_i2c_probe(dev); if (0 != err) - goto fail_free; + goto fail_core; #endif /* dvb stuff */ @@ -848,28 +896,16 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev, sizeof(struct cx88_buffer), dev); err = dvb_register(dev); - if (0 != err) - goto fail_fini; - - /* Maintain a reference to cx88-video can query the 8802 device. */ - core->dvbdev = dev; - return 0; + if (err != 0) + printk("%s dvb_register failed err = %d\n", __FUNCTION__, err); - fail_fini: - cx8802_fini_common(dev); - fail_free: - kfree(dev); fail_core: - cx88_core_put(core,pci_dev); return err; } -static void __devexit dvb_remove(struct pci_dev *pci_dev) +static int cx8802_dvb_remove(struct cx8802_driver *drv) { - struct cx8802_dev *dev = pci_get_drvdata(pci_dev); - - /* Destroy any 8802 reference. */ - dev->core->dvbdev = NULL; + struct cx8802_dev *dev = drv->core->dvbdev; /* dvb */ videobuf_dvb_unregister(&dev->dvb); @@ -878,33 +914,16 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev) vp3054_i2c_remove(dev); #endif - /* common */ - cx8802_fini_common(dev); - cx88_core_put(dev->core,dev->pci); - kfree(dev); + return 0; } -static struct pci_device_id cx8802_pci_tbl[] = { - { - .vendor = 0x14f1, - .device = 0x8802, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - },{ - /* --- end of list --- */ - } -}; -MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); - -static struct pci_driver dvb_pci_driver = { - .name = "cx88-dvb", - .id_table = cx8802_pci_tbl, - .probe = dvb_probe, - .remove = __devexit_p(dvb_remove), -#ifdef CONFIG_PM - .suspend = cx8802_suspend_common, - .resume = cx8802_resume_common, -#endif +static struct cx8802_driver cx8802_dvb_driver = { + .type_id = CX88_MPEG_DVB, + .hw_access = CX8802_DRVCTL_SHARED, + .probe = cx8802_dvb_probe, + .remove = cx8802_dvb_remove, + .advise_acquire = cx8802_dvb_advise_acquire, + .advise_release = cx8802_dvb_advise_release, }; static int dvb_init(void) @@ -917,12 +936,12 @@ static int dvb_init(void) printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif - return pci_register_driver(&dvb_pci_driver); + return cx8802_register_driver(&cx8802_dvb_driver); } static void dvb_fini(void) { - pci_unregister_driver(&dvb_pci_driver); + cx8802_unregister_driver(&cx8802_dvb_driver); } module_init(dvb_init); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 6b23a4e..6f15571 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -44,8 +44,12 @@ module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); #define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2: " fmt, dev->core->name , ## arg) + printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg) +#define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) + +static LIST_HEAD(cx8802_devlist); /* ------------------------------------------------------------------ */ static int cx8802_start_dma(struct cx8802_dev *dev, @@ -65,17 +69,13 @@ static int cx8802_start_dma(struct cx8802_dev *dev, /* FIXME: this needs a review. * also: move to cx88-blackbird + cx88-dvb source files? */ - if (cx88_boards[core->board].mpeg == (CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) ) { - /* Report a warning until the mini driver patch is applied, - * else the following conditions will set the dma registers incorrectly. - * This will be removed in the next major patch and changes to the conditions - * will be made. - */ - printk(KERN_INFO "%s() board->(CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) is invalid\n", __FUNCTION__); - return -EINVAL; - } - if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) { + dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id); + + if ( (core->active_type_id == CX88_MPEG_DVB) && + (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) { + + dprintk( 1, "cx8802_start_dma doing .dvb\n"); /* negedge driven & software reset */ cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); @@ -93,15 +93,17 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ udelay(100); break; + case CX88_BOARD_HAUPPAUGE_HVR1300: + break; default: cx_write(TS_SOP_STAT, 0x00); break; } cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); - } - - if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && + (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) { + dprintk( 1, "cx8802_start_dma doing .blackbird\n"); cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ @@ -112,6 +114,10 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ udelay(100); + } else { + printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__, + cx88_boards[core->board].mpeg ); + return -EINVAL; } /* reset counter */ @@ -542,8 +548,311 @@ int cx8802_resume_common(struct pci_dev *pci_dev) return 0; } +struct cx8802_dev * cx8802_get_device(struct inode *inode) +{ + int minor = iminor(inode); + struct cx8802_dev *h = NULL; + struct list_head *list; + + list_for_each(list,&cx8802_devlist) { + h = list_entry(list, struct cx8802_dev, devlist); + if (h->mpeg_dev->minor == minor) + return h; + } + + return NULL; +} + +struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) +{ + struct cx8802_dev *h = NULL; + struct cx8802_driver *d = NULL; + struct list_head *list; + struct list_head *list2; + + list_for_each(list,&cx8802_devlist) { + h = list_entry(list, struct cx8802_dev, devlist); + + list_for_each(list2, &h->drvlist.devlist) { + d = list_entry(list2, struct cx8802_driver, devlist); + + /* only unregister the correct driver type */ + if (d->type_id == btype) { + return d; + } + } + } + + return NULL; +} + +/* Driver asked for hardware access. */ +int cx8802_request_acquire(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + + /* Fail a request for hardware if the device is busy. */ + if (core->active_type_id != CX88_BOARD_NONE) + return -EBUSY; + + if (drv->advise_acquire) + { + core->active_type_id = drv->type_id; + drv->advise_acquire(drv); + + mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO)); + } + + return 0; +} + +/* Driver asked to release hardware. */ +int cx8802_request_release(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + + if (drv->advise_release) + { + drv->advise_release(drv); + core->active_type_id = CX88_BOARD_NONE; + mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO)); + } + + return 0; +} + +static int cx8802_check_driver(struct cx8802_driver *drv) +{ + if (drv == NULL) + return -ENODEV; + + if ((drv->type_id != CX88_MPEG_DVB) && + (drv->type_id != CX88_MPEG_BLACKBIRD)) + return -EINVAL; + + if ((drv->hw_access != CX8802_DRVCTL_SHARED) && + (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE)) + return -EINVAL; + + if ((drv->probe == NULL) || + (drv->remove == NULL) || + (drv->advise_acquire == NULL) || + (drv->advise_release == NULL)) + return -EINVAL; + + return 0; +} + +int cx8802_register_driver(struct cx8802_driver *drv) +{ + struct cx8802_dev *h; + struct cx8802_driver *driver; + struct list_head *list; + int err = 0, i = 0; + + printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ , + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + + if ((err = cx8802_check_driver(drv)) != 0) { + printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ ); + return err; + } + + list_for_each(list,&cx8802_devlist) { + i++; + h = list_entry(list, struct cx8802_dev, devlist); + + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name,h->pci->subsystem_vendor, + h->pci->subsystem_device,cx88_boards[h->core->board].name, + h->core->board); + + /* Bring up a new struct for each driver instance */ + driver = kzalloc(sizeof(*drv),GFP_KERNEL); + if (driver == NULL) + return -ENOMEM; + + /* Snapshot of the driver registration data */ + drv->core = h->core; + drv->suspend = cx8802_suspend_common; + drv->resume = cx8802_resume_common; + drv->request_acquire = cx8802_request_acquire; + drv->request_release = cx8802_request_release; + memcpy(driver, drv, sizeof(*driver)); + + err = drv->probe(driver); + if (err == 0) { + mutex_lock(&drv->core->lock); + list_add_tail(&driver->devlist,&h->drvlist.devlist); + mutex_unlock(&drv->core->lock); + } else { + printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err); + } + + } + if (i == 0) + err = -ENODEV; + + return err; +} + +int cx8802_unregister_driver(struct cx8802_driver *drv) +{ + struct cx8802_dev *h; + struct cx8802_driver *d; + struct list_head *list; + struct list_head *list2, *q; + int err = 0, i = 0; + + printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ , + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird"); + + list_for_each(list,&cx8802_devlist) { + i++; + h = list_entry(list, struct cx8802_dev, devlist); + + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name,h->pci->subsystem_vendor, + h->pci->subsystem_device,cx88_boards[h->core->board].name, + h->core->board); + + list_for_each_safe(list2, q, &h->drvlist.devlist) { + d = list_entry(list2, struct cx8802_driver, devlist); + + /* only unregister the correct driver type */ + if (d->type_id != drv->type_id) + continue; + + err = d->remove(d); + if (err == 0) { + mutex_lock(&drv->core->lock); + list_del(list2); + mutex_unlock(&drv->core->lock); + } else + printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err); + + } + + } + + return err; +} + /* ----------------------------------------------------------- */ +static int __devinit cx8802_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cx8802_dev *dev; + struct cx88_core *core; + int err; + + /* general setup */ + core = cx88_core_get(pci_dev); + if (NULL == core) + return -EINVAL; + + printk("%s/2: cx2388x 8802 Driver Manager\n", core->name); + + err = -ENODEV; + if (!cx88_boards[core->board].mpeg) + goto fail_core; + + err = -ENOMEM; + dev = kzalloc(sizeof(*dev),GFP_KERNEL); + if (NULL == dev) + goto fail_core; + dev->pci = pci_dev; + dev->core = core; + + err = cx8802_init_common(dev); + if (err != 0) + goto fail_free; + + INIT_LIST_HEAD(&dev->drvlist.devlist); + list_add_tail(&dev->devlist,&cx8802_devlist); + /* Maintain a reference so cx88-video can query the 8802 device. */ + core->dvbdev = dev; + return 0; + + fail_free: + kfree(dev); + fail_core: + cx88_core_put(core,pci_dev); + return err; +} + +static void __devexit cx8802_remove(struct pci_dev *pci_dev) +{ + struct cx8802_dev *dev; + struct cx8802_driver *h; + struct list_head *list; + + dev = pci_get_drvdata(pci_dev); + + dprintk( 1, "%s\n", __FUNCTION__); + + list_for_each(list,&dev->drvlist.devlist) { + h = list_entry(list, struct cx8802_driver, devlist); + dprintk( 1, " ->driver\n"); + if (h->remove == NULL) { + printk(KERN_ERR "%s .. skipping driver, no probe function\n", __FUNCTION__); + continue; + } + printk(KERN_INFO "%s .. Removing driver type %d\n", __FUNCTION__, h->type_id); + cx8802_unregister_driver(h); + list_del(&dev->drvlist.devlist); + } + + /* Destroy any 8802 reference. */ + dev->core->dvbdev = NULL; + + /* common */ + cx8802_fini_common(dev); + cx88_core_put(dev->core,dev->pci); + kfree(dev); +} + +static struct pci_device_id cx8802_pci_tbl[] = { + { + .vendor = 0x14f1, + .device = 0x8802, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* --- end of list --- */ + } +}; +MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); + +static struct pci_driver cx8802_pci_driver = { + .name = "cx88-mpeg driver manager", + .id_table = cx8802_pci_tbl, + .probe = cx8802_probe, + .remove = __devexit_p(cx8802_remove), +}; + +static int cx8802_init(void) +{ + printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx8802_pci_driver); +} + +static void cx8802_fini(void) +{ + pci_unregister_driver(&cx8802_pci_driver); +} + +module_init(cx8802_init); +module_exit(cx8802_fini); EXPORT_SYMBOL(cx8802_buf_prepare); EXPORT_SYMBOL(cx8802_buf_queue); EXPORT_SYMBOL(cx8802_cancel_buffers); @@ -551,9 +860,10 @@ EXPORT_SYMBOL(cx8802_cancel_buffers); EXPORT_SYMBOL(cx8802_init_common); EXPORT_SYMBOL(cx8802_fini_common); -EXPORT_SYMBOL(cx8802_suspend_common); -EXPORT_SYMBOL(cx8802_resume_common); - +EXPORT_SYMBOL(cx8802_register_driver); +EXPORT_SYMBOL(cx8802_unregister_driver); +EXPORT_SYMBOL(cx8802_get_device); +EXPORT_SYMBOL(cx8802_get_driver); /* ----------------------------------------------------------- */ /* * Local variables: diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 3bc91aa..5980e47 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -74,6 +74,11 @@ enum cx88_board_type { CX88_MPEG_BLACKBIRD }; +enum cx8802_board_access { + CX8802_DRVCTL_SHARED = 1, + CX8802_DRVCTL_EXCLUSIVE = 2, +}; + /* ----------------------------------------------------------- */ /* tv norms */ @@ -330,6 +335,7 @@ struct cx88_core { /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ struct cx8802_dev *dvbdev; + enum cx88_board_type active_type_id; }; struct cx8800_dev; @@ -405,6 +411,31 @@ struct cx8802_suspend_state { int disabled; }; +struct cx8802_driver { + struct cx88_core *core; + struct list_head devlist; + + /* Type of driver and access required */ + enum cx88_board_type type_id; + enum cx8802_board_access hw_access; + + /* MPEG 8802 internal only */ + int (*suspend)(struct pci_dev *pci_dev, pm_message_t state); + int (*resume)(struct pci_dev *pci_dev); + + /* MPEG 8802 -> mini driver - Driver probe and configuration */ + int (*probe)(struct cx8802_driver *drv); + int (*remove)(struct cx8802_driver *drv); + + /* MPEG 8802 -> mini driver - Access for hardware control */ + int (*advise_acquire)(struct cx8802_driver *drv); + int (*advise_release)(struct cx8802_driver *drv); + + /* MPEG 8802 <- mini driver - Access for hardware control */ + int (*request_acquire)(struct cx8802_driver *drv); + int (*request_release)(struct cx8802_driver *drv); +}; + struct cx8802_dev { struct cx88_core *core; spinlock_t slock; @@ -439,6 +470,9 @@ struct cx8802_dev { /* mpeg params */ struct cx2341x_mpeg_params params; + + /* List of attached drivers */ + struct cx8802_driver drvlist; }; /* ----------------------------------------------------------- */ @@ -571,6 +605,11 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); int cx88_audio_thread(void *data); +int cx8802_register_driver(struct cx8802_driver *drv); +int cx8802_unregister_driver(struct cx8802_driver *drv); +struct cx8802_dev * cx8802_get_device(struct inode *inode); +struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); + /* ----------------------------------------------------------- */ /* cx88-input.c */ @@ -600,6 +639,13 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, extern const u32 cx88_user_ctrls[]; extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl); +/* ----------------------------------------------------------- */ +/* cx88-blackbird.c */ +/* used by cx88-ivtv ioctl emulation layer */ +extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd); + /* * Local variables: * c-basic-offset: 8 |