diff options
Diffstat (limited to 'linux/drivers/media/common/saa7146_core.c')
-rw-r--r-- | linux/drivers/media/common/saa7146_core.c | 456 |
1 files changed, 33 insertions, 423 deletions
diff --git a/linux/drivers/media/common/saa7146_core.c b/linux/drivers/media/common/saa7146_core.c index 46ce10842..1ebb7ed36 100644 --- a/linux/drivers/media/common/saa7146_core.c +++ b/linux/drivers/media/common/saa7146_core.c @@ -27,8 +27,9 @@ #endif /* global variables */ -static struct list_head devices; -static struct semaphore devices_lock; +struct list_head saa7146_devices; +struct semaphore saa7146_devices_lock; + static struct list_head extensions; static int initialized = 0; static int saa7146_num = 0; @@ -49,20 +50,7 @@ static void dump_registers(struct saa7146_dev* dev) } /********************************************************************************/ -/* common dma and page table functions */ - -void saa7146_dma_free(struct saa7146_dev *dev,struct saa7146_buf *buf) -{ - DEB_EE(("dev:%p, buf:%p\n",dev,buf)); - - if (in_interrupt()) - BUG(); - - videobuf_waiton(&buf->vb,0,0); - videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); - buf->vb.state = STATE_NEEDS_INIT; -} +/* common page table functions */ #define SAA7146_PGTABLE_SIZE 4096 @@ -128,220 +116,9 @@ void saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *p } /********************************************************************************/ -/* file operations */ - -static -int video_open(struct inode *inode, struct file *file) -{ - unsigned int minor = minor(inode->i_rdev); - struct saa7146_dev *h = NULL, *dev = NULL; - struct list_head *list; - struct saa7146_fh *fh = NULL; - int result = 0; - - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - DEB_EE(("inode:%p, file:%p, minor:%d\n",inode,file,minor)); - - if (down_interruptible(&devices_lock)) - return -ERESTARTSYS; - - list_for_each(list,&devices) { - h = list_entry(list, struct saa7146_dev, item); - DEB_D(("trying: %p @ major %d,%d\n",h,h->video_dev.minor,h->vbi_dev.minor)); - if (h->video_dev.minor == minor) { - dev = h; - } - if (h->vbi_dev.minor == minor) { - type = V4L2_BUF_TYPE_VBI_CAPTURE; - dev = h; - } - } - DEB_D(("using: %p\n",dev)); - - if (NULL == dev) { - DEB_S(("no such video device.\n")); - result = -ENODEV; - goto out; - } - - /* check if an extension is registered */ - if( NULL == dev->ext ) { - DEB_S(("no extension registered for this device.\n")); - result = -ENODEV; - goto out; - } - - /* allocate per open data */ - fh = kmalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) { - DEB_S(("cannot allocate memory for per open data.\n")); - result = -ENOMEM; - goto out; - } - memset(fh,0,sizeof(*fh)); - - /* fixme: increase some usage counts */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) - dev->ext->inc_use(dev); - MOD_INC_USE_COUNT; -#else - if( 0 == try_module_get(dev->ext->module)) { - result = -EINVAL; - goto out; - } -#endif - file->private_data = fh; - fh->dev = dev; - fh->type = type; - - dev->current_hps_source = SAA7146_HPS_SOURCE_PORT_A; - dev->current_hps_sync = SAA7146_HPS_SYNC_PORT_A; - - saa7146_video_uops.open(dev,fh); - if( 0 != BOARD_CAN_DO_VBI(dev) ) { - saa7146_vbi_uops.open(dev,fh); - } - - result = 0; -out: - if( fh != 0 && result != 0 ) { - kfree(fh); - } - up(&devices_lock); - return result; -} - -static int video_release(struct inode *inode, struct file *file) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - - DEB_EE(("inode:%p, file:%p\n",inode,file)); - - if (down_interruptible(&devices_lock)) - return -ERESTARTSYS; - - saa7146_video_uops.release(dev,fh,file); - if( 0 != BOARD_CAN_DO_VBI(dev) ) { - saa7146_vbi_uops.release(dev,fh,file); - } - - /* fixme: decrease some usage counts */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) - dev->ext->dec_use(dev); - MOD_DEC_USE_COUNT; -#else - module_put(dev->ext->module); -#endif - file->private_data = NULL; - kfree(fh); - - up(&devices_lock); - - return 0; -} - -static int video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ -/* - DEB_EE(("inode:%p, file:%p, cmd:%d, arg:%li\n",inode, file, cmd, arg)); -*/ - return video_usercopy(inode, file, cmd, arg, video_do_ioctl); -} - -static int video_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct videobuf_queue *q; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: { - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",file, vma)); - q = &fh->video_q; - break; - } - case V4L2_BUF_TYPE_VBI_CAPTURE: { - DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",file, vma)); - q = &fh->vbi_q; - break; - } - default: - BUG(); - return 0; - } - return videobuf_mmap_mapper(vma,q); -} - -static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct videobuf_buffer *buf = NULL; - struct videobuf_queue *q; - - DEB_EE(("file:%p, poll:%p\n",file, wait)); - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - if( 0 == fh->vbi_q.streaming ) - return videobuf_poll_stream(file, &fh->vbi_q, wait); - q = &fh->vbi_q; - } else { - q = &fh->video_q; - } - - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - - if (!buf) { - return POLLERR; - } - - poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || buf->state == STATE_ERROR) { - return POLLIN|POLLRDNORM; - } - - return 0; -} - -static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *ppos) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: { - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%d\n",file, data, count)); - return saa7146_video_uops.read(file,data,count,ppos); - } - case V4L2_BUF_TYPE_VBI_CAPTURE: { - DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%d\n",file, data, count)); - return saa7146_vbi_uops.read(file,data,count,ppos); - } - break; - default: - BUG(); - return 0; - } -} - -static struct file_operations video_fops = -{ - owner: THIS_MODULE, - open: video_open, - release: video_release, - read: video_read, - poll: video_poll, - mmap: video_mmap, - ioctl: video_ioctl, - llseek: no_llseek, -}; - -/********************************************************************************/ /* interrupt handler */ +/* FIXME: here are dependencies to the video and vbi code... */ static void interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) { struct saa7146_dev *dev = (struct saa7146_dev*)dev_id; @@ -369,7 +146,9 @@ static void interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) } if (0 != (isr & (MASK_27))) { DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); - saa7146_video_uops.irq_done(dev,isr); + if( 0 != dev->video_irq_done ) { + dev->video_irq_done(dev,isr); + } isr &= ~MASK_27; } if (0 != (isr & (MASK_28))) { @@ -382,7 +161,9 @@ static void interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) return; } DEB_INT(("irq: RPS1 (0x%08x).\n",isr)); - saa7146_vbi_uops.irq_done(dev,isr); + if( 0 != dev->vbi_irq_done ) { + dev->vbi_irq_done(dev,isr); + } } if (0 != (isr & (MASK_16|MASK_17))) { u32 status = saa7146_read(dev, I2C_STATUS); @@ -410,138 +191,9 @@ static void interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) } } -/********************************************************************************/ -/* common buffer functions */ - -int saa7146_buffer_queue(struct saa7146_dev *dev, - struct saa7146_dmaqueue *q, - struct saa7146_buf *buf) -{ -#if DEBUG_SPINLOCKS - BUG_ON(!spin_is_locked(&dev->slock)); -#endif - DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf)); - - if( NULL == q ) { - ERR(("internal error: fatal NULL pointer for q.\n")); - return 0; - } - - if (NULL == q->curr) { - q->curr = buf; - DEB_D(("immediately activating buffer %p\n", buf)); - buf->activate(dev,buf,NULL); - } else { - list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; - DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); - } - return 0; -} - -void saa7146_buffer_finish(struct saa7146_dev *dev, - struct saa7146_dmaqueue *q, - int state) -{ -#if DEBUG_SPINLOCKS - BUG_ON(!spin_is_locked(&dev->slock)); -#endif - if( NULL == q->curr ) { - ERR(("internal error: fatal NULL pointer for q->curr.\n")); - return; - } - - DEB_EE(("dev:%p, dmaq:%p, state:%d\n", dev, q, state)); - - /* finish current buffer */ - q->curr->vb.state = state; - do_gettimeofday(&q->curr->vb.ts); - wake_up(&q->curr->vb.done); - - q->curr = NULL; -} - -void saa7146_buffer_next(struct saa7146_dev *dev, - struct saa7146_dmaqueue *q, int vbi) -{ - struct saa7146_buf *buf,*next = NULL; - - if( NULL == q ) { - ERR(("internal error: fatal NULL pointer for q.\n")); - return; - } - - DEB_EE(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi)); - -#if DEBUG_SPINLOCKS - BUG_ON(!spin_is_locked(&dev->slock)); -#endif - if (!list_empty(&q->queue)) { - /* activate next one from queue */ - buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue); - list_del(&buf->vb.queue); - if (!list_empty(&q->queue)) - next = list_entry(q->queue.next,struct saa7146_buf, vb.queue); - q->curr = buf; - DEB_D(("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev,q->queue.next)); - buf->activate(dev,buf,next); - } else { - DEB_D(("no next buffer. stopping.\n")); - if( 0 != vbi ) { - /* turn off video-dma3 */ - saa7146_write(dev,MC1, MASK_20); - } else { - /* nothing to do -- just prevent next video-dma1 transfer - by lowering the protection address */ - - // fixme: fix this for vflip != 0 - - saa7146_write(dev, PROT_ADDR1, 0); - /* write the address of the rps-program */ - saa7146_write(dev, RPS_ADDR0, virt_to_bus(&dev->rps0[ 0])); - /* turn on rps */ - saa7146_write(dev, MC1, (MASK_12 | MASK_28)); - } - del_timer(&q->timeout); - } -} - -void saa7146_buffer_timeout(unsigned long data) -{ - struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data; - struct saa7146_dev *dev = q->dev; - unsigned long flags; - - DEB_EE(("dev:%p, dmaq:%p\n", dev, q)); - - spin_lock_irqsave(&dev->slock,flags); - if (q->curr) { - DEB_D(("timeout on %p\n", q->curr)); - saa7146_buffer_finish(dev,q,STATE_ERROR); - } - - /* we don't restart the transfer here like other drivers do. when - a streaming capture is disabled, the timeout function will be - called for the current buffer. if we activate the next buffer now, - we mess up our capture logic. if a timeout occurs on another buffer, - then something is seriously broken before, so no need to buffer the - next capture IMHO... */ -/* - saa7146_buffer_next(dev,q); -*/ - spin_unlock_irqrestore(&dev->slock,flags); -} - /*********************************************************************************/ /* extension handling functions */ -static struct video_device device_template = -{ - .hardware = VID_HARDWARE_SAA7146, - .fops = &video_fops, - .minor = -1, -}; - void try_attach_extension_and_device(struct saa7146_dev *dev, struct saa7146_extension *ext) { int i = 0; @@ -554,9 +206,6 @@ void try_attach_extension_and_device(struct saa7146_dev *dev, struct saa7146_ext return; } - dev->vbi_dev.minor = -1; - dev->video_dev.minor = -1; - DEB_S(("Trying device %p...\n",dev)); /* first check the subvendor and subdevice ids */ @@ -593,36 +242,6 @@ void try_attach_extension_and_device(struct saa7146_dev *dev, struct saa7146_ext dev->ext = NULL; return; } - - /* v4l2 initialization stuff */ - dev->video_dev = device_template; - strncpy(dev->video_dev.name, ext->name, 32); - dev->video_dev.priv = dev; - - // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr"); - if (video_register_device(&dev->video_dev,VFL_TYPE_GRABBER,-1) < 0) { - ERR(("cannot register capture v4l2 device. skipping.\n")); - /* in this case the extension has probably - already "done something", but the v4l2-device - could not be registered. this is not as bad as - it looks - you cannot access the device. - we simply call the 'release' function. */ - ext->detach(dev); - dev->ext = NULL; - return; - } - INFO(("%s: registered device video%d [v4l2]\n", dev->name,dev->video_dev.minor & 0x1f)); - - /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ - if( 0 != BOARD_CAN_DO_VBI(dev)) { - dev->vbi_dev = device_template; - strncpy(dev->vbi_dev.name, ext->name, 32); - dev->vbi_dev.priv = dev; - if (video_register_device(&dev->vbi_dev,VFL_TYPE_VBI,-1) < 0) { - ERR(("cannot register vbi v4l2 device. skipping.\n")); - } - INFO(("%s: registered device vbi%d [v4l2]\n", dev->name,dev->vbi_dev.minor & 0x1f)); - } } static int try_match_device_to_extension(struct saa7146_dev *dev) @@ -631,7 +250,7 @@ static int try_match_device_to_extension(struct saa7146_dev *dev) DEB_EE(("dev:%p\n",dev)); - if (down_interruptible(&devices_lock)) + if (down_interruptible(&saa7146_devices_lock)) return -ERESTARTSYS; list_for_each(list,&extensions) { @@ -639,7 +258,7 @@ static int try_match_device_to_extension(struct saa7146_dev *dev) try_attach_extension_and_device(dev,ext); } - up(&devices_lock); + up(&saa7146_devices_lock); return 0; } @@ -654,15 +273,15 @@ static int try_match_extension_to_device(struct saa7146_extension *ext) return 0; } - if (down_interruptible(&devices_lock)) + if (down_interruptible(&saa7146_devices_lock)) return -ERESTARTSYS; - list_for_each(list,&devices) { + list_for_each(list,&saa7146_devices) { dev = list_entry(list, struct saa7146_dev, item); try_attach_extension_and_device(dev,ext); } - up(&devices_lock); + up(&saa7146_devices_lock); return 0; } @@ -673,8 +292,8 @@ int saa7146_register_extension(struct saa7146_extension* ext) DEB_EE(("ext:%p\n",ext)); if( 0 == initialized ) { - INIT_LIST_HEAD(&devices); - init_MUTEX(&devices_lock); + INIT_LIST_HEAD(&saa7146_devices); + init_MUTEX(&saa7146_devices_lock); INIT_LIST_HEAD(&extensions); initialized = 1; } @@ -692,9 +311,9 @@ int saa7146_unregister_extension(struct saa7146_extension* ext) DEB_EE(("ext:%p\n",ext)); - down(&devices_lock); + down(&saa7146_devices_lock); - list_for_each(list,&devices) { + list_for_each(list,&saa7146_devices) { dev = list_entry(list, struct saa7146_dev, item); /* check if handled by this extension */ @@ -706,22 +325,13 @@ int saa7146_unregister_extension(struct saa7146_extension* ext) DEB_D(("ext->detach() failed. ignoring.\n")); } - video_unregister_device(&dev->video_dev); - if( 0 != BOARD_CAN_DO_VBI(dev)) { - video_unregister_device(&dev->vbi_dev); - } - dev->ext = NULL; - - /* make sure to erase the minor number... */ - dev->video_dev = device_template; - - dump_registers(dev); +// dump_registers(dev); } list_del(&ext->item); - up(&devices_lock); + up(&saa7146_devices_lock); return 0; } @@ -827,9 +437,6 @@ static int config_a_device(struct pci_dev *pci) goto kmalloc_error_4; memset(dev->i2c_mem, 0x00, SAA7146_I2C_MEM); - /* enable i2c-port pins, video-port-pins */ - saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); - /* the rest + print status message */ /* create a nice device name */ @@ -846,15 +453,15 @@ static int config_a_device(struct pci_dev *pci) init_MUTEX(&dev->i2c_lock); INIT_LIST_HEAD(&dev->item); - list_add_tail(&dev->item,&devices); + list_add_tail(&dev->item,&saa7146_devices); saa7146_num++; - saa7146_video_uops.init(dev); - saa7146_vbi_uops.init(dev); - dev->module = THIS_MODULE; init_waitqueue_head(&dev->i2c_wq); + dev->video_minor = -1; + dev->vbi_minor = -1; + return try_match_device_to_extension(dev); kmalloc_error_4: @@ -950,8 +557,8 @@ int __init saa7146_init_module(void) DEB_EE((".\n")); if( 0 == initialized ) { - INIT_LIST_HEAD(&devices); - init_MUTEX(&devices_lock); + INIT_LIST_HEAD(&saa7146_devices); + init_MUTEX(&saa7146_devices_lock); INIT_LIST_HEAD(&extensions); initialized = 1; } @@ -975,15 +582,18 @@ EXPORT_SYMBOL_GPL(saa7146_register_extension); EXPORT_SYMBOL_GPL(saa7146_unregister_extension); /* misc functions used by extension modules */ -EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync); EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc); EXPORT_SYMBOL_GPL(saa7146_pgtable_free); EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single); + EXPORT_SYMBOL_GPL(saa7146_i2c_transfer); EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); EXPORT_SYMBOL_GPL(saa7146_debug); +EXPORT_SYMBOL_GPL(saa7146_devices); +EXPORT_SYMBOL_GPL(saa7146_devices_lock); + MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); -MODULE_DESCRIPTION("video4linux driver for saa7146-based video hardware"); +MODULE_DESCRIPTION("core driver for saa7146-based hardware"); MODULE_LICENSE("GPL"); |