diff options
Diffstat (limited to 'linux/drivers/media/common')
-rw-r--r-- | linux/drivers/media/common/Makefile | 8 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146.h | 48 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146_core.c | 456 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146_fops.c | 426 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146_vbi.c | 8 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146_video.c | 18 |
6 files changed, 497 insertions, 467 deletions
diff --git a/linux/drivers/media/common/Makefile b/linux/drivers/media/common/Makefile index 5ececd228..526bf968c 100644 --- a/linux/drivers/media/common/Makefile +++ b/linux/drivers/media/common/Makefile @@ -1,8 +1,8 @@ -export-objs := video-buf.o +export-objs := saa7146_core.o saa7146_fops.o saa7146_video.o saa7146_vbi.o video-buf.o -saa7146-objs := saa7146_core.o saa7146_hlp.o saa7146_i2c.o \ - saa7146_vbi.o saa7146_video.o +saa7146-objs := saa7146_i2c.o saa7146_core.o +saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o obj-$(CONFIG_VIDEO_VIDEOBUF) += video-buf.o -obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o +obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o saa7146_vv.o diff --git a/linux/drivers/media/common/saa7146.h b/linux/drivers/media/common/saa7146.h index 4fd023dd5..b35b14672 100644 --- a/linux/drivers/media/common/saa7146.h +++ b/linux/drivers/media/common/saa7146.h @@ -35,8 +35,6 @@ from flaws in video-buf.c => Gerd Knorr */ #endif #endif -#define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && 0 != dev->ext->vbi) - extern unsigned int saa7146_debug; //#define DEBUG_PROLOG printk("(0x%08x)(0x%08x) %s: %s(): ",(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,RPS_ADDR0))),(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,IER))),__stringify(KBUILD_MODNAME),__FUNCTION__) @@ -77,9 +75,7 @@ struct saa7146_sub_info { #define SAA7146_AFTER 0x4 /* flags */ -#define SAA7146_EXT_PROVIDES_VIDEO 0x1 /* provides vbi device */ -#define SAA7146_EXT_PROVIDES_VBI 0x2 /* provides vbi device */ -#define SAA7146_EXT_SWAP_ODD_EVEN 0x4 /* needs odd/even fields swapped */ +#define SAA7146_EXT_SWAP_ODD_EVEN 0x1 /* needs odd/even fields swapped */ struct saa7146_extension { @@ -88,7 +84,7 @@ struct saa7146_extension int audios; u32 capabilities; - int flags; + int flags; struct list_head item; @@ -107,9 +103,7 @@ struct saa7146_extension struct saa7146_standard *stds; int num_stds; int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *); - - int (*vbi)(struct saa7146_dev*); // want vbi - + struct saa7146_extension_ioctls *ioctls; /* extension functions */ @@ -191,7 +185,7 @@ struct saa7146_dmaqueue { }; struct saa7146_overlay { - struct saa7146_fh *fh; + struct saa7146_fh *fh; struct v4l2_window win; struct v4l2_clip clips[16]; int nclips; @@ -201,7 +195,7 @@ struct saa7146_overlay { struct saa7146_fh { struct saa7146_dev *dev; /* if this is a vbi or capture open */ - enum v4l2_buf_type type; + enum v4l2_buf_type type; /* video overlay */ struct saa7146_overlay ov; @@ -218,11 +212,8 @@ struct saa7146_fh { struct saa7146_dev { - struct video_device video_dev; - struct video_device vbi_dev; - /* used for loadable modules */ - struct module *module; + struct module *module; struct list_head item; @@ -231,7 +222,7 @@ struct saa7146_dev struct semaphore lock; struct semaphore i2c_lock; - unsigned char* mem; /* pointer to mapped IO memory */ + unsigned char *mem; /* pointer to mapped IO memory */ int revision; /* chip revision; needed for bug-workarounds*/ /* pci-device & irq stuff*/ @@ -239,19 +230,23 @@ struct saa7146_dev struct pci_dev *pci; /* extension handling */ - struct saa7146_extension* ext; /* indicates if handled by extension */ - void* ext_priv; /* pointer for extension private use (most likely some private data) */ + struct saa7146_extension *ext; /* indicates if handled by extension */ + void *ext_priv; /* pointer for extension private use (most likely some private data) */ + int video_minor, vbi_minor; + + void (*video_irq_done)(struct saa7146_dev *dev, unsigned long status); + void (*vbi_irq_done)(struct saa7146_dev *dev, unsigned long status); /* i2c-stuff */ u32 i2c_bitrate; - u32* i2c_mem; /* pointer to i2c memory */ + u32 *i2c_mem; /* pointer to i2c memory */ wait_queue_head_t i2c_wq; int i2c_op; /* memories */ - u32* clipping; /* pointer to clipping memory */ - u32* rps0; - u32* rps1; + u32 *clipping; /* pointer to clipping memory */ + u32 *rps0; + u32 *rps1; /* vbi capture */ struct saa7146_dmaqueue vbi_q; @@ -276,6 +271,7 @@ struct saa7146_dev all opens? currently, we do the latter, like all other drivers do... */ struct saa7146_standard *standard; + int vflip; int hflip; int current_hps_source; @@ -293,6 +289,10 @@ struct saa7146_use_ops { int (*capture_end)(struct saa7146_fh *fh); }; +/* from saa7146_fops.c */ +int saa7146_register_device(struct video_device *vid, struct saa7146_dev* dev, char *name, int type); +int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev* dev); + /* from saa7146_i2c.c */ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg msgs[], int num, int retries); @@ -306,6 +306,9 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sy void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data); /* from saa7146_core.c */ +extern struct list_head saa7146_devices; +extern struct semaphore saa7146_devices_lock; + int saa7146_register_extension(struct saa7146_extension*); int saa7146_unregister_extension(struct saa7146_extension*); struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc); @@ -322,7 +325,6 @@ void saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *p /* from saa7146_video.c */ extern struct saa7146_use_ops saa7146_video_uops; -int video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg); /* from saa7146_vbi.c */ extern struct saa7146_use_ops saa7146_vbi_uops; 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"); diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c new file mode 100644 index 000000000..d8202c65f --- /dev/null +++ b/linux/drivers/media/common/saa7146_fops.c @@ -0,0 +1,426 @@ +#include "saa7146.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) + #define KBUILD_MODNAME saa7146 +#endif + +#define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vbi_minor != -1) + +/********************************************************************************/ +/* common dma 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 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); +} + +/********************************************************************************/ +/* 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(&saa7146_devices_lock)) + return -ERESTARTSYS; + + list_for_each(list,&saa7146_devices) { + h = list_entry(list, struct saa7146_dev, item); + DEB_D(("trying: %p @ major %d,%d\n",h,h->video_minor,h->vbi_minor)); + if (h->video_minor == minor) { + dev = h; + } + if (h->vbi_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; + + /* FIXME: what's this? */ + 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(&saa7146_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(&saa7146_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(&saa7146_devices_lock); + + return 0; +} + +int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg); +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, saa7146_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, +}; + +static struct video_device device_template = +{ + .hardware = VID_HARDWARE_SAA7146, + .fops = &video_fops, + .minor = -1, +}; + +int saa7146_register_device(struct video_device *vid, struct saa7146_dev* dev, char *name, int type) +{ + *vid = device_template; + strncpy(vid->name, name, 32); + vid->priv = dev; + + // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr"); + if (video_register_device(vid,type,-1) < 0) { + ERR(("cannot register vbi v4l2 device. skipping.\n")); + return -1; + } + + if( VFL_TYPE_GRABBER == type ) { + dev->video_minor = vid->minor; + INFO(("%s: registered device video%d [v4l2]\n", dev->name,vid->minor & 0x1f)); + } else { + dev->vbi_minor = vid->minor; + INFO(("%s: registered device vbi%d [v4l2]\n", dev->name,vid->minor & 0x1f)); + } + return 0; +} + +int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev* dev) +{ + if( VFL_TYPE_GRABBER == vid->type ) { + dev->video_minor = -1; + dev->video_irq_done = saa7146_video_uops.irq_done; + } else { + dev->vbi_minor = -1; + dev->vbi_irq_done = saa7146_vbi_uops.irq_done; + } + video_unregister_device(vid); + return 0; +} + +static +int __init saa7146_vv_init_module(void) +{ + return 0; +} + + +static +void __exit saa7146_vv_cleanup_module(void) +{ +} + +module_init(saa7146_vv_init_module); +module_exit(saa7146_vv_cleanup_module); + +EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync); +EXPORT_SYMBOL_GPL(saa7146_register_device); +EXPORT_SYMBOL_GPL(saa7146_unregister_device); + +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware"); +MODULE_LICENSE("GPL"); + + diff --git a/linux/drivers/media/common/saa7146_vbi.c b/linux/drivers/media/common/saa7146_vbi.c index be318cfee..1b880ff9c 100644 --- a/linux/drivers/media/common/saa7146_vbi.c +++ b/linux/drivers/media/common/saa7146_vbi.c @@ -15,17 +15,13 @@ int vbi_workaround(struct saa7146_dev *dev) DECLARE_WAITQUEUE(wait, current); - DEB_VBI(("dev:%p",dev)); + DEB_VBI(("dev:%p\n",dev)); /* once again, a bug in the saa7146: the brs acquisition is buggy and especially the BXO-counter does not work as specified. there is this workaround, but please don't let me explain it. ;-) */ - if(0 != dev->ext->vbi) { - dev->ext->vbi(dev); - } - cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr); if (NULL == cpu) return -ENOMEM; @@ -451,3 +447,5 @@ struct saa7146_use_ops saa7146_vbi_uops = { .irq_done = vbi_irq_done, .read = vbi_read, }; + +EXPORT_SYMBOL_GPL(saa7146_vbi_uops); diff --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c index 8c0f19239..2038e4748 100644 --- a/linux/drivers/media/common/saa7146_video.c +++ b/linux/drivers/media/common/saa7146_video.c @@ -64,10 +64,6 @@ int g_fmt(struct saa7146_fh *fh, struct v4l2_format *f) return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: { - if( 0 == BOARD_CAN_DO_VBI(dev)) { - DEB_D(("this device does not support vbi.\n")); - return -ENODEV; - } f->fmt.vbi = fh->vbi_fmt; return 0; } @@ -681,8 +677,7 @@ int video_end(struct saa7146_fh *fh) * copying is done already, arg is a kernel fhinter. */ -int video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; @@ -747,9 +742,6 @@ int video_do_ioctl(struct inode *inode, struct file *file, V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if( BOARD_CAN_DO_VBI(dev) != 0) { - cap->capabilities |= V4L2_CAP_VBI_CAPTURE; - } cap->capabilities |= dev->ext->capabilities; return 0; } @@ -1044,12 +1036,11 @@ int video_do_ioctl(struct inode *inode, struct file *file, } default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, - video_do_ioctl); + saa7146_video_do_ioctl); } return 0; } - /*********************************************************************************/ /* buffer handling functions */ @@ -1209,6 +1200,8 @@ static void video_init(struct saa7146_dev *dev) { INIT_LIST_HEAD(&dev->video_q.queue); + + init_timer(&dev->video_q.timeout); dev->video_q.timeout.function = saa7146_buffer_timeout; dev->video_q.timeout.data = (unsigned long)(&dev->video_q); dev->video_q.dev = dev; @@ -1277,7 +1270,6 @@ void video_irq_done(struct saa7146_dev *dev, unsigned long st) spin_unlock(&dev->slock); } - static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *ppos) { @@ -1310,3 +1302,5 @@ struct saa7146_use_ops saa7146_video_uops = { .capture_begin = video_begin, .capture_end = video_end, }; + +EXPORT_SYMBOL_GPL(saa7146_video_uops); |