diff options
108 files changed, 5040 insertions, 899 deletions
@@ -1,52 +1,53 @@ -Mauro Carvalho Chehab 2006 Jan 30 +Mauro Carvalho Chehab 2006 Mar 8 -This file describes the general procedures used by v4l-dvb maintainers. -Some of these also applies to patch submitters. +This file describes the general procedures used by v4l-dvb developers +who are responsible for maintaining V4L/DVB drivers. Some of these +also applies to patch submitters. -We've moved from cvs to a modern SCM system that fits better into +Current V4L/DVB tree uses a modern SCM system that fits better into kernel development model, called Mercurial (aka hg). -At http://selenic.com/mercurial you'll find quick-start info, a -tutorial and FAQs. +There are some tutorials, FAQs and other valuable informations at +http://selenic.com/mercurial Mercurial is a distributed SCM, which means every developer gets his own full copy of the repository (including the complete revision history), and can work and commit locally without network connection. The resulting changesets can then be exchanged between repositories and -finally published to the master repository in linuxtv.org. +finally published to the master repository in linuxtv.org. A list of +current available repositories is available at: http://linuxtv.org/hg + +The master repository with stable patches is available at: +http://linuxtv/org/hg/v4l-dvb Mercurial is organized with a master tag, called tip. This tag contains the master repository that will be used by normal users and to generate patches to kernel. -The v4l-dvb mercurial repository is meant for development. It means -that it might be broken from time to time, although all efforts should -be done to avoid this. There are more "stable" snapshots at -http://www.linuxtv.org/downloads/snapshot page. - -This file postulates some simple rules for maintaing hg tree, as stated +This file postulates some simple rules for maintaing hg trees, as stated below: 1) It is strongly recommended that each developer be active at IRC channels (irc://irc.freenode.net) #v4l (for analog) and/or #linuxtv (for digital). It helps to have more discussions at major changes; -2) Minor changes, like simple card additions (for example a new card - row at a card struct) can be applied directly by each developer; +2) Each developer may have one or more development trees, for his daily + work. It is recommended to have a tree called 'v4l-dvb' for each + developer with their stable patches. -3) Medium changes that needs modification on card coding or creating a - new card type should be discussed first at the Mailing Lists - video4linux-list@redhat.com (analog/common parts) and/or - linux-dvb@linuxtv.org to allow other contributors to discuss about - the way it will be included. +3) After the patches are ready, developer should send an email to + v4l-dvb-maintainer list asking the maintainer to pull it from developer + repository, pushing it at master. The maintainer will analyse the patch + and publish at master hg if everything looks ok. -4) Major changes that implies changing some core structs should be - widely discussed on IRC, posted to the list, created a snapshot THEN - committed to the tip branch. It is strongly recommended to use a branch - or v4l_experimental area for such changes. +4) Medium or major changes that needs modification on card coding, creating a + new card type or requiring changes at core structs should be discussed first + at the Mailing Lists video4linux-list@redhat.com (analog/common parts) + and/or linux-dvb@linuxtv.org and at IRC to allow other contributors to + discuss about the way it will be included. -5) Every CVS maintainer should follow the "rules of thumb" of kernel - development stated at Linux source code, especially: +5) Every developer should follow the "rules of thumb" of kernel development + stated at Linux source code, especially: Documentation/SubmittingPatches Documentation/SubmittingDrivers @@ -66,7 +67,7 @@ below: hg add <files> hg remove <files> hg rename <source> <dest> - hg addremove + hg addremove [<files>] *Warning* hg addremove will add/removes all files, including object files. Be careful! You can remove wrongly added files with hg remove. @@ -79,14 +80,19 @@ below: This command will preserve the changes at the files. So, a new hg commit will redo the desired commit. -9) To push the change to the *MASTER* repository you need to run: +9) To push the change to the repository you need to run: - make push + hg push <url> 10) To update from the master repository, it is needed to do: make pull + After pulling from master, if there are some changes at local repository, + hg will require to merge it. This is done by + hg update -m + make commit + 11) For hg to work properly, these vars should be defined (replacing the names at the left): @@ -185,7 +191,16 @@ below: since the macro preprocessing script used to prepare kernel upstream patches (v4l/scripts/gentree.pl) is not able to handle it. -Cheers, +18) To import contributed stuff, a script is provided at tree and allows easy + import of a mbox-based patch emails. This is done with: + ./mailimport <mbox file> + For it to work properly, git tools need to be installed at local machine, + since git have a gitimport script that is used by mailimport. + Also, hg have a feature, called mqueue, that allows having several patches + that can be applied/unapplied for testing. mailimport trusts on it to work, + so, this extension should be enabled for mailimport script to work. + +Good Work! Mauro Mauro Carvalho Chehab <mchehab .at. linuxtv .dot. org> diff --git a/linux/Documentation/video4linux/CARDLIST.saa7134 b/linux/Documentation/video4linux/CARDLIST.saa7134 index 17ea5a031..8c7195455 100644 --- a/linux/Documentation/video4linux/CARDLIST.saa7134 +++ b/linux/Documentation/video4linux/CARDLIST.saa7134 @@ -86,6 +86,9 @@ 85 -> AverTV DVB-T 777 [1461:2c05] 86 -> LifeView FlyDVB-T [5168:0301] 87 -> ADS Instant TV Duo Cardbus PTV331 [0331:1421] - 88 -> Tevion DVB-T 220RF [17de:7201] + 88 -> Tevion/KWorld DVB-T 220RF [17de:7201] 89 -> ELSA EX-VISION 700TV [1048:226c] 90 -> Kworld ATSC110 [17de:7350] + 91 -> AVerMedia A169 B [1461:7360] + 92 -> AVerMedia A169 B1 [1461:6360] + 93 -> Medion 7134 Bridge #2 [16be:0005] diff --git a/linux/Documentation/video4linux/CARDLIST.tuner b/linux/Documentation/video4linux/CARDLIST.tuner index 603f16537..1bcdac67d 100644 --- a/linux/Documentation/video4linux/CARDLIST.tuner +++ b/linux/Documentation/video4linux/CARDLIST.tuner @@ -64,10 +64,10 @@ tuner=62 - Philips TEA5767HN FM Radio tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner tuner=64 - LG TDVS-H062F/TUA6034 tuner=65 - Ymec TVF66T5-B/DFF -tuner=66 - LG NTSC (TALN mini series) +tuner=66 - LG TALN series tuner=67 - Philips TD1316 Hybrid Tuner tuner=68 - Philips TUV1236D ATSC/NTSC dual in -tuner=69 - Tena TNF 5335 MF +tuner=69 - Tena TNF 5335 and similar models tuner=70 - Samsung TCPN 2121P30A tuner=71 - Xceive xc3028 tuner=72 - Thomson FE6600 diff --git a/linux/Documentation/video4linux/README.cpia2 b/linux/Documentation/video4linux/README.cpia2 index f3bd3439a..ce8213d28 100644 --- a/linux/Documentation/video4linux/README.cpia2 +++ b/linux/Documentation/video4linux/README.cpia2 @@ -70,7 +70,7 @@ line like this: If the driver is compiled into the kernel, at boot time specify them like this: - cpia2=num_buffers:3,buffer_size:65535 + cpia2.num_buffers=3 cpia2.buffer_size=65535 What buffer size should I use? ------------------------------ diff --git a/v4l_experimental/pvrusb2/README b/linux/Documentation/video4linux/README.pvrusb2 index 073491307..c73a32c34 100644 --- a/v4l_experimental/pvrusb2/README +++ b/linux/Documentation/video4linux/README.pvrusb2 @@ -1,5 +1,5 @@ -$Id: README,v 1.2 2006/01/01 08:26:03 mcisely Exp $ +$Id$ Mike Isely <isely@pobox.com> pvrusb2 driver diff --git a/linux/drivers/media/common/saa7146_core.c b/linux/drivers/media/common/saa7146_core.c index 71a5f1329..4233c2c2b 100644 --- a/linux/drivers/media/common/saa7146_core.c +++ b/linux/drivers/media/common/saa7146_core.c @@ -116,8 +116,7 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) pg = vmalloc_to_page(virt); if (NULL == pg) goto err; - if (PageHighMem(pg)) - BUG(); + BUG_ON(PageHighMem(pg)); sglist[i].page = pg; sglist[i].length = PAGE_SIZE; } diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c index 480a34a26..fd9163d4b 100644 --- a/linux/drivers/media/common/saa7146_fops.c +++ b/linux/drivers/media/common/saa7146_fops.c @@ -38,8 +38,7 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - if ((fh->resources & bits) != bits) - BUG(); + BUG_ON((fh->resources & bits) != bits); mutex_lock(&dev->lock); fh->resources &= ~bits; @@ -56,8 +55,7 @@ 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(); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma); diff --git a/linux/drivers/media/dvb/cinergyT2/cinergyT2.c b/linux/drivers/media/dvb/cinergyT2/cinergyT2.c index 10ed8b8c0..57ab7b0f3 100644 --- a/linux/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/linux/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -523,6 +523,9 @@ static int cinergyt2_open (struct inode *inode, struct file *file) static void cinergyt2_unregister(struct cinergyt2 *cinergyt2) { + dvb_net_release(&cinergyt2->dvbnet); + dvb_dmxdev_release(&cinergyt2->dmxdev); + dvb_dmx_release(&cinergyt2->demux); dvb_unregister_device(cinergyt2->fedev); dvb_unregister_adapter(&cinergyt2->adapter); @@ -955,6 +958,7 @@ static int cinergyt2_probe (struct usb_interface *intf, return 0; bailout: + dvb_net_release(&cinergyt2->dvbnet); dvb_dmxdev_release(&cinergyt2->dmxdev); dvb_dmx_release(&cinergyt2->demux); dvb_unregister_adapter(&cinergyt2->adapter); diff --git a/linux/drivers/media/dvb/dvb-core/demux.h b/linux/drivers/media/dvb/dvb-core/demux.h index 9f025825b..0c1d87c52 100644 --- a/linux/drivers/media/dvb/dvb-core/demux.h +++ b/linux/drivers/media/dvb/dvb-core/demux.h @@ -216,7 +216,7 @@ struct dmx_frontend { /*--------------------------------------------------------------------------*/ /* - * Flags OR'ed in the capabilites field of struct dmx_demux. + * Flags OR'ed in the capabilities field of struct dmx_demux. */ #define DMX_TS_FILTERING 1 diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.c b/linux/drivers/media/dvb/dvb-core/dmxdev.c index 4c52c8521..09e96e9dd 100644 --- a/linux/drivers/media/dvb/dvb-core/dmxdev.c +++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c @@ -1,9 +1,8 @@ /* * dmxdev.c - DVB demultiplexer device * - * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> - * & Marcus Metzler <marcus@convergence.de> - for convergence integrated media GmbH + * Copyright (C) 2000 Ralph Metzler & Marcus Metzler + * for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -32,7 +31,6 @@ #include <linux/wait.h> #include <asm/uaccess.h> #include <asm/system.h> - #include "dmxdev.h" static int debug; @@ -42,119 +40,83 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); #define dprintk if (debug) printk -static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) +static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, + const u8 *src, size_t len) { - buffer->data=NULL; - buffer->size=8192; - buffer->pread=0; - buffer->pwrite=0; - buffer->error=0; - init_waitqueue_head(&buffer->queue); -} - -static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf, const u8 *src, int len) -{ - int split; - int free; - int todo; + ssize_t free; if (!len) return 0; if (!buf->data) return 0; - free=buf->pread-buf->pwrite; - split=0; - if (free<=0) { - free+=buf->size; - split=buf->size-buf->pwrite; - } - if (len>=free) { + free = dvb_ringbuffer_free(buf); + if (len > free) { dprintk("dmxdev: buffer overflow\n"); - return -1; + return -EOVERFLOW; } - if (split>=len) - split=0; - todo=len; - if (split) { - memcpy(buf->data + buf->pwrite, src, split); - todo-=split; - buf->pwrite=0; - } - memcpy(buf->data + buf->pwrite, src+split, todo); - buf->pwrite=(buf->pwrite+todo)%buf->size; - return len; + + return dvb_ringbuffer_write(buf, src, len); } -static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_buffer *src, - int non_blocking, char __user *buf, size_t count, loff_t *ppos) +static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, + int non_blocking, char __user *buf, + size_t count, loff_t *ppos) { - unsigned long todo=count; - int split, avail, error; + size_t todo; + ssize_t avail; + ssize_t ret = 0; if (!src->data) return 0; - if ((error=src->error)) { - src->pwrite=src->pread; - src->error=0; - return error; + if (src->error) { + ret = src->error; + dvb_ringbuffer_flush(src); + return ret; } - if (non_blocking && (src->pwrite==src->pread)) - return -EWOULDBLOCK; - - while (todo>0) { - if (non_blocking && (src->pwrite==src->pread)) - return (count-todo) ? (count-todo) : -EWOULDBLOCK; + for (todo = count; todo > 0; todo -= ret) { + if (non_blocking && dvb_ringbuffer_empty(src)) { + ret = -EWOULDBLOCK; + break; + } - if (wait_event_interruptible(src->queue, - (src->pread!=src->pwrite) || - (src->error))<0) - return count-todo; + ret = wait_event_interruptible(src->queue, + !dvb_ringbuffer_empty(src) || + (src->error != 0)); + if (ret < 0) + break; - if ((error=src->error)) { - src->pwrite=src->pread; - src->error=0; - return error; + if (src->error) { + ret = src->error; + dvb_ringbuffer_flush(src); + break; } - split=src->size; - avail=src->pwrite - src->pread; - if (avail<0) { - avail+=src->size; - split=src->size - src->pread; - } - if (avail>todo) - avail=todo; - if (split<avail) { - if (copy_to_user(buf, src->data+src->pread, split)) - return -EFAULT; - buf+=split; - src->pread=0; - todo-=split; - avail-=split; - } - if (avail) { - if (copy_to_user(buf, src->data+src->pread, avail)) - return -EFAULT; - src->pread = (src->pread + avail) % src->size; - todo-=avail; - buf+=avail; - } + avail = dvb_ringbuffer_avail(src); + if (avail > todo) + avail = todo; + + ret = dvb_ringbuffer_read(src, buf, avail, 1); + if (ret < 0) + break; + + buf += ret; } - return count; + + return (count - todo) ? (count - todo) : ret; } -static struct dmx_frontend * get_fe(struct dmx_demux *demux, int type) +static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type) { struct list_head *head, *pos; - head=demux->get_frontends(demux); + head = demux->get_frontends(demux); if (!head) return NULL; list_for_each(pos, head) - if (DMX_FE_ENTRY(pos)->source==type) + if (DMX_FE_ENTRY(pos)->source == type) return DMX_FE_ENTRY(pos); return NULL; @@ -166,37 +128,36 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) struct dmxdev *dmxdev = dvbdev->priv; struct dmx_frontend *front; - dprintk ("function : %s\n", __FUNCTION__); + dprintk("function : %s\n", __FUNCTION__); if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; - if ((file->f_flags&O_ACCMODE)==O_RDWR) { - if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) { + if ((file->f_flags & O_ACCMODE) == O_RDWR) { + if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { mutex_unlock(&dmxdev->mutex); return -EOPNOTSUPP; } } - if ((file->f_flags&O_ACCMODE)==O_RDONLY) { - dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer); - dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE; - dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE); - if (!dmxdev->dvr_buffer.data) { - mutex_unlock(&dmxdev->mutex); - return -ENOMEM; - } + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + void *mem = vmalloc(DVR_BUFFER_SIZE); + if (!mem) { + mutex_unlock(&dmxdev->mutex); + return -ENOMEM; + } + dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); } - if ((file->f_flags&O_ACCMODE)==O_WRONLY) { - dmxdev->dvr_orig_fe=dmxdev->demux->frontend; + if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + dmxdev->dvr_orig_fe = dmxdev->demux->frontend; if (!dmxdev->demux->write) { mutex_unlock(&dmxdev->mutex); return -EOPNOTSUPP; } - front=get_fe(dmxdev->demux, DMX_MEMORY_FE); + front = get_fe(dmxdev->demux, DMX_MEMORY_FE); if (!front) { mutex_unlock(&dmxdev->mutex); @@ -217,17 +178,17 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; - if ((file->f_flags&O_ACCMODE)==O_WRONLY) { + if ((file->f_flags & O_ACCMODE) == O_WRONLY) { dmxdev->demux->disconnect_frontend(dmxdev->demux); dmxdev->demux->connect_frontend(dmxdev->demux, dmxdev->dvr_orig_fe); } - if ((file->f_flags&O_ACCMODE)==O_RDONLY) { + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if (dmxdev->dvr_buffer.data) { - void *mem=dmxdev->dvr_buffer.data; + void *mem = dmxdev->dvr_buffer.data; mb(); spin_lock_irq(&dmxdev->lock); - dmxdev->dvr_buffer.data=NULL; + dmxdev->dvr_buffer.data = NULL; spin_unlock_irq(&dmxdev->lock); vfree(mem); } @@ -237,7 +198,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) } static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; @@ -245,60 +206,62 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, if (!dmxdev->demux->write) return -EOPNOTSUPP; - if ((file->f_flags&O_ACCMODE)!=O_WRONLY) + if ((file->f_flags & O_ACCMODE) != O_WRONLY) return -EINVAL; if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; - ret=dmxdev->demux->write(dmxdev->demux, buf, count); + ret = dmxdev->demux->write(dmxdev->demux, buf, count); mutex_unlock(&dmxdev->mutex); return ret; } static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) + loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; int ret; //mutex_lock(&dmxdev->mutex); - ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, - file->f_flags&O_NONBLOCK, - buf, count, ppos); + ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); //mutex_unlock(&dmxdev->mutex); return ret; } -static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter *dmxdevfilter, int state) +static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter + *dmxdevfilter, int state) { spin_lock_irq(&dmxdevfilter->dev->lock); - dmxdevfilter->state=state; + dmxdevfilter->state = state; spin_unlock_irq(&dmxdevfilter->dev->lock); } -static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsigned long size) +static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, + unsigned long size) { - struct dmxdev_buffer *buf=&dmxdevfilter->buffer; + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; void *mem; - if (buf->size==size) + if (buf->size == size) return 0; - if (dmxdevfilter->state>=DMXDEV_STATE_GO) + if (dmxdevfilter->state >= DMXDEV_STATE_GO) return -EBUSY; spin_lock_irq(&dmxdevfilter->dev->lock); - mem=buf->data; - buf->data=NULL; - buf->size=size; - buf->pwrite=buf->pread=0; + mem = buf->data; + buf->data = NULL; + buf->size = size; + dvb_ringbuffer_flush(buf); spin_unlock_irq(&dmxdevfilter->dev->lock); vfree(mem); if (buf->size) { - mem=vmalloc(dmxdevfilter->buffer.size); + mem = vmalloc(dmxdevfilter->buffer.size); if (!mem) return -ENOMEM; spin_lock_irq(&dmxdevfilter->dev->lock); - buf->data=mem; + buf->data = mem; spin_unlock_irq(&dmxdevfilter->dev->lock); } return 0; @@ -306,31 +269,33 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsign static void dvb_dmxdev_filter_timeout(unsigned long data) { - struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *)data; + struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; - dmxdevfilter->buffer.error=-ETIMEDOUT; + dmxdevfilter->buffer.error = -ETIMEDOUT; spin_lock_irq(&dmxdevfilter->dev->lock); - dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT; + dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; spin_unlock_irq(&dmxdevfilter->dev->lock); wake_up(&dmxdevfilter->buffer.queue); } static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) { - struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec; + struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec; del_timer(&dmxdevfilter->timer); if (para->timeout) { - dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout; - dmxdevfilter->timer.data=(unsigned long) dmxdevfilter; - dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000; + dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout; + dmxdevfilter->timer.data = (unsigned long)dmxdevfilter; + dmxdevfilter->timer.expires = + jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; add_timer(&dmxdevfilter->timer); } } static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *filter, enum dmx_success success) + const u8 *buffer2, size_t buffer2_len, + struct dmx_section_filter *filter, + enum dmx_success success) { struct dmxdev_filter *dmxdevfilter = filter->priv; int ret; @@ -340,68 +305,68 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, return 0; } spin_lock(&dmxdevfilter->dev->lock); - if (dmxdevfilter->state!=DMXDEV_STATE_GO) { + if (dmxdevfilter->state != DMXDEV_STATE_GO) { spin_unlock(&dmxdevfilter->dev->lock); return 0; } del_timer(&dmxdevfilter->timer); dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n", buffer1[0], buffer1[1], - buffer1[2], buffer1[3], - buffer1[4], buffer1[5]); - ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len); - if (ret==buffer1_len) { - ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len); + buffer1[2], buffer1[3], buffer1[4], buffer1[5]); + ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, + buffer1_len); + if (ret == buffer1_len) { + ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, + buffer2_len); } - if (ret<0) { - dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread; - dmxdevfilter->buffer.error=-EOVERFLOW; + if (ret < 0) { + dvb_ringbuffer_flush(&dmxdevfilter->buffer); + dmxdevfilter->buffer.error = ret; } - if (dmxdevfilter->params.sec.flags&DMX_ONESHOT) - dmxdevfilter->state=DMXDEV_STATE_DONE; + if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) + dmxdevfilter->state = DMXDEV_STATE_DONE; spin_unlock(&dmxdevfilter->dev->lock); wake_up(&dmxdevfilter->buffer.queue); return 0; } static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed, enum dmx_success success) + const u8 *buffer2, size_t buffer2_len, + struct dmx_ts_feed *feed, + enum dmx_success success) { struct dmxdev_filter *dmxdevfilter = feed->priv; - struct dmxdev_buffer *buffer; + struct dvb_ringbuffer *buffer; int ret; spin_lock(&dmxdevfilter->dev->lock); - if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) { + if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { spin_unlock(&dmxdevfilter->dev->lock); return 0; } - if (dmxdevfilter->params.pes.output==DMX_OUT_TAP) - buffer=&dmxdevfilter->buffer; + if (dmxdevfilter->params.pes.output == DMX_OUT_TAP) + buffer = &dmxdevfilter->buffer; else - buffer=&dmxdevfilter->dev->dvr_buffer; + buffer = &dmxdevfilter->dev->dvr_buffer; if (buffer->error) { spin_unlock(&dmxdevfilter->dev->lock); wake_up(&buffer->queue); return 0; } - ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); - if (ret==buffer1_len) - ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); - if (ret<0) { - buffer->pwrite=buffer->pread; - buffer->error=-EOVERFLOW; + ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); + if (ret == buffer1_len) + ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); + if (ret < 0) { + dvb_ringbuffer_flush(buffer); + buffer->error = ret; } spin_unlock(&dmxdevfilter->dev->lock); wake_up(&buffer->queue); return 0; } - /* stop feed but only mark the specified filter as stopped (state set) */ - static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) { dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); @@ -420,20 +385,16 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) return 0; } - /* start feed associated with the specified filter */ - static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) { - dvb_dmxdev_filter_state_set (filter, DMXDEV_STATE_GO); + dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); switch (filter->type) { case DMXDEV_TYPE_SEC: return filter->feed.sec->start_filtering(filter->feed.sec); - break; case DMXDEV_TYPE_PES: return filter->feed.ts->start_filtering(filter->feed.ts); - break; default: return -EINVAL; } @@ -441,32 +402,31 @@ static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) return 0; } - /* restart section feed if it has filters left associated with it, otherwise release the feed */ - static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) { int i; struct dmxdev *dmxdev = filter->dev; u16 pid = filter->params.sec.pid; - for (i=0; i<dmxdev->filternum; i++) - if (dmxdev->filter[i].state>=DMXDEV_STATE_GO && - dmxdev->filter[i].type==DMXDEV_TYPE_SEC && - dmxdev->filter[i].pid==pid) { + for (i = 0; i < dmxdev->filternum; i++) + if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && + dmxdev->filter[i].type == DMXDEV_TYPE_SEC && + dmxdev->filter[i].params.sec.pid == pid) { dvb_dmxdev_feed_start(&dmxdev->filter[i]); return 0; } - filter->dev->demux->release_section_feed(dmxdev->demux, filter->feed.sec); + filter->dev->demux->release_section_feed(dmxdev->demux, + filter->feed.sec); return 0; } static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) { - if (dmxdevfilter->state<DMXDEV_STATE_GO) + if (dmxdevfilter->state < DMXDEV_STATE_GO) return 0; switch (dmxdevfilter->type) { @@ -476,36 +436,36 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) dvb_dmxdev_feed_stop(dmxdevfilter); if (dmxdevfilter->filter.sec) dmxdevfilter->feed.sec-> - release_filter(dmxdevfilter->feed.sec, - dmxdevfilter->filter.sec); + release_filter(dmxdevfilter->feed.sec, + dmxdevfilter->filter.sec); dvb_dmxdev_feed_restart(dmxdevfilter); - dmxdevfilter->feed.sec=NULL; + dmxdevfilter->feed.sec = NULL; break; case DMXDEV_TYPE_PES: if (!dmxdevfilter->feed.ts) break; dvb_dmxdev_feed_stop(dmxdevfilter); dmxdevfilter->dev->demux-> - release_ts_feed(dmxdevfilter->dev->demux, - dmxdevfilter->feed.ts); - dmxdevfilter->feed.ts=NULL; + release_ts_feed(dmxdevfilter->dev->demux, + dmxdevfilter->feed.ts); + dmxdevfilter->feed.ts = NULL; break; default: - if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED) + if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) return 0; return -EINVAL; } - dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0; + + dvb_ringbuffer_flush(&dmxdevfilter->buffer); return 0; } static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) { - if (dmxdevfilter->state<DMXDEV_STATE_SET) + if (dmxdevfilter->state < DMXDEV_STATE_SET) return 0; - dmxdevfilter->type=DMXDEV_TYPE_NONE; - dmxdevfilter->pid=0xffff; + dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); return 0; } @@ -522,32 +482,33 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) if (filter->state >= DMXDEV_STATE_GO) dvb_dmxdev_filter_stop(filter); - if (!(mem = filter->buffer.data)) { + if (!filter->buffer.data) { mem = vmalloc(filter->buffer.size); + if (!mem) + return -ENOMEM; spin_lock_irq(&filter->dev->lock); - filter->buffer.data=mem; + filter->buffer.data = mem; spin_unlock_irq(&filter->dev->lock); - if (!filter->buffer.data) - return -ENOMEM; } - filter->buffer.pwrite = filter->buffer.pread = 0; + dvb_ringbuffer_flush(&filter->buffer); switch (filter->type) { case DMXDEV_TYPE_SEC: { - struct dmx_sct_filter_params *para=&filter->params.sec; - struct dmx_section_filter **secfilter=&filter->filter.sec; - struct dmx_section_feed **secfeed=&filter->feed.sec; + struct dmx_sct_filter_params *para = &filter->params.sec; + struct dmx_section_filter **secfilter = &filter->filter.sec; + struct dmx_section_feed **secfeed = &filter->feed.sec; + + *secfilter = NULL; + *secfeed = NULL; - *secfilter=NULL; - *secfeed=NULL; /* find active filter/feed with same PID */ - for (i=0; i<dmxdev->filternum; i++) { + for (i = 0; i < dmxdev->filternum; i++) { if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && - dmxdev->filter[i].pid == para->pid && - dmxdev->filter[i].type == DMXDEV_TYPE_SEC) { + dmxdev->filter[i].type == DMXDEV_TYPE_SEC && + dmxdev->filter[i].params.sec.pid == para->pid) { *secfeed = dmxdev->filter[i].feed.sec; break; } @@ -555,21 +516,20 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) /* if no feed found, try to allocate new one */ if (!*secfeed) { - ret=dmxdev->demux->allocate_section_feed(dmxdev->demux, - secfeed, - dvb_dmxdev_section_callback); - if (ret<0) { - printk ("DVB (%s): could not alloc feed\n", - __FUNCTION__); + ret = dmxdev->demux->allocate_section_feed(dmxdev->demux, + secfeed, + dvb_dmxdev_section_callback); + if (ret < 0) { + printk("DVB (%s): could not alloc feed\n", + __FUNCTION__); return ret; } - ret=(*secfeed)->set(*secfeed, para->pid, 32768, - (para->flags & DMX_CHECK_CRC) ? 1 : 0); - - if (ret<0) { - printk ("DVB (%s): could not set feed\n", - __FUNCTION__); + ret = (*secfeed)->set(*secfeed, para->pid, 32768, + (para->flags & DMX_CHECK_CRC) ? 1 : 0); + if (ret < 0) { + printk("DVB (%s): could not set feed\n", + __FUNCTION__); dvb_dmxdev_feed_restart(filter); return ret; } @@ -577,41 +537,38 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) dvb_dmxdev_feed_stop(filter); } - ret=(*secfeed)->allocate_filter(*secfeed, secfilter); - + ret = (*secfeed)->allocate_filter(*secfeed, secfilter); if (ret < 0) { dvb_dmxdev_feed_restart(filter); filter->feed.sec->start_filtering(*secfeed); - dprintk ("could not get filter\n"); + dprintk("could not get filter\n"); return ret; } (*secfilter)->priv = filter; memcpy(&((*secfilter)->filter_value[3]), - &(para->filter.filter[1]), DMX_FILTER_SIZE-1); + &(para->filter.filter[1]), DMX_FILTER_SIZE - 1); memcpy(&(*secfilter)->filter_mask[3], - ¶->filter.mask[1], DMX_FILTER_SIZE-1); + ¶->filter.mask[1], DMX_FILTER_SIZE - 1); memcpy(&(*secfilter)->filter_mode[3], - ¶->filter.mode[1], DMX_FILTER_SIZE-1); + ¶->filter.mode[1], DMX_FILTER_SIZE - 1); - (*secfilter)->filter_value[0]=para->filter.filter[0]; - (*secfilter)->filter_mask[0]=para->filter.mask[0]; - (*secfilter)->filter_mode[0]=para->filter.mode[0]; - (*secfilter)->filter_mask[1]=0; - (*secfilter)->filter_mask[2]=0; + (*secfilter)->filter_value[0] = para->filter.filter[0]; + (*secfilter)->filter_mask[0] = para->filter.mask[0]; + (*secfilter)->filter_mode[0] = para->filter.mode[0]; + (*secfilter)->filter_mask[1] = 0; + (*secfilter)->filter_mask[2] = 0; filter->todo = 0; - ret = filter->feed.sec->start_filtering (filter->feed.sec); - + ret = filter->feed.sec->start_filtering(filter->feed.sec); if (ret < 0) return ret; dvb_dmxdev_filter_timer(filter); break; } - case DMXDEV_TYPE_PES: { struct timespec timeout = { 0 }; @@ -623,41 +580,41 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) struct dmx_ts_feed **tsfeed = &filter->feed.ts; filter->feed.ts = NULL; - otype=para->output; + otype = para->output; - ts_pes=(enum dmx_ts_pes) para->pes_type; + ts_pes = (enum dmx_ts_pes)para->pes_type; - if (ts_pes<DMX_PES_OTHER) - ts_type=TS_DECODER; + if (ts_pes < DMX_PES_OTHER) + ts_type = TS_DECODER; else - ts_type=0; + ts_type = 0; if (otype == DMX_OUT_TS_TAP) ts_type |= TS_PACKET; if (otype == DMX_OUT_TAP) - ts_type |= TS_PAYLOAD_ONLY|TS_PACKET; + ts_type |= TS_PAYLOAD_ONLY | TS_PACKET; - ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux, - tsfeed, - dvb_dmxdev_ts_callback); - if (ret<0) + ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, + tsfeed, + dvb_dmxdev_ts_callback); + if (ret < 0) return ret; - (*tsfeed)->priv = (void *) filter; + (*tsfeed)->priv = filter; ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, 32768, timeout); - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); + dmxdev->demux->release_ts_feed(dmxdev->demux, + *tsfeed); return ret; } ret = filter->feed.ts->start_filtering(filter->feed.ts); - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); + dmxdev->demux->release_ts_feed(dmxdev->demux, + *tsfeed); return ret; } @@ -684,32 +641,31 @@ static int dvb_demux_open(struct inode *inode, struct file *file) if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; - for (i=0; i<dmxdev->filternum; i++) - if (dmxdev->filter[i].state==DMXDEV_STATE_FREE) + for (i = 0; i < dmxdev->filternum; i++) + if (dmxdev->filter[i].state == DMXDEV_STATE_FREE) break; - if (i==dmxdev->filternum) { + if (i == dmxdev->filternum) { mutex_unlock(&dmxdev->mutex); return -EMFILE; } - dmxdevfilter=&dmxdev->filter[i]; + dmxdevfilter = &dmxdev->filter[i]; mutex_init(&dmxdevfilter->mutex); - dmxdevfilter->dvbdev=dmxdev->dvbdev; - file->private_data=dmxdevfilter; + file->private_data = dmxdevfilter; - dvb_dmxdev_buffer_init(&dmxdevfilter->buffer); - dmxdevfilter->type=DMXDEV_TYPE_NONE; + dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); + dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - dmxdevfilter->feed.ts=NULL; + dmxdevfilter->feed.ts = NULL; init_timer(&dmxdevfilter->timer); mutex_unlock(&dmxdev->mutex); return 0; } - -static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter) +static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, + struct dmxdev_filter *dmxdevfilter) { if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; @@ -723,10 +679,10 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *d dvb_dmxdev_filter_reset(dmxdevfilter); if (dmxdevfilter->buffer.data) { - void *mem=dmxdevfilter->buffer.data; + void *mem = dmxdevfilter->buffer.data; spin_lock_irq(&dmxdev->lock); - dmxdevfilter->buffer.data=NULL; + dmxdevfilter->buffer.data = NULL; spin_unlock_irq(&dmxdev->lock); vfree(mem); } @@ -742,120 +698,120 @@ static inline void invert_mode(dmx_filter_t *filter) { int i; - for (i=0; i<DMX_FILTER_SIZE; i++) - filter->mode[i]^=0xff; + for (i = 0; i < DMX_FILTER_SIZE; i++) + filter->mode[i] ^= 0xff; } - static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, - struct dmxdev_filter *dmxdevfilter, - struct dmx_sct_filter_params *params) + struct dmxdev_filter *dmxdevfilter, + struct dmx_sct_filter_params *params) { - dprintk ("function : %s\n", __FUNCTION__); + dprintk("function : %s\n", __FUNCTION__); dvb_dmxdev_filter_stop(dmxdevfilter); - dmxdevfilter->type=DMXDEV_TYPE_SEC; - dmxdevfilter->pid=params->pid; + dmxdevfilter->type = DMXDEV_TYPE_SEC; memcpy(&dmxdevfilter->params.sec, params, sizeof(struct dmx_sct_filter_params)); invert_mode(&dmxdevfilter->params.sec.filter); dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); - if (params->flags&DMX_IMMEDIATE_START) + if (params->flags & DMX_IMMEDIATE_START) return dvb_dmxdev_filter_start(dmxdevfilter); return 0; } static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, - struct dmxdev_filter *dmxdevfilter, - struct dmx_pes_filter_params *params) + struct dmxdev_filter *dmxdevfilter, + struct dmx_pes_filter_params *params) { dvb_dmxdev_filter_stop(dmxdevfilter); - if (params->pes_type>DMX_PES_OTHER || params->pes_type<0) + if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0) return -EINVAL; - dmxdevfilter->type=DMXDEV_TYPE_PES; - dmxdevfilter->pid=params->pid; - memcpy(&dmxdevfilter->params, params, sizeof(struct dmx_pes_filter_params)); + dmxdevfilter->type = DMXDEV_TYPE_PES; + memcpy(&dmxdevfilter->params, params, + sizeof(struct dmx_pes_filter_params)); dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); - if (params->flags&DMX_IMMEDIATE_START) + if (params->flags & DMX_IMMEDIATE_START) return dvb_dmxdev_filter_start(dmxdevfilter); return 0; } static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, - struct file *file, char __user *buf, size_t count, loff_t *ppos) + struct file *file, char __user *buf, + size_t count, loff_t *ppos) { int result, hcount; - int done=0; - - if (dfil->todo<=0) { - hcount=3+dfil->todo; - if (hcount>count) - hcount=count; - result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, - buf, hcount, ppos); - if (result<0) { - dfil->todo=0; + int done = 0; + + if (dfil->todo <= 0) { + hcount = 3 + dfil->todo; + if (hcount > count) + hcount = count; + result = dvb_dmxdev_buffer_read(&dfil->buffer, + file->f_flags & O_NONBLOCK, + buf, hcount, ppos); + if (result < 0) { + dfil->todo = 0; return result; } - if (copy_from_user(dfil->secheader-dfil->todo, buf, result)) + if (copy_from_user(dfil->secheader - dfil->todo, buf, result)) return -EFAULT; - buf+=result; - done=result; - count-=result; - dfil->todo-=result; - if (dfil->todo>-3) + buf += result; + done = result; + count -= result; + dfil->todo -= result; + if (dfil->todo > -3) return done; - dfil->todo=((dfil->secheader[1]<<8)|dfil->secheader[2])&0xfff; + dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff; if (!count) return done; } - if (count>dfil->todo) - count=dfil->todo; - result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, - buf, count, ppos); - if (result<0) + if (count > dfil->todo) + count = dfil->todo; + result = dvb_dmxdev_buffer_read(&dfil->buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); + if (result < 0) return result; - dfil->todo-=result; - return (result+done); + dfil->todo -= result; + return (result + done); } - static ssize_t -dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +dvb_demux_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) { - struct dmxdev_filter *dmxdevfilter= file->private_data; - int ret=0; + struct dmxdev_filter *dmxdevfilter = file->private_data; + int ret; if (mutex_lock_interruptible(&dmxdevfilter->mutex)) return -ERESTARTSYS; - if (dmxdevfilter->type==DMXDEV_TYPE_SEC) - ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); + if (dmxdevfilter->type == DMXDEV_TYPE_SEC) + ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); else - ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, - file->f_flags&O_NONBLOCK, - buf, count, ppos); + ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); mutex_unlock(&dmxdevfilter->mutex); return ret; } - static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { struct dmxdev_filter *dmxdevfilter = file->private_data; - struct dmxdev *dmxdev=dmxdevfilter->dev; - unsigned long arg=(unsigned long) parg; - int ret=0; + struct dmxdev *dmxdev = dmxdevfilter->dev; + unsigned long arg = (unsigned long)parg; + int ret = 0; if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; @@ -866,7 +822,7 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - if (dmxdevfilter->state<DMXDEV_STATE_SET) + if (dmxdevfilter->state < DMXDEV_STATE_SET) ret = -EINVAL; else ret = dvb_dmxdev_filter_start(dmxdevfilter); @@ -878,7 +834,7 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret=dvb_dmxdev_filter_stop(dmxdevfilter); + ret = dvb_dmxdev_filter_stop(dmxdevfilter); mutex_unlock(&dmxdevfilter->mutex); break; @@ -887,8 +843,7 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, - (struct dmx_sct_filter_params *)parg); + ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); mutex_unlock(&dmxdevfilter->mutex); break; @@ -897,8 +852,7 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, - (struct dmx_pes_filter_params *)parg); + ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); mutex_unlock(&dmxdevfilter->mutex); break; @@ -907,7 +861,7 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); + ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); mutex_unlock(&dmxdevfilter->mutex); break; @@ -916,10 +870,10 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, case DMX_GET_PES_PIDS: if (!dmxdev->demux->get_pes_pids) { - ret=-EINVAL; + ret = -EINVAL; break; } - dmxdev->demux->get_pes_pids(dmxdev->demux, (u16 *)parg); + dmxdev->demux->get_pes_pids(dmxdev->demux, parg); break; case DMX_GET_CAPS: @@ -940,17 +894,18 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, case DMX_GET_STC: if (!dmxdev->demux->get_stc) { - ret=-EINVAL; + ret = -EINVAL; break; } ret = dmxdev->demux->get_stc(dmxdev->demux, - ((struct dmx_stc *)parg)->num, - &((struct dmx_stc *)parg)->stc, - &((struct dmx_stc *)parg)->base); + ((struct dmx_stc *)parg)->num, + &((struct dmx_stc *)parg)->stc, + &((struct dmx_stc *)parg)->base); break; default: - ret=-EINVAL; + ret = -EINVAL; + break; } mutex_unlock(&dmxdev->mutex); return ret; @@ -962,8 +917,7 @@ static int dvb_demux_ioctl(struct inode *inode, struct file *file, return dvb_usercopy(inode, file, cmd, arg, dvb_demux_do_ioctl); } - -static unsigned int dvb_demux_poll (struct file *file, poll_table *wait) +static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) { struct dmxdev_filter *dmxdevfilter = file->private_data; unsigned int mask = 0; @@ -981,13 +935,12 @@ static unsigned int dvb_demux_poll (struct file *file, poll_table *wait) if (dmxdevfilter->buffer.error) mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); - if (dmxdevfilter->buffer.pread != dmxdevfilter->buffer.pwrite) + if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) mask |= (POLLIN | POLLRDNORM | POLLPRI); return mask; } - static int dvb_demux_release(struct inode *inode, struct file *file) { struct dmxdev_filter *dmxdevfilter = file->private_data; @@ -996,32 +949,28 @@ static int dvb_demux_release(struct inode *inode, struct file *file) return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); } - static struct file_operations dvb_demux_fops = { - .owner = THIS_MODULE, - .read = dvb_demux_read, - .ioctl = dvb_demux_ioctl, - .open = dvb_demux_open, - .release = dvb_demux_release, - .poll = dvb_demux_poll, + .owner = THIS_MODULE, + .read = dvb_demux_read, + .ioctl = dvb_demux_ioctl, + .open = dvb_demux_open, + .release = dvb_demux_release, + .poll = dvb_demux_poll, }; - static struct dvb_device dvbdev_demux = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_demux_fops + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_demux_fops }; - static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *parg) + unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; - - int ret=0; + int ret; if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; @@ -1029,39 +978,38 @@ static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file, switch (cmd) { case DMX_SET_BUFFER_SIZE: // FIXME: implement - ret=0; + ret = 0; break; default: - ret=-EINVAL; + ret = -EINVAL; + break; } mutex_unlock(&dmxdev->mutex); return ret; } - static int dvb_dvr_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { return dvb_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl); } - -static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait) +static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; unsigned int mask = 0; - dprintk ("function : %s\n", __FUNCTION__); + dprintk("function : %s\n", __FUNCTION__); poll_wait(file, &dmxdev->dvr_buffer.queue, wait); - if ((file->f_flags&O_ACCMODE) == O_RDONLY) { + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if (dmxdev->dvr_buffer.error) mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); - if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite) + if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) mask |= (POLLIN | POLLRDNORM | POLLPRI); } else mask |= (POLLOUT | POLLWRNORM | POLLPRI); @@ -1069,61 +1017,63 @@ static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait) return mask; } - static struct file_operations dvb_dvr_fops = { - .owner = THIS_MODULE, - .read = dvb_dvr_read, - .write = dvb_dvr_write, - .ioctl = dvb_dvr_ioctl, - .open = dvb_dvr_open, - .release = dvb_dvr_release, - .poll = dvb_dvr_poll, + .owner = THIS_MODULE, + .read = dvb_dvr_read, + .write = dvb_dvr_write, + .ioctl = dvb_dvr_ioctl, + .open = dvb_dvr_open, + .release = dvb_dvr_release, + .poll = dvb_dvr_poll, }; static struct dvb_device dvbdev_dvr = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_dvr_fops + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_dvr_fops }; -int -dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) +int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) { int i; if (dmxdev->demux->open(dmxdev->demux) < 0) return -EUSERS; - dmxdev->filter = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_filter)); + dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter)); if (!dmxdev->filter) return -ENOMEM; mutex_init(&dmxdev->mutex); spin_lock_init(&dmxdev->lock); - for (i=0; i<dmxdev->filternum; i++) { - dmxdev->filter[i].dev=dmxdev; - dmxdev->filter[i].buffer.data=NULL; - dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); + for (i = 0; i < dmxdev->filternum; i++) { + dmxdev->filter[i].dev = dmxdev; + dmxdev->filter[i].buffer.data = NULL; + dvb_dmxdev_filter_state_set(&dmxdev->filter[i], + DMXDEV_STATE_FREE); } - dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX); - dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR); + dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, + DVB_DEVICE_DEMUX); + dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, + dmxdev, DVB_DEVICE_DVR); - dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer); + dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); return 0; } + EXPORT_SYMBOL(dvb_dmxdev_init); -void -dvb_dmxdev_release(struct dmxdev *dmxdev) +void dvb_dmxdev_release(struct dmxdev *dmxdev) { dvb_unregister_device(dmxdev->dvbdev); dvb_unregister_device(dmxdev->dvr_dvbdev); vfree(dmxdev->filter); - dmxdev->filter=NULL; + dmxdev->filter = NULL; dmxdev->demux->close(dmxdev->demux); } + EXPORT_SYMBOL(dvb_dmxdev_release); diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.h b/linux/drivers/media/dvb/dvb-core/dmxdev.h index d1d34a71b..080abd9a9 100644 --- a/linux/drivers/media/dvb/dvb-core/dmxdev.h +++ b/linux/drivers/media/dvb/dvb-core/dmxdev.h @@ -39,8 +39,9 @@ #include "dvbdev.h" #include "demux.h" +#include "dvb_ringbuffer.h" -enum dmxdevype { +enum dmxdev_type { DMXDEV_TYPE_NONE, DMXDEV_TYPE_SEC, DMXDEV_TYPE_PES, @@ -55,18 +56,7 @@ enum dmxdev_state { DMXDEV_STATE_TIMEDOUT }; -struct dmxdev_buffer { - u8 *data; - int size; - int pread; - int pwrite; - wait_queue_head_t queue; - int error; -}; - struct dmxdev_filter { - struct dvb_device *dvbdev; - union { struct dmx_section_filter *sec; } filter; @@ -81,10 +71,10 @@ struct dmxdev_filter { struct dmx_pes_filter_params pes; } params; - int type; + enum dmxdev_type type; enum dmxdev_state state; struct dmxdev *dev; - struct dmxdev_buffer buffer; + struct dvb_ringbuffer buffer; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) struct mutex mutex; @@ -96,8 +86,6 @@ struct dmxdev_filter { struct timer_list timer; int todo; u8 secheader[3]; - - u16 pid; }; @@ -113,7 +101,7 @@ struct dmxdev { #define DMXDEV_CAP_DUPLEX 1 struct dmx_frontend *dvr_orig_fe; - struct dmxdev_buffer dvr_buffer; + struct dvb_ringbuffer dvr_buffer; #define DVR_BUFFER_SIZE (10*188*1024) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) diff --git a/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index 77ad2410f..c972fe014 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c @@ -45,6 +45,7 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) rbuf->pread=rbuf->pwrite=0; rbuf->data=data; rbuf->size=len; + rbuf->error=0; init_waitqueue_head(&rbuf->queue); @@ -87,6 +88,7 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) { rbuf->pread = rbuf->pwrite; + rbuf->error = 0; } diff --git a/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h index 6d2560972..d97714e75 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h +++ b/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h @@ -35,6 +35,7 @@ struct dvb_ringbuffer { ssize_t size; ssize_t pread; ssize_t pwrite; + int error; wait_queue_head_t queue; spinlock_t lock; diff --git a/linux/drivers/media/dvb/dvb-usb/dtt200u.c b/linux/drivers/media/dvb/dvb-usb/dtt200u.c index d2ce5d52a..b25f65238 100644 --- a/linux/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/linux/drivers/media/dvb/dvb-usb/dtt200u.c @@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = { .cold_ids = { &dtt200u_usb_table[0], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL }, }, - { 0 }, + { NULL }, } }; @@ -192,7 +192,7 @@ static struct dvb_usb_properties wt220u_properties = { .cold_ids = { &dtt200u_usb_table[2], NULL }, .warm_ids = { &dtt200u_usb_table[3], NULL }, }, - { 0 }, + { NULL }, } }; diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c index 4258a995d..a1705ecb9 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -47,7 +47,7 @@ static int dvb_usb_init(struct dvb_usb_device *d) d->state = DVB_USB_STATE_INIT; -/* check the capabilites and set appropriate variables */ +/* check the capabilities and set appropriate variables */ /* speed - when running at FULL speed we need a HW PID filter */ if (d->udev->speed == USB_SPEED_FULL && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) { diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb.h index bdf596c42..b14e842d0 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -91,7 +91,7 @@ struct dvb_usb_device; /** * struct dvb_usb_properties - properties of a dvb-usb-device - * @caps: capabilites of the DVB USB device. + * @caps: capabilities of the DVB USB device. * @pid_filter_count: number of PID filter position in the optional hardware * PID-filter. * diff --git a/linux/drivers/media/dvb/dvb-usb/vp7045.c b/linux/drivers/media/dvb/dvb-usb/vp7045.c index 16aa00ec4..20beb2539 100644 --- a/linux/drivers/media/dvb/dvb-usb/vp7045.c +++ b/linux/drivers/media/dvb/dvb-usb/vp7045.c @@ -247,7 +247,7 @@ static struct dvb_usb_properties vp7045_properties = { .cold_ids = { &vp7045_usb_table[2], NULL }, .warm_ids = { &vp7045_usb_table[3], NULL }, }, - { 0 }, + { NULL }, } }; diff --git a/linux/drivers/media/dvb/frontends/zl10353.c b/linux/drivers/media/dvb/frontends/zl10353.c index c1510ebb8..10bb871fa 100644 --- a/linux/drivers/media/dvb/frontends/zl10353.c +++ b/linux/drivers/media/dvb/frontends/zl10353.c @@ -91,7 +91,7 @@ static int zl10353_read_register(struct zl10353_state *state, u8 reg) } #if 1 -void zl10353_dump_regs(struct dvb_frontend *fe) +static void zl10353_dump_regs(struct dvb_frontend *fe) { struct zl10353_state *state = fe->demodulator_priv; char buf[52], buf2[4]; diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c index 56492926a..106022c39 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.c +++ b/linux/drivers/media/dvb/ttpci/av7110.c @@ -1090,11 +1090,9 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, struct av7110 *av7110; /* pointer casting paranoia... */ - if (!demux) - BUG(); + BUG_ON(!demux); dvbdemux = (struct dvb_demux *) demux->priv; - if (!dvbdemux) - BUG(); + BUG_ON(!dvbdemux); av7110 = (struct av7110 *) dvbdemux->priv; dprintk(4, "%p\n", av7110); @@ -1441,7 +1439,7 @@ static int check_firmware(struct av7110* av7110) len = ntohl(*(u32*) ptr); ptr += 4; if (len >= 512) { - printk("dvb-ttpci: dpram file is way to big.\n"); + printk("dvb-ttpci: dpram file is way too big.\n"); return -EINVAL; } if (crc != crc32_le(0, ptr, len)) { diff --git a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 245db934f..69a550871 100644 --- a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -696,8 +696,7 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len) memcpy(ttusb->muxpack + ttusb->muxpack_ptr, data, avail); ttusb->muxpack_ptr += avail; - if (ttusb->muxpack_ptr > 264) - BUG(); + BUG_ON(ttusb->muxpack_ptr > 264); data += avail; len -= avail; /* determine length */ diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index f6889f771..9750ee1bb 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -26,6 +26,7 @@ config VIDEO_BT848 select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM + select VIDEO_MSP3400 ---help--- Support for BT848 based frame grabber/overlay boards. This includes the Miro, Hauppauge and STB boards. Please read the material in @@ -142,15 +143,7 @@ config VIDEO_CPIA_USB otherwise say N. This will not work with the Creative Webcam III. It is also available as a module (cpia_usb). -config VIDEO_CPIA2 - tristate "CPiA2 Video For Linux" - depends on VIDEO_DEV - ---help--- - This is the video4linux driver for cameras based on Vision's CPiA2 - (Colour Processor Interface ASIC), such as the Digital Blue QX5 - Microscope. If you have one of these cameras, say Y here - - This driver is also available as a module (cpia2). +source "drivers/media/video/cpia2/Kconfig" config VIDEO_SAA5246A tristate "SAA5246A, SAA5281 Teletext processor" @@ -324,6 +317,8 @@ source "drivers/media/video/cx88/Kconfig" source "drivers/media/video/em28xx/Kconfig" +source "drivers/media/video/pvrusb2/Kconfig" + config VIDEO_OVCAMCHIP tristate "OmniVision Camera Chip support" depends on VIDEO_DEV && I2C @@ -352,15 +347,28 @@ config VIDEO_M32R_AR_M64278 config VIDEO_AUDIO_DECODER tristate "Add support for additional audio chipsets" depends on VIDEO_DEV && I2C && EXPERIMENTAL + select VIDEO_MSP3400 + ---help--- + Say Y here to compile drivers for WM8775, CS53L32A and + MSP34xx audio decoders. + +config VIDEO_MSP3400 + tristate "Micronas MSP34xx audio decoders" + depends on VIDEO_DEV && I2C ---help--- - Say Y here to compile drivers for WM8775 and CS53L32A audio - decoders. + Support for the Micronas MSP34xx series of audio decoders. + + To compile this driver as a module, choose M here: the + module will be called msp3400 config VIDEO_DECODER tristate "Add support for additional video chipsets" depends on VIDEO_DEV && I2C && EXPERIMENTAL + select VIDEO_CX25840 ---help--- Say Y here to compile drivers for SAA7115, SAA7127 and CX25840 video decoders. +source "drivers/media/video/cx25840/Kconfig" + endmenu diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile index 2ad2ddd97..3b8b6d627 100644 --- a/linux/drivers/media/video/Makefile +++ b/linux/drivers/media/video/Makefile @@ -15,7 +15,7 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o -obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ +obj-$(CONFIG_VIDEO_BT848) += bttv.o tvaudio.o \ tda7432.o tda9875.o ir-kbd-i2c.o obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o @@ -45,10 +45,12 @@ obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_EM28XX) += saa7115.o tvp5150.o +obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ +obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ -obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o +obj-$(CONFIG_VIDEO_MXB) += saa7111.o tda9840.o tea6415c.o tea6420.o mxb.o obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o @@ -62,6 +64,7 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o -obj-$(CONFIG_VIDEO_DECODER) += saa7115.o cx25840/ saa7127.o +obj-$(CONFIG_VIDEO_DECODER) += saa7115.o saa7127.o +obj-$(CONFIG_VIDEO_CX25840) += cx25840/ EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core diff --git a/linux/drivers/media/video/bttv-cards.c b/linux/drivers/media/video/bttv-cards.c index b46f1118b..47131de0d 100644 --- a/linux/drivers/media/video/bttv-cards.c +++ b/linux/drivers/media/video/bttv-cards.c @@ -161,6 +161,8 @@ MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a li MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)"); MODULE_PARM_DESC(tuner,"specify installed tuner type"); MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)"); +MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" + " [some VIA/SIS chipsets are known to have problem with overlay]"); /* ----------------------------------------------------------------------- */ /* list of card IDs for bt878+ cards */ @@ -5044,12 +5046,14 @@ void __devinit bttv_check_chipset(void) if (vsfx) printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n"); if (pcipci_fail) { - printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n"); + printk(KERN_INFO "bttv: bttv and your chipset may not work " + "together.\n"); if (!no_overlay) { - printk(KERN_WARNING "bttv: overlay will be disabled.\n"); + printk(KERN_INFO "bttv: overlay will be disabled.\n"); no_overlay = 1; } else { - printk(KERN_WARNING "bttv: overlay forced. Use this option at your own risk.\n"); + printk(KERN_INFO "bttv: overlay forced. Use this " + "option at your own risk.\n"); } } if (UNSET != latency) diff --git a/linux/drivers/media/video/bttv-risc.c b/linux/drivers/media/video/bttv-risc.c index 4efe74dd8..148e86a79 100644 --- a/linux/drivers/media/video/bttv-risc.c +++ b/linux/drivers/media/video/bttv-risc.c @@ -277,6 +277,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, if (line > maxy) btcx_calc_skips(line, ov->w.width, &maxy, skips, &nskips, ov->clips, ov->nclips); + else + nskips = 0; /* write out risc code */ for (start = 0, skip = 0; start < ov->w.width; start = end) { @@ -514,8 +516,7 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf) { - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(btv->c.pci, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); diff --git a/linux/drivers/media/video/compat_ioctl32.c b/linux/drivers/media/video/compat_ioctl32.c index 9e9e9304b..8323dcf30 100644 --- a/linux/drivers/media/video/compat_ioctl32.c +++ b/linux/drivers/media/video/compat_ioctl32.c @@ -169,29 +169,32 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (kp->clipcount > 2048) return -EINVAL; if (kp->clipcount) { - struct v4l2_clip32 *uclips = compat_ptr(up->clips); - struct v4l2_clip *kclips; + struct v4l2_clip32 __user *uclips; + struct v4l2_clip __user *kclips; int n = kp->clipcount; + compat_caddr_t p; + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); kp->clips = kclips; while (--n >= 0) { - if (!access_ok(VERIFY_READ, &uclips->c, sizeof(uclips->c)) || - copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c))) + if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) + return -EFAULT; + if (put_user(n ? kclips + 1 : NULL, &kclips->next)) return -EFAULT; - kclips->next = n ? kclips + 1 : 0; uclips += 1; kclips += 1; } } else - kp->clips = 0; + kp->clips = NULL; return 0; } static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_window32)) || - copy_to_user(&up->w, &kp->w, sizeof(up->w)) || + if (copy_to_user(&up->w, &kp->w, sizeof(up->w)) || put_user(kp->field, &up->field) || put_user(kp->chromakey, &up->chromakey) || put_user(kp->clipcount, &up->clipcount)) @@ -201,33 +204,29 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_pix_format)) || - copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; + if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) + return -EFAULT; return 0; } static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_pix_format)) || - copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; + if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) + return -EFAULT; return 0; } static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_vbi_format)) || - copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; + if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) + return -EFAULT; return 0; } static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_vbi_format)) || - copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; + if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) + return -EFAULT; return 0; } @@ -281,18 +280,16 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user static inline int get_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard)) || - copy_from_user(kp, up, sizeof(struct v4l2_standard))) - return -EFAULT; + if (copy_from_user(kp, up, sizeof(struct v4l2_standard))) + return -EFAULT; return 0; } static inline int put_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard)) || - copy_to_user(up, kp, sizeof(struct v4l2_standard))) - return -EFAULT; + if (copy_to_user(up, kp, sizeof(struct v4l2_standard))) + return -EFAULT; return 0; } @@ -330,18 +327,16 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 static inline int get_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_tuner)) || - copy_from_user(kp, up, sizeof(struct v4l2_tuner))) - return -EFAULT; + if (copy_from_user(kp, up, sizeof(struct v4l2_tuner))) + return -EFAULT; return 0; } static inline int put_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_tuner)) || - copy_to_user(up, kp, sizeof(struct v4l2_tuner))) - return -EFAULT; + if (copy_to_user(up, kp, sizeof(struct v4l2_tuner))) + return -EFAULT; return 0; } @@ -382,11 +377,13 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user break; case V4L2_MEMORY_USERPTR: { - unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr); + compat_long_t tmp; - if(get_user(kp->length, &up->length) || - get_user(kp->m.userptr, &tmp)) - return -EFAULT; + if (get_user(kp->length, &up->length) || + get_user(tmp, &up->m.userptr)) + return -EFAULT; + + kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; case V4L2_MEMORY_OVERLAY: @@ -470,33 +467,29 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_input) - 4) || - copy_from_user(kp, up, sizeof(struct v4l2_input) - 4)) - return -EFAULT; + if (copy_from_user(kp, up, sizeof(struct v4l2_input) - 4)) + return -EFAULT; return 0; } static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_input) - 4) || - copy_to_user(up, kp, sizeof(struct v4l2_input) - 4)) - return -EFAULT; + if (copy_to_user(up, kp, sizeof(struct v4l2_input) - 4)) + return -EFAULT; return 0; } static inline int get_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_input)) || - copy_from_user(kp, up, sizeof(struct v4l2_input))) - return -EFAULT; + if (copy_from_user(kp, up, sizeof(struct v4l2_input))) + return -EFAULT; return 0; } static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_input)) || - copy_to_user(up, kp, sizeof(struct v4l2_input))) - return -EFAULT; + if (copy_to_user(up, kp, sizeof(struct v4l2_input))) + return -EFAULT; return 0; } diff --git a/linux/drivers/media/video/cpia2/Kconfig b/linux/drivers/media/video/cpia2/Kconfig new file mode 100644 index 000000000..1c09ef981 --- /dev/null +++ b/linux/drivers/media/video/cpia2/Kconfig @@ -0,0 +1,9 @@ +config VIDEO_CPIA2 + tristate "CPiA2 Video For Linux" + depends on VIDEO_DEV + ---help--- + This is the video4linux driver for cameras based on Vision's CPiA2 + (Colour Processor Interface ASIC), such as the Digital Blue QX5 + Microscope. If you have one of these cameras, say Y here + + This driver is also available as a module (cpia2). diff --git a/linux/drivers/media/video/cpia2/cpia2_v4l.c b/linux/drivers/media/video/cpia2/cpia2_v4l.c index c38681283..2ab1582fd 100644 --- a/linux/drivers/media/video/cpia2/cpia2_v4l.c +++ b/linux/drivers/media/video/cpia2/cpia2_v4l.c @@ -1629,7 +1629,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file, } switch (ioctl_nr) { - case VIDIOCGCAP: /* query capabilites */ + case VIDIOCGCAP: /* query capabilities */ retval = ioctl_cap_query(arg, cam); break; @@ -2054,7 +2054,7 @@ static void __init check_parameters(void) * cpia2_init/module_init * *****************************************************************************/ -int __init cpia2_init(void) +static int __init cpia2_init(void) { LOG("%s v%d.%d.%d\n", ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); @@ -2069,37 +2069,12 @@ int __init cpia2_init(void) * cpia2_exit/module_exit * *****************************************************************************/ -void __exit cpia2_exit(void) +static void __exit cpia2_exit(void) { cpia2_usb_cleanup(); schedule_timeout(2 * HZ); } - -int __init cpia2_setup(char *str) -{ - while(str) { - if(!strncmp(str, "buffer_size:", 12)) { - buffer_size = simple_strtoul(str + 13, &str, 10); - } else if(!strncmp(str, "num_buffers:", 12)) { - num_buffers = simple_strtoul(str + 13, &str, 10); - } else if(!strncmp(str, "alternate:", 10)) { - alternate = simple_strtoul(str + 11, &str, 10); - } else if(!strncmp(str, "video_nr:", 9)) { - video_nr = simple_strtoul(str + 10, &str, 10); - } else if(!strncmp(str, "flicker_freq:",13)) { - flicker_freq = simple_strtoul(str + 14, &str, 10); - } else if(!strncmp(str, "flicker_mode:",13)) { - flicker_mode = simple_strtoul(str + 14, &str, 10); - } else { - ++str; - } - } - return 1; -} - -__setup("cpia2=", cpia2_setup); - module_init(cpia2_init); module_exit(cpia2_exit); diff --git a/linux/drivers/media/video/cx25840/Kconfig b/linux/drivers/media/video/cx25840/Kconfig new file mode 100644 index 000000000..854264e42 --- /dev/null +++ b/linux/drivers/media/video/cx25840/Kconfig @@ -0,0 +1,9 @@ +config VIDEO_CX25840 + tristate "Conexant CX2584x audio/video decoders" + depends on VIDEO_DEV && I2C && EXPERIMENTAL + select FW_LOADER + ---help--- + Support for the Conexant CX2584x audio/video decoders. + + To compile this driver as a module, choose M here: the + module will be called cx25840 diff --git a/linux/drivers/media/video/cx25840/Makefile b/linux/drivers/media/video/cx25840/Makefile index 543ebacdc..32a896c23 100644 --- a/linux/drivers/media/video/cx25840/Makefile +++ b/linux/drivers/media/video/cx25840/Makefile @@ -1,6 +1,6 @@ cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ cx25840-vbi.o -obj-$(CONFIG_VIDEO_DECODER) += cx25840.o +obj-$(CONFIG_VIDEO_CX25840) += cx25840.o EXTRA_CFLAGS += -I$(src)/.. diff --git a/linux/drivers/media/video/cx88/Kconfig b/linux/drivers/media/video/cx88/Kconfig index b52a243c3..e140996e6 100644 --- a/linux/drivers/media/video/cx88/Kconfig +++ b/linux/drivers/media/video/cx88/Kconfig @@ -15,20 +15,6 @@ config VIDEO_CX88 To compile this driver as a module, choose M here: the module will be called cx8800 -config VIDEO_CX88_DVB - tristate "DVB/ATSC Support for cx2388x based TV cards" - depends on VIDEO_CX88 && DVB_CORE - select VIDEO_BUF_DVB - ---help--- - This adds support for DVB/ATSC cards based on the - Connexant 2388x chip. - - To compile this driver as a module, choose M here: the - module will be called cx88-dvb. - - You must also select one or more DVB/ATSC demodulators. - If you are unsure which you need, choose all of them. - config VIDEO_CX88_ALSA tristate "ALSA DMA audio support" depends on VIDEO_CX88 && SND && EXPERIMENTAL @@ -44,6 +30,20 @@ config VIDEO_CX88_ALSA To compile this driver as a module, choose M here: the module will be called cx88-alsa. +config VIDEO_CX88_DVB + tristate "DVB/ATSC Support for cx2388x based TV cards" + depends on VIDEO_CX88 && DVB_CORE + select VIDEO_BUF_DVB + ---help--- + This adds support for DVB/ATSC cards based on the + Connexant 2388x chip. + + To compile this driver as a module, choose M here: the + module will be called cx88-dvb. + + You must also select one or more DVB/ATSC demodulators. + If you are unsure which you need, choose all of them. + config VIDEO_CX88_DVB_ALL_FRONTENDS bool "Build all supported frontends for cx2388x based TV cards" default y diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c index e5b9007c2..e6cc40e04 100644 --- a/linux/drivers/media/video/cx88/cx88-alsa.c +++ b/linux/drivers/media/video/cx88/cx88-alsa.c @@ -686,6 +686,11 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci, chip = (snd_cx88_card_t *) card->private_data; core = cx88_core_get(pci); + if (NULL == core) { + err = -EINVAL; + kfree (chip); + return err; + } if (!pci_dma_supported(pci,0xffffffff)) { dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); @@ -702,11 +707,6 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci, spin_lock_init(&chip->reg_lock); cx88_reset(core); - if (NULL == core) { - err = -EINVAL; - kfree (chip); - return err; - } chip->core = core; /* get irq */ diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index c9c76003e..73b7ed14f 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -186,17 +186,18 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio1 = 0x309f, + .gpio1 = 0xe09f, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio1 = 0x305f, + .gpio1 = 0xe05f, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, - .gpio1 = 0x305f, + .gpio1 = 0xe05f, }}, .radio = { + .gpio1 = 0xe0df, .type = CX88_RADIO, }, }, @@ -324,19 +325,19 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0xff00, + .gpio0 = 0xbff0, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio0 = 0xff03, + .gpio0 = 0xbff3, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, - .gpio0 = 0xff03, + .gpio0 = 0xbff3, }}, .radio = { .type = CX88_RADIO, - .gpio0 = 0xff00, + .gpio0 = 0xbff0, }, }, [CX88_BOARD_ASUS_PVR_416] = { diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c index 24acfa2bd..e8bf7cf7c 100644 --- a/linux/drivers/media/video/cx88/cx88-core.c +++ b/linux/drivers/media/video/cx88/cx88-core.c @@ -232,8 +232,7 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf) { - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(pci, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c index 94b9ab35f..11d2e625a 100644 --- a/linux/drivers/media/video/cx88/cx88-input.c +++ b/linux/drivers/media/video/cx88/cx88-input.c @@ -188,6 +188,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keydown = 0x02; ir->polling = 5; /* ms */ break; + case CX88_BOARD_PROLINK_PLAYTVPVR: case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO: ir_codes = ir_codes_pixelview; ir->gpio_addr = MO_GP1_IO; diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c index a40d1bcd0..7d811004d 100644 --- a/linux/drivers/media/video/cx88/cx88-mpeg.c +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c @@ -162,10 +162,43 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, struct cx88_buffer *buf; struct list_head *item; - dprintk( 0, "cx8802_restart_queue\n" ); + dprintk( 1, "cx8802_restart_queue\n" ); if (list_empty(&q->active)) { - dprintk( 0, "cx8802_restart_queue: queue is empty\n" ); + struct cx88_buffer *prev; + prev = NULL; + + dprintk(1, "cx8802_restart_queue: queue is empty\n" ); + + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + cx8802_start_dma(dev, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(1,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(1,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); + } else { + return 0; + } + prev = buf; + } return 0; } diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c index edd32f7c1..4484744bc 100644 --- a/linux/drivers/media/video/cx88/cx88-video.c +++ b/linux/drivers/media/video/cx88/cx88-video.c @@ -253,7 +253,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .minimum = 0x00, .maximum = 0xff, .step = 1, - .default_value = 0, + .default_value = 0x7f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 128, @@ -281,7 +281,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .minimum = 0, .maximum = 0xff, .step = 1, - .default_value = 0, + .default_value = 0x7f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 128, @@ -326,7 +326,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .minimum = 0, .maximum = 0x3f, .step = 1, - .default_value = 0x1f, + .default_value = 0x3f, .type = V4L2_CTRL_TYPE_INTEGER, }, .reg = AUD_VOL_CTL, @@ -392,8 +392,7 @@ static void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits) { struct cx88_core *core = dev->core; - if ((fh->resources & bits) != bits) - BUG(); + BUG_ON((fh->resources & bits) != bits); mutex_lock(&core->lock); fh->resources &= ~bits; @@ -1160,7 +1159,8 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl) value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: - ctl->value = (value & 0x40) ? (value & 0x3f) : (0x40 - (value & 0x3f)); + ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) + : (0x7f - (value & 0x7f)); break; case V4L2_CID_AUDIO_VOLUME: ctl->value = 0x3f - (value & 0x3f); @@ -1205,7 +1205,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl) mask=c->mask; switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: - value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value; + value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); break; case V4L2_CID_AUDIO_VOLUME: value = 0x3f - (ctl->value & 0x3f); @@ -1246,8 +1246,7 @@ static void init_controls(struct cx88_core *core) for (i = 0; i < CX8800_CTLS; i++) { ctrl.id=cx8800_ctls[i].v.id; - ctrl.value=cx8800_ctls[i].v.default_value - +cx8800_ctls[i].off; + ctrl.value=cx8800_ctls[i].v.default_value; set_control(core, &ctrl); } } diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 27a8bfdd6..a03be58aa 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -69,7 +69,7 @@ /* need "shadow" registers for some write-only ones ... */ #define SHADOW_AUD_VOL_CTL 1 #define SHADOW_AUD_BAL_CTL 2 -#define SHADOW_MAX 2 +#define SHADOW_MAX 3 /* FM Radio deemphasis type */ enum cx88_deemph_type { diff --git a/linux/drivers/media/video/dpc7146.c b/linux/drivers/media/video/dpc7146.c new file mode 100644 index 000000000..5cce40af6 --- /dev/null +++ b/linux/drivers/media/video/dpc7146.c @@ -0,0 +1,402 @@ +/* + dpc7146.c - v4l2 driver for the dpc7146 demonstration board + + Copyright (C) 2000-2003 Michael Hunold <michael@mihu.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEBUG_VARIABLE debug + +#include "compat.h" +#include <media/saa7146_vv.h> +#include <linux/video_decoder.h> /* for saa7111a */ + +#define I2C_SAA7111A 0x24 + +/* All unused bytes are reserverd. */ +#define SAA711X_CHIP_VERSION 0x00 +#define SAA711X_ANALOG_INPUT_CONTROL_1 0x02 +#define SAA711X_ANALOG_INPUT_CONTROL_2 0x03 +#define SAA711X_ANALOG_INPUT_CONTROL_3 0x04 +#define SAA711X_ANALOG_INPUT_CONTROL_4 0x05 +#define SAA711X_HORIZONTAL_SYNC_START 0x06 +#define SAA711X_HORIZONTAL_SYNC_STOP 0x07 +#define SAA711X_SYNC_CONTROL 0x08 +#define SAA711X_LUMINANCE_CONTROL 0x09 +#define SAA711X_LUMINANCE_BRIGHTNESS 0x0A +#define SAA711X_LUMINANCE_CONTRAST 0x0B +#define SAA711X_CHROMA_SATURATION 0x0C +#define SAA711X_CHROMA_HUE_CONTROL 0x0D +#define SAA711X_CHROMA_CONTROL 0x0E +#define SAA711X_FORMAT_DELAY_CONTROL 0x10 +#define SAA711X_OUTPUT_CONTROL_1 0x11 +#define SAA711X_OUTPUT_CONTROL_2 0x12 +#define SAA711X_OUTPUT_CONTROL_3 0x13 +#define SAA711X_V_GATE_1_START 0x15 +#define SAA711X_V_GATE_1_STOP 0x16 +#define SAA711X_V_GATE_1_MSB 0x17 +#define SAA711X_TEXT_SLICER_STATUS 0x1A +#define SAA711X_DECODED_BYTES_OF_TS_1 0x1B +#define SAA711X_DECODED_BYTES_OF_TS_2 0x1C +#define SAA711X_STATUS_BYTE 0x1F + +#define DPC_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) + +static int debug = 0; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "debug verbosity"); + +static int dpc_num = 0; + +#define DPC_INPUTS 2 +static struct v4l2_input dpc_inputs[DPC_INPUTS] = { + { 0, "Port A", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 1, "Port B", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, +}; + +#define DPC_AUDIOS 0 + +static struct saa7146_extension_ioctls ioctls[] = { + { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_STD, SAA7146_AFTER }, + { 0, 0 } +}; + +struct dpc +{ + struct video_device *video_dev; + struct video_device *vbi_dev; + + struct i2c_adapter i2c_adapter; + struct i2c_client *saa7111a; + + int cur_input; /* current input */ +}; + +/* fixme: add vbi stuff here */ +static int dpc_probe(struct saa7146_dev* dev) +{ + struct dpc* dpc = NULL; + struct i2c_client *client; + struct list_head *item; + + dpc = (struct dpc*)kmalloc(sizeof(struct dpc), GFP_KERNEL); + if( NULL == dpc ) { + printk("dpc_v4l2.o: dpc_probe: not enough kernel memory.\n"); + return -ENOMEM; + } + memset(dpc, 0x0, sizeof(struct dpc)); + + /* FIXME: enable i2c-port pins, video-port-pins + video port pins should be enabled here ?! */ + saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); + + dpc->i2c_adapter = (struct i2c_adapter) { + .class = I2C_CLASS_TV_ANALOG, + .name = "dpc7146", + }; + saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); + if(i2c_add_adapter(&dpc->i2c_adapter) < 0) { + DEB_S(("cannot register i2c-device. skipping.\n")); + kfree(dpc); + return -EFAULT; + } + + /* loop through all i2c-devices on the bus and look who is there */ + list_for_each(item,&dpc->i2c_adapter.clients) { + client = list_entry(item, struct i2c_client, list); + if( I2C_SAA7111A == client->addr ) + dpc->saa7111a = client; + } + + /* check if all devices are present */ + if( 0 == dpc->saa7111a ) { + DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n")); + i2c_del_adapter(&dpc->i2c_adapter); + kfree(dpc); + return -ENODEV; + } + + /* all devices are present, probe was successful */ + DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n")); + + /* we store the pointer in our private data field */ + dev->ext_priv = dpc; + + return 0; +} + +/* bring hardware to a sane state. this has to be done, just in case someone + wants to capture from this device before it has been properly initialized. + the capture engine would badly fail, because no valid signal arrives on the + saa7146, thus leading to timeouts and stuff. */ +static int dpc_init_done(struct saa7146_dev* dev) +{ + struct dpc* dpc = (struct dpc*)dev->ext_priv; + + DEB_D(("dpc_v4l2.o: dpc_init_done called.\n")); + + /* initialize the helper ics to useful values */ + i2c_smbus_write_byte_data(dpc->saa7111a, 0x00, 0x11); + + i2c_smbus_write_byte_data(dpc->saa7111a, 0x02, 0xc0); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x03, 0x30); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x04, 0x00); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x05, 0x00); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x06, 0xde); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x07, 0xad); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x08, 0xa8); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x09, 0x00); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x0a, 0x80); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x0b, 0x47); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x0c, 0x40); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x0d, 0x00); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x0e, 0x03); + + i2c_smbus_write_byte_data(dpc->saa7111a, 0x10, 0xd0); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x11, 0x1c); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x12, 0xc1); + i2c_smbus_write_byte_data(dpc->saa7111a, 0x13, 0x30); + + i2c_smbus_write_byte_data(dpc->saa7111a, 0x1f, 0x81); + + return 0; +} + +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) +{ + struct dpc* dpc = (struct dpc*)dev->ext_priv; + + DEB_D(("dpc_v4l2.o: dpc_attach called.\n")); + + /* checking for i2c-devices can be omitted here, because we + already did this in "dpc_vl42_probe" */ + + saa7146_vv_init(dev,&vv_data); + if( 0 != saa7146_register_device(&dpc->video_dev, dev, "dpc", VFL_TYPE_GRABBER)) { + ERR(("cannot register capture v4l2 device. skipping.\n")); + return -1; + } + + /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ + if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) { + if( 0 != saa7146_register_device(&dpc->vbi_dev, dev, "dpc", VFL_TYPE_VBI)) { + ERR(("cannot register vbi v4l2 device. skipping.\n")); + } + } + + i2c_use_client(dpc->saa7111a); + + printk("dpc: found 'dpc7146 demonstration board'-%d.\n",dpc_num); + dpc_num++; + + /* the rest */ + dpc->cur_input = 0; + dpc_init_done(dev); + + return 0; +} + +static int dpc_detach(struct saa7146_dev* dev) +{ + struct dpc* dpc = (struct dpc*)dev->ext_priv; + + DEB_EE(("dev:%p\n",dev)); + + i2c_release_client(dpc->saa7111a); + + saa7146_unregister_device(&dpc->video_dev,dev); + if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) { + saa7146_unregister_device(&dpc->vbi_dev,dev); + } + saa7146_vv_release(dev); + + dpc_num--; + + i2c_del_adapter(&dpc->i2c_adapter); + kfree(dpc); + return 0; +} + +#ifdef axa +int dpc_vbi_bypass(struct saa7146_dev* dev) +{ + struct dpc* dpc = (struct dpc*)dev->ext_priv; + + int i = 1; + + /* switch bypass in saa7111a */ + if ( 0 != dpc->saa7111a->driver->command(dpc->saa7111a,SAA711X_VBI_BYPASS, &i)) { + printk("dpc_v4l2.o: VBI_BYPASS: could not address saa7111a.\n"); + return -1; + } + + return 0; +} +#endif + +static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +{ + struct saa7146_dev *dev = fh->dev; + struct dpc* dpc = (struct dpc*)dev->ext_priv; +/* + struct saa7146_vv *vv = dev->vv_data; +*/ + switch(cmd) + { + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index)); + + if( i->index < 0 || i->index >= DPC_INPUTS) { + return -EINVAL; + } + + memcpy(i, &dpc_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("dpc_v4l2.o: v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index)); + return 0; + } + case VIDIOC_G_INPUT: + { + int *input = (int *)arg; + *input = dpc->cur_input; + + DEB_D(("dpc_v4l2.o: VIDIOC_G_INPUT: %d\n",*input)); + return 0; + } + case VIDIOC_S_INPUT: + { + int input = *(int *)arg; + + if (input < 0 || input >= DPC_INPUTS) { + return -EINVAL; + } + + dpc->cur_input = input; + + /* fixme: switch input here, switch audio, too! */ +// saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync); + printk("dpc_v4l2.o: VIDIOC_S_INPUT: fixme switch input.\n"); + + return 0; + } + default: +/* + DEB_D(("dpc_v4l2.o: v4l2_ioctl does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} + +static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) +{ + return 0; +} + +static struct saa7146_standard standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL, + .v_offset = 0x17, .v_field = 288, + .h_offset = 0x14, .h_pixels = 680, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x16, .v_field = 240, + .h_offset = 0x06, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 0x14, .v_field = 288, + .h_offset = 0x14, .h_pixels = 720, + .v_max_out = 576, .h_max_out = 768, + } +}; + +static struct saa7146_extension extension; + +static struct saa7146_pci_extension_data dpc = { + .ext_priv = "Multimedia eXtension Board", + .ext = &extension, +}; + +static struct pci_device_id pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x0000, + .subdevice = 0x0000, + .driver_data = (unsigned long)&dpc, + }, { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_ext_vv vv_data = { + .inputs = DPC_INPUTS, + .capabilities = V4L2_CAP_VBI_CAPTURE, + .stds = &standard[0], + .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), + .std_callback = &std_callback, + .ioctls = &ioctls[0], + .ioctl = dpc_ioctl, +}; + +static struct saa7146_extension extension = { + .name = "dpc7146 demonstration board", + .flags = SAA7146_USE_I2C_IRQ, + + .pci_tbl = &pci_tbl[0], + .module = THIS_MODULE, + + .probe = dpc_probe, + .attach = dpc_attach, + .detach = dpc_detach, + + .irq_mask = 0, + .irq_func = NULL, +}; + +static int __init dpc_init_module(void) +{ + if( 0 != saa7146_register_extension(&extension)) { + DEB_S(("failed to register extension.\n")); + return -ENODEV; + } + + return 0; +} + +static void __exit dpc_cleanup_module(void) +{ + saa7146_unregister_extension(&extension); +} + +module_init(dpc_init_module); +module_exit(dpc_cleanup_module); + +MODULE_DESCRIPTION("video4linux-2 driver for the 'dpc7146 demonstration board'"); +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index bbbff8fa4..64d395472 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -1870,7 +1870,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, model=id->driver_info; - if (nr > EM28XX_MAXBOARDS) { + if (nr >= EM28XX_MAXBOARDS) { printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); em28xx_devused&=~(1<<nr); return -ENOMEM; diff --git a/linux/drivers/media/video/hexium_gemini.c b/linux/drivers/media/video/hexium_gemini.c new file mode 100644 index 000000000..24ae47cff --- /dev/null +++ b/linux/drivers/media/video/hexium_gemini.c @@ -0,0 +1,557 @@ +/* + hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards + + Visit http://www.mihu.de/linux/saa7146/ and follow the link + to "hexium" for further details about this card. + + Copyright (C) 2003 Michael Hunold <michael@mihu.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEBUG_VARIABLE debug + +#include "compat.h" +#include <media/saa7146_vv.h> + +static int debug = 0; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "debug verbosity"); + +/* global variables */ +static int hexium_num = 0; + +#define HEXIUM_GEMINI 4 +#define HEXIUM_GEMINI_DUAL 5 + +#define HEXIUM_INPUTS 9 +static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = { + { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, +}; + +#define HEXIUM_AUDIOS 0 + +struct hexium_data +{ + s8 adr; + u8 byte; +}; + +static struct saa7146_extension_ioctls ioctls[] = { + { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_QUERYCTRL, SAA7146_BEFORE }, + { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_STD, SAA7146_AFTER }, + { VIDIOC_G_CTRL, SAA7146_BEFORE }, + { VIDIOC_S_CTRL, SAA7146_BEFORE }, + { 0, 0 } +}; + +#define HEXIUM_CONTROLS 1 +static struct v4l2_queryctrl hexium_controls[] = { + { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 }, +}; + +#define HEXIUM_GEMINI_V_1_0 1 +#define HEXIUM_GEMINI_DUAL_V_1_0 2 + +struct hexium +{ + int type; + + struct video_device *video_dev; + struct i2c_adapter i2c_adapter; + + int cur_input; /* current input */ + v4l2_std_id cur_std; /* current standard */ + int cur_bw; /* current black/white status */ +}; + +/* Samsung KS0127B decoder default registers */ +static u8 hexium_ks0127b[0x100]={ +/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10, +/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06, +/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00, +/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22, +/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00, +/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80, +/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00, +/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static struct hexium_data hexium_pal[] = { + { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_pal_bw[] = { + { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_ntsc[] = { + { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_ntsc_bw[] = { + { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_secam[] = { + { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_input_select[] = { + { 0x02, 0x60 }, + { 0x02, 0x64 }, + { 0x02, 0x61 }, + { 0x02, 0x65 }, + { 0x02, 0x62 }, + { 0x02, 0x66 }, + { 0x02, 0x68 }, + { 0x02, 0x69 }, + { 0x02, 0x6A }, +}; + +/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which + are currently *not* supported*/ +static struct saa7146_standard hexium_standards[] = { + { + .name = "PAL", .id = V4L2_STD_PAL, + .v_offset = 28, .v_field = 288, + .h_offset = 1, .h_pixels = 680, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 28, .v_field = 240, + .h_offset = 1, .h_pixels = 640, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 28, .v_field = 288, + .h_offset = 1, .h_pixels = 720, + .v_max_out = 576, .h_max_out = 768, + } +}; + +/* bring hardware to a sane state. this has to be done, just in case someone + wants to capture from this device before it has been properly initialized. + the capture engine would badly fail, because no valid signal arrives on the + saa7146, thus leading to timeouts and stuff. */ +static int hexium_init_done(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + union i2c_smbus_data data; + int i = 0; + + DEB_D(("hexium_init_done called.\n")); + + /* initialize the helper ics to useful values */ + for (i = 0; i < sizeof(hexium_ks0127b); i++) { + data.byte = hexium_ks0127b[i]; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { + printk("hexium_gemini: hexium_init_done() failed for address 0x%02x\n", i); + } + } + + return 0; +} + +static int hexium_set_input(struct hexium *hexium, int input) +{ + union i2c_smbus_data data; + + DEB_D((".\n")); + + data.byte = hexium_input_select[input].byte; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) { + return -1; + } + + return 0; +} + +static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) +{ + union i2c_smbus_data data; + int i = 0; + + DEB_D((".\n")); + + while (vdec[i].adr != -1) { + data.byte = vdec[i].byte; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) { + printk("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", i); + return -1; + } + i++; + } + return 0; +} + +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE((".\n")); + + hexium = (struct hexium *) kmalloc(sizeof(struct hexium), GFP_KERNEL); + if (NULL == hexium) { + printk("hexium_gemini: not enough kernel memory in hexium_attach().\n"); + return -ENOMEM; + } + memset(hexium, 0x0, sizeof(struct hexium)); + dev->ext_priv = hexium; + + /* enable i2c-port pins */ + saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); + + hexium->i2c_adapter = (struct i2c_adapter) { + .class = I2C_CLASS_TV_ANALOG, + .name = "hexium gemini", + }; + saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); + if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { + DEB_S(("cannot register i2c-device. skipping.\n")); + kfree(hexium); + return -EFAULT; + } + + /* set HWControl GPIO number 2 */ + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + + saa7146_write(dev, DD1_INIT, 0x07000700); + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* the rest */ + hexium->cur_input = 0; + hexium_init_done(dev); + + hexium_set_standard(hexium, hexium_pal); + hexium->cur_std = V4L2_STD_PAL; + + hexium_set_input(hexium, 0); + hexium->cur_input = 0; + + saa7146_vv_init(dev, &vv_data); + if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) { + printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n"); + return -1; + } + + printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num); + hexium_num++; + + return 0; +} + +static int hexium_detach(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE(("dev:%p\n", dev)); + + saa7146_unregister_device(&hexium->video_dev, dev); + saa7146_vv_release(dev); + + hexium_num--; + + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return 0; +} + +static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +{ + struct saa7146_dev *dev = fh->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; +/* + struct saa7146_vv *vv = dev->vv_data; +*/ + switch (cmd) { + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index < 0 || i->index >= HEXIUM_INPUTS) { + return -EINVAL; + } + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; + } + case VIDIOC_G_INPUT: + { + int *input = (int *) arg; + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; + } + case VIDIOC_S_INPUT: + { + int input = *(int *) arg; + + DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + + if (input < 0 || input >= HEXIUM_INPUTS) { + return -EINVAL; + } + + hexium->cur_input = input; + hexium_set_input(hexium, input); + + return 0; + } + /* the saa7146 provides some controls (brightness, contrast, saturation) + which gets registered *after* this function. because of this we have + to return with a value != 0 even if the function succeded.. */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == qc->id) { + *qc = hexium_controls[i]; + DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + return 0; + } + } + return -EAGAIN; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *vc = arg; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) { + break; + } + } + + if (i < 0) { + return -EAGAIN; + } + + switch (vc->id) { + case V4L2_CID_PRIVATE_BASE:{ + vc->value = hexium->cur_bw; + DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); + return 0; + } + } + return -EINVAL; + } + + case VIDIOC_S_CTRL: + { + struct v4l2_control *vc = arg; + int i = 0; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) { + break; + } + } + + if (i < 0) { + return -EAGAIN; + } + + switch (vc->id) { + case V4L2_CID_PRIVATE_BASE:{ + hexium->cur_bw = vc->value; + break; + } + } + + DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); + + if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { + hexium_set_standard(hexium, hexium_secam); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { + /* fixme: is there no bw secam mode? */ + return -EINVAL; + } + + return -EINVAL; + } + default: +/* + DEB_D(("hexium_ioctl() does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} + +static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + if (V4L2_STD_PAL == std->id) { + hexium_set_standard(hexium, hexium_pal); + hexium->cur_std = V4L2_STD_PAL; + return 0; + } else if (V4L2_STD_NTSC == std->id) { + hexium_set_standard(hexium, hexium_ntsc); + hexium->cur_std = V4L2_STD_NTSC; + return 0; + } else if (V4L2_STD_SECAM == std->id) { + hexium_set_standard(hexium, hexium_secam); + hexium->cur_std = V4L2_STD_SECAM; + return 0; + } + + return -1; +} + +static struct saa7146_extension hexium_extension; + +static struct saa7146_pci_extension_data hexium_gemini_4bnc = { + .ext_priv = "Hexium Gemini (4 BNC)", + .ext = &hexium_extension, +}; + +static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = { + .ext_priv = "Hexium Gemini Dual (4 BNC)", + .ext = &hexium_extension, +}; + +static struct pci_device_id pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x2401, + .driver_data = (unsigned long) &hexium_gemini_4bnc, + }, + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x2402, + .driver_data = (unsigned long) &hexium_gemini_dual_4bnc, + }, + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_ext_vv vv_data = { + .inputs = HEXIUM_INPUTS, + .capabilities = 0, + .stds = &hexium_standards[0], + .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), + .std_callback = &std_callback, + .ioctls = &ioctls[0], + .ioctl = hexium_ioctl, +}; + +static struct saa7146_extension hexium_extension = { + .name = "hexium gemini", + .flags = SAA7146_USE_I2C_IRQ, + + .pci_tbl = &pci_tbl[0], + .module = THIS_MODULE, + + .attach = hexium_attach, + .detach = hexium_detach, + + .irq_mask = 0, + .irq_func = NULL, +}; + +static int __init hexium_init_module(void) +{ + if (0 != saa7146_register_extension(&hexium_extension)) { + DEB_S(("failed to register extension.\n")); + return -ENODEV; + } + + return 0; +} + +static void __exit hexium_cleanup_module(void) +{ + saa7146_unregister_extension(&hexium_extension); +} + +module_init(hexium_init_module); +module_exit(hexium_cleanup_module); + +MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards"); +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/hexium_orion.c b/linux/drivers/media/video/hexium_orion.c new file mode 100644 index 000000000..776eeea1b --- /dev/null +++ b/linux/drivers/media/video/hexium_orion.c @@ -0,0 +1,523 @@ +/* + hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards + + Visit http://www.mihu.de/linux/saa7146/ and follow the link + to "hexium" for further details about this card. + + Copyright (C) 2003 Michael Hunold <michael@mihu.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEBUG_VARIABLE debug + +#include "compat.h" +#include <media/saa7146_vv.h> + +static int debug = 0; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "debug verbosity"); + +/* global variables */ +static int hexium_num = 0; + +#define HEXIUM_HV_PCI6_ORION 1 +#define HEXIUM_ORION_1SVHS_3BNC 2 +#define HEXIUM_ORION_4BNC 3 + +#define HEXIUM_INPUTS 9 +static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = { + { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, +}; + +#define HEXIUM_AUDIOS 0 + +struct hexium_data +{ + s8 adr; + u8 byte; +}; + +static struct saa7146_extension_ioctls ioctls[] = { + { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_STD, SAA7146_AFTER }, + { 0, 0 } +}; + +struct hexium +{ + int type; + struct video_device *video_dev; + struct i2c_adapter i2c_adapter; + + int cur_input; /* current input */ +}; + +/* Philips SAA7110 decoder default registers */ +static u8 hexium_saa7110[53]={ +/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00, +/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90, +/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA, +/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00, +/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F, +/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03, +/*30*/ 0x44,0x75,0x01,0x8C,0x03 +}; + +static struct { + struct hexium_data data[8]; +} hexium_input_select[] = { +{ + { /* cvbs 1 */ + { 0x06, 0x00 }, + { 0x20, 0xD9 }, + { 0x21, 0x17 }, // 0x16, + { 0x22, 0x40 }, + { 0x2C, 0x03 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, // ?? + { 0x21, 0x16 }, // 0x03, + } +}, { + { /* cvbs 2 */ + { 0x06, 0x00 }, + { 0x20, 0x78 }, + { 0x21, 0x07 }, // 0x03, + { 0x22, 0xD2 }, + { 0x2C, 0x83 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ? + { 0x21, 0x03 }, + } +}, { + { /* cvbs 3 */ + { 0x06, 0x00 }, + { 0x20, 0xBA }, + { 0x21, 0x07 }, // 0x05, + { 0x22, 0x91 }, + { 0x2C, 0x03 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ?? + { 0x21, 0x05 }, // 0x03, + } +}, { + { /* cvbs 4 */ + { 0x06, 0x00 }, + { 0x20, 0xD8 }, + { 0x21, 0x17 }, // 0x16, + { 0x22, 0x40 }, + { 0x2C, 0x03 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, // ?? + { 0x21, 0x16 }, // 0x03, + } +}, { + { /* cvbs 5 */ + { 0x06, 0x00 }, + { 0x20, 0xB8 }, + { 0x21, 0x07 }, // 0x05, + { 0x22, 0x91 }, + { 0x2C, 0x03 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ?? + { 0x21, 0x05 }, // 0x03, + } +}, { + { /* cvbs 6 */ + { 0x06, 0x00 }, + { 0x20, 0x7C }, + { 0x21, 0x07 }, // 0x03 + { 0x22, 0xD2 }, + { 0x2C, 0x83 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ?? + { 0x21, 0x03 }, + } +}, { + { /* y/c 1 */ + { 0x06, 0x80 }, + { 0x20, 0x59 }, + { 0x21, 0x17 }, + { 0x22, 0x42 }, + { 0x2C, 0xA3 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, + { 0x21, 0x12 }, + } +}, { + { /* y/c 2 */ + { 0x06, 0x80 }, + { 0x20, 0x9A }, + { 0x21, 0x17 }, + { 0x22, 0xB1 }, + { 0x2C, 0x13 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, + { 0x21, 0x14 }, + } +}, { + { /* y/c 3 */ + { 0x06, 0x80 }, + { 0x20, 0x3C }, + { 0x21, 0x27 }, + { 0x22, 0xC1 }, + { 0x2C, 0x23 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, + { 0x21, 0x21 }, + } +} +}; + +static struct saa7146_standard hexium_standards[] = { + { + .name = "PAL", .id = V4L2_STD_PAL, + .v_offset = 16, .v_field = 288, + .h_offset = 1, .h_pixels = 680, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 16, .v_field = 240, + .h_offset = 1, .h_pixels = 640, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 16, .v_field = 288, + .h_offset = 1, .h_pixels = 720, + .v_max_out = 576, .h_max_out = 768, + } +}; + +/* this is only called for old HV-PCI6/Orion cards + without eeprom */ +static int hexium_probe(struct saa7146_dev *dev) +{ + struct hexium *hexium = NULL; + union i2c_smbus_data data; + int err = 0; + + DEB_EE((".\n")); + + /* there are no hexium orion cards with revision 0 saa7146s */ + if (0 == dev->revision) { + return -EFAULT; + } + + hexium = (struct hexium *) kmalloc(sizeof(struct hexium), GFP_KERNEL); + if (NULL == hexium) { + printk("hexium_orion: hexium_probe: not enough kernel memory.\n"); + return -ENOMEM; + } + memset(hexium, 0x0, sizeof(struct hexium)); + + /* enable i2c-port pins */ + saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); + + saa7146_write(dev, DD1_INIT, 0x01000100); + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + hexium->i2c_adapter = (struct i2c_adapter) { + .class = I2C_CLASS_TV_ANALOG, + .name = "hexium orion", + }; + saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); + if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { + DEB_S(("cannot register i2c-device. skipping.\n")); + kfree(hexium); + return -EFAULT; + } + + /* set SAA7110 control GPIO 0 */ + saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI); + /* set HWControl GPIO number 2 */ + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + + mdelay(10); + + /* detect newer Hexium Orion cards by subsystem ids */ + if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) { + printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n"); + /* we store the pointer in our private data field */ + dev->ext_priv = hexium; + hexium->type = HEXIUM_ORION_1SVHS_3BNC; + return 0; + } + + if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) { + printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n"); + /* we store the pointer in our private data field */ + dev->ext_priv = hexium; + hexium->type = HEXIUM_ORION_4BNC; + return 0; + } + + /* check if this is an old hexium Orion card by looking at + a saa7110 at address 0x4e */ + if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) { + printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n"); + /* we store the pointer in our private data field */ + dev->ext_priv = hexium; + hexium->type = HEXIUM_HV_PCI6_ORION; + return 0; + } + + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return -EFAULT; +} + +/* bring hardware to a sane state. this has to be done, just in case someone + wants to capture from this device before it has been properly initialized. + the capture engine would badly fail, because no valid signal arrives on the + saa7146, thus leading to timeouts and stuff. */ +static int hexium_init_done(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + union i2c_smbus_data data; + int i = 0; + + DEB_D(("hexium_init_done called.\n")); + + /* initialize the helper ics to useful values */ + for (i = 0; i < sizeof(hexium_saa7110); i++) { + data.byte = hexium_saa7110[i]; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { + printk("hexium_orion: failed for address 0x%02x\n", i); + } + } + + return 0; +} + +static int hexium_set_input(struct hexium *hexium, int input) +{ + union i2c_smbus_data data; + int i = 0; + + DEB_D((".\n")); + + for (i = 0; i < 8; i++) { + int adr = hexium_input_select[input].data[i].adr; + data.byte = hexium_input_select[input].data[i].byte; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) { + return -1; + } + printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte); + } + + return 0; +} + +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE((".\n")); + + saa7146_vv_init(dev, &vv_data); + if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { + printk("hexium_orion: cannot register capture v4l2 device. skipping.\n"); + return -1; + } + + printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num); + hexium_num++; + + /* the rest */ + hexium->cur_input = 0; + hexium_init_done(dev); + + return 0; +} + +static int hexium_detach(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE(("dev:%p\n", dev)); + + saa7146_unregister_device(&hexium->video_dev, dev); + saa7146_vv_release(dev); + + hexium_num--; + + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return 0; +} + +static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +{ + struct saa7146_dev *dev = fh->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; +/* + struct saa7146_vv *vv = dev->vv_data; +*/ + switch (cmd) { + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index < 0 || i->index >= HEXIUM_INPUTS) { + return -EINVAL; + } + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; + } + case VIDIOC_G_INPUT: + { + int *input = (int *) arg; + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; + } + case VIDIOC_S_INPUT: + { + int input = *(int *) arg; + + if (input < 0 || input >= HEXIUM_INPUTS) { + return -EINVAL; + } + + hexium->cur_input = input; + hexium_set_input(hexium, input); + + return 0; + } + default: +/* + DEB_D(("hexium_ioctl() does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} + +static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) +{ + return 0; +} + +static struct saa7146_extension extension; + +static struct saa7146_pci_extension_data hexium_hv_pci6 = { + .ext_priv = "Hexium HV-PCI6 / Orion", + .ext = &extension, +}; + +static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = { + .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)", + .ext = &extension, +}; + +static struct saa7146_pci_extension_data hexium_orion_4bnc = { + .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)", + .ext = &extension, +}; + +static struct pci_device_id pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x0000, + .subdevice = 0x0000, + .driver_data = (unsigned long) &hexium_hv_pci6, + }, + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x0101, + .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc, + }, + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x2101, + .driver_data = (unsigned long) &hexium_orion_4bnc, + }, + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_ext_vv vv_data = { + .inputs = HEXIUM_INPUTS, + .capabilities = 0, + .stds = &hexium_standards[0], + .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), + .std_callback = &std_callback, + .ioctls = &ioctls[0], + .ioctl = hexium_ioctl, +}; + +static struct saa7146_extension extension = { + .name = "hexium HV-PCI6/Orion", + .flags = 0, // SAA7146_USE_I2C_IRQ, + + .pci_tbl = &pci_tbl[0], + .module = THIS_MODULE, + + .probe = hexium_probe, + .attach = hexium_attach, + .detach = hexium_detach, + + .irq_mask = 0, + .irq_func = NULL, +}; + +static int __init hexium_init_module(void) +{ + if (0 != saa7146_register_extension(&extension)) { + DEB_S(("failed to register extension.\n")); + return -ENODEV; + } + + return 0; +} + +static void __exit hexium_cleanup_module(void) +{ + saa7146_unregister_extension(&extension); +} + +module_init(hexium_init_module); +module_exit(hexium_cleanup_module); + +MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards"); +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/msp3400-kthreads.c b/linux/drivers/media/video/msp3400-kthreads.c index 387f76c9f..dd8dc256d 100644 --- a/linux/drivers/media/video/msp3400-kthreads.c +++ b/linux/drivers/media/video/msp3400-kthreads.c @@ -160,7 +160,7 @@ const char *msp_standard_std_name(int std) return "unknown"; } -void msp_set_source(struct i2c_client *client, u16 src) +static void msp_set_source(struct i2c_client *client, u16 src) { struct msp_state *state = i2c_get_clientdata(client); @@ -223,7 +223,7 @@ void msp3400c_set_mode(struct i2c_client *client, int mode) /* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP, nor do they support stereo BTSC. */ -void msp3400c_set_audmode(struct i2c_client *client) +static void msp3400c_set_audmode(struct i2c_client *client) { static char *strmode[] = { "mono", "stereo", "lang2", "lang1" }; struct msp_state *state = i2c_get_clientdata(client); @@ -989,7 +989,7 @@ static void msp34xxg_detect_stereo(struct i2c_client *client) status, is_stereo, is_bilingual, state->rxsubchans); } -void msp34xxg_set_audmode(struct i2c_client *client) +static void msp34xxg_set_audmode(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); int source; diff --git a/linux/drivers/media/video/msp3400.h b/linux/drivers/media/video/msp3400.h index 80e26e68f..5bb277609 100644 --- a/linux/drivers/media/video/msp3400.h +++ b/linux/drivers/media/video/msp3400.h @@ -109,7 +109,6 @@ int msp_sleep(struct msp_state *state, int timeout); /* msp3400-kthreads.c */ const char *msp_standard_std_name(int std); -void msp_set_source(struct i2c_client *client, u16 src); void msp_set_audmode(struct i2c_client *client); void msp_detect_stereo(struct i2c_client *client); int msp3400c_thread(void *data); diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c new file mode 100644 index 000000000..cedefda72 --- /dev/null +++ b/linux/drivers/media/video/mxb.c @@ -0,0 +1,1037 @@ +/* + mxb - v4l2 driver for the Multimedia eXtension Board + + Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de> + + Visit http://www.mihu.de/linux/saa7146/mxb/ + for further details about this card. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEBUG_VARIABLE debug + +#include "compat.h" +#include <media/saa7146_vv.h> +#include <media/tuner.h> +#include <media/v4l2-common.h> +#include <linux/video_decoder.h> + +#include "mxb.h" +#include "tea6415c.h" +#include "tea6420.h" +#include "tda9840.h" + +#define I2C_SAA7111 0x24 + +#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) + +/* global variable */ +static int mxb_num = 0; + +/* initial frequence the tuner will be tuned to. + in verden (lower saxony, germany) 4148 is a + channel called "phoenix" */ +static int freq = 4148; +module_param(freq, int, 0644); +MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup"); + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); + +#define MXB_INPUTS 4 +enum { TUNER, AUX1, AUX3, AUX3_YC }; + +static struct v4l2_input mxb_inputs[MXB_INPUTS] = { + { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, +}; + +/* this array holds the information, which port of the saa7146 each + input actually uses. the mxb uses port 0 for every input */ +static struct { + int hps_source; + int hps_sync; +} input_port_selection[MXB_INPUTS] = { + { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, + { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, + { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, + { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, +}; + +/* this array holds the information of the audio source (mxb_audios), + which has to be switched corresponding to the video source (mxb_channels) */ +static int video_audio_connect[MXB_INPUTS] = + { 0, 1, 3, 3 }; + +/* these are the necessary input-output-pins for bringing one audio source +(see above) to the CD-output */ +static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] = + { + {{1,1,0},{1,1,0}}, /* Tuner */ + {{5,1,0},{6,1,0}}, /* AUX 1 */ + {{4,1,0},{6,1,0}}, /* AUX 2 */ + {{3,1,0},{6,1,0}}, /* AUX 3 */ + {{1,1,0},{3,1,0}}, /* Radio */ + {{1,1,0},{2,1,0}}, /* CD-Rom */ + {{6,1,0},{6,1,0}} /* Mute */ + }; + +/* these are the necessary input-output-pins for bringing one audio source +(see above) to the line-output */ +static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] = + { + {{2,3,0},{1,2,0}}, + {{5,3,0},{6,2,0}}, + {{4,3,0},{6,2,0}}, + {{3,3,0},{6,2,0}}, + {{2,3,0},{3,2,0}}, + {{2,3,0},{2,2,0}}, + {{6,3,0},{6,2,0}} /* Mute */ + }; + +#define MAXCONTROLS 1 +static struct v4l2_queryctrl mxb_controls[] = { + { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 }, +}; + +static struct saa7146_extension_ioctls ioctls[] = { + { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_QUERYCTRL, SAA7146_BEFORE }, + { VIDIOC_G_CTRL, SAA7146_BEFORE }, + { VIDIOC_S_CTRL, SAA7146_BEFORE }, + { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE }, + { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, + { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE }, + { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE }, + { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, + { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, + { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */ + { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */ + { 0, 0 } +}; + +struct mxb +{ + struct video_device *video_dev; + struct video_device *vbi_dev; + + struct i2c_adapter i2c_adapter; + + struct i2c_client* saa7111a; + struct i2c_client* tda9840; + struct i2c_client* tea6415c; + struct i2c_client* tuner; + struct i2c_client* tea6420_1; + struct i2c_client* tea6420_2; + + int cur_mode; /* current audio mode (mono, stereo, ...) */ + int cur_input; /* current input */ + int cur_mute; /* current mute status */ + struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */ +}; + +static struct saa7146_extension extension; + +static int mxb_probe(struct saa7146_dev* dev) +{ + struct mxb* mxb = NULL; + struct i2c_client *client; + struct list_head *item; + int result; + + if ((result = request_module("saa7111")) < 0) { + printk("mxb: saa7111 i2c module not available.\n"); + return -ENODEV; + } + if ((result = request_module("tuner")) < 0) { + printk("mxb: tuner i2c module not available.\n"); + return -ENODEV; + } + if ((result = request_module("tea6420")) < 0) { + printk("mxb: tea6420 i2c module not available.\n"); + return -ENODEV; + } + if ((result = request_module("tea6415c")) < 0) { + printk("mxb: tea6415c i2c module not available.\n"); + return -ENODEV; + } + if ((result = request_module("tda9840")) < 0) { + printk("mxb: tda9840 i2c module not available.\n"); + return -ENODEV; + } + + mxb = (struct mxb*)kmalloc(sizeof(struct mxb), GFP_KERNEL); + if( NULL == mxb ) { + DEB_D(("not enough kernel memory.\n")); + return -ENOMEM; + } + memset(mxb, 0x0, sizeof(struct mxb)); + + mxb->i2c_adapter = (struct i2c_adapter) { + .class = I2C_CLASS_TV_ANALOG, + .name = "mxb", + }; + + saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); + if(i2c_add_adapter(&mxb->i2c_adapter) < 0) { + DEB_S(("cannot register i2c-device. skipping.\n")); + kfree(mxb); + return -EFAULT; + } + + /* loop through all i2c-devices on the bus and look who is there */ + list_for_each(item,&mxb->i2c_adapter.clients) { + client = list_entry(item, struct i2c_client, list); + if( I2C_TEA6420_1 == client->addr ) + mxb->tea6420_1 = client; + if( I2C_TEA6420_2 == client->addr ) + mxb->tea6420_2 = client; + if( I2C_TEA6415C_2 == client->addr ) + mxb->tea6415c = client; + if( I2C_TDA9840 == client->addr ) + mxb->tda9840 = client; + if( I2C_SAA7111 == client->addr ) + mxb->saa7111a = client; + if( 0x60 == client->addr ) + mxb->tuner = client; + } + + /* check if all devices are present */ + if( 0 == mxb->tea6420_1 || 0 == mxb->tea6420_2 || 0 == mxb->tea6415c + || 0 == mxb->tda9840 || 0 == mxb->saa7111a || 0 == mxb->tuner ) { + + printk("mxb: did not find all i2c devices. aborting\n"); + i2c_del_adapter(&mxb->i2c_adapter); + kfree(mxb); + return -ENODEV; + } + + /* all devices are present, probe was successful */ + + /* we store the pointer in our private data field */ + dev->ext_priv = mxb; + + return 0; +} + +/* some init data for the saa7740, the so-called 'sound arena module'. + there are no specs available, so we simply use some init values */ +static struct { + int length; + char data[9]; +} mxb_saa7740_init[] = { + { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } }, + { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } }, + { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } }, + { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } }, + { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } }, + { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } }, + { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } }, + { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } }, + { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } }, + { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } }, + { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } }, + { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } }, + { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } }, + { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } }, + { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } }, + { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } }, + { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } }, + { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } }, + { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } }, + { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } }, + { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } }, + { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } }, + { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } }, + { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } }, + { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } }, + { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } }, + { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } }, + { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } }, + { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } }, + { 3, { 0x48, 0x00, 0x01 } }, + { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } }, + { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } }, + { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } }, + { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } }, + { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } }, + { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } }, + { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } }, + { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } }, + { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } }, + { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } }, + { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } }, + { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } }, + { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } }, + { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } }, + { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } }, + { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } }, + { 3, { 0x80, 0xb3, 0x0a } }, + {-1, { 0} } +}; + +static const unsigned char mxb_saa7111_init[] = { + 0x00, 0x00, /* 00 - ID byte */ + 0x01, 0x00, /* 01 - reserved */ + + /*front end */ + 0x02, 0xd8, /* 02 - FUSE=x, GUDL=x, MODE=x */ + 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */ + 0x04, 0x00, /* 04 - GAI1=256 */ + 0x05, 0x00, /* 05 - GAI2=256 */ + + /* decoder */ + 0x06, 0xf0, /* 06 - HSB at xx(50Hz) / xx(60Hz) pixels after end of last line */ + 0x07, 0x30, /* 07 - HSS at xx(50Hz) / xx(60Hz) pixels after end of last line */ + 0x08, 0xa8, /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */ + 0x09, 0x02, /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */ + 0x0a, 0x80, /* 0a - BRIG=128 */ + 0x0b, 0x47, /* 0b - CONT=1.109 */ + 0x0c, 0x40, /* 0c - SATN=1.0 */ + 0x0d, 0x00, /* 0d - HUE=0 */ + 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */ + 0x0f, 0x00, /* 0f - reserved */ + 0x10, 0xd0, /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */ + 0x11, 0x8c, /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */ + 0x12, 0x80, /* 12 - xx output control 2 */ + 0x13, 0x30, /* 13 - xx output control 3 */ + 0x14, 0x00, /* 14 - reserved */ + 0x15, 0x15, /* 15 - VBI */ + 0x16, 0x04, /* 16 - VBI */ + 0x17, 0x00, /* 17 - VBI */ +}; + +/* bring hardware to a sane state. this has to be done, just in case someone + wants to capture from this device before it has been properly initialized. + the capture engine would badly fail, because no valid signal arrives on the + saa7146, thus leading to timeouts and stuff. */ +static int mxb_init_done(struct saa7146_dev* dev) +{ + struct mxb* mxb = (struct mxb*)dev->ext_priv; + struct video_decoder_init init; + struct i2c_msg msg; + struct tuner_setup tun_setup; + v4l2_std_id std = V4L2_STD_PAL_BG; + + int i = 0, err = 0; + struct tea6415c_multiplex vm; + + /* select video mode in saa7111a */ + i = VIDEO_MODE_PAL; + /* fixme: currently pointless: gets overwritten by configuration below */ + mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i); + + /* write configuration to saa7111a */ + init.data = mxb_saa7111_init; + init.len = sizeof(mxb_saa7111_init); + mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init); + + /* select tuner-output on saa7111a */ + i = 0; + mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i); + + /* enable vbi bypass */ + i = 1; + mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i); + + /* select a tuner type */ + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.addr = ADDR_UNSET; + tun_setup.type = TUNER_PHILIPS_PAL; + mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup); + /* tune in some frequency on tuner */ + mxb->cur_freq.tuner = 0; + mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV; + mxb->cur_freq.frequency = freq; + mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, + &mxb->cur_freq); + + /* set a default video standard */ + mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std); + + /* mute audio on tea6420s */ + mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]); + mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[6][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[6][1]); + + /* switch to tuner-channel on tea6415c*/ + vm.out = 17; + vm.in = 3; + mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm); + + /* select tuner-output on multicable on tea6415c*/ + vm.in = 3; + vm.out = 13; + mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm); + + /* the rest for mxb */ + mxb->cur_input = 0; + mxb->cur_mute = 1; + + mxb->cur_mode = V4L2_TUNER_MODE_STEREO; + mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode); + + /* check if the saa7740 (aka 'sound arena module') is present + on the mxb. if so, we must initialize it. due to lack of + informations about the saa7740, the values were reverse + engineered. */ + msg.addr = 0x1b; + msg.flags = 0; + msg.len = mxb_saa7740_init[0].length; + msg.buf = &mxb_saa7740_init[0].data[0]; + + if( 1 == (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) { + /* the sound arena module is a pos, that's probably the reason + philips refuses to hand out a datasheet for the saa7740... + it seems to screw up the i2c bus, so we disable fast irq + based i2c transactions here and rely on the slow and safe + polling method ... */ + extension.flags &= ~SAA7146_USE_I2C_IRQ; + for(i = 1;;i++) { + if( -1 == mxb_saa7740_init[i].length ) { + break; + } + + msg.len = mxb_saa7740_init[i].length; + msg.buf = &mxb_saa7740_init[i].data[0]; + if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) { + DEB_D(("failed to initialize 'sound arena module'.\n")); + goto err; + } + } + INFO(("'sound arena module' detected.\n")); + } +err: + /* the rest for saa7146: you should definitely set some basic values + for the input-port handling of the saa7146. */ + + /* ext->saa has been filled by the core driver */ + + /* some stuff is done via variables */ + saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync); + + /* some stuff is done via direct write to the registers */ + + /* this is ugly, but because of the fact that this is completely + hardware dependend, it should be done directly... */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x02000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + return 0; +} + +/* interrupt-handler. this gets called when irq_mask is != 0. + it must clear the interrupt-bits in irq_mask it has handled */ +/* +void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask) +{ + struct mxb* mxb = (struct mxb*)dev->ext_priv; +} +*/ + +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) +{ + struct mxb* mxb = (struct mxb*)dev->ext_priv; + + DEB_EE(("dev:%p\n",dev)); + + /* checking for i2c-devices can be omitted here, because we + already did this in "mxb_vl42_probe" */ + + saa7146_vv_init(dev,&vv_data); + if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { + ERR(("cannot register capture v4l2 device. skipping.\n")); + return -1; + } + + /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ + if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) { + if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { + ERR(("cannot register vbi v4l2 device. skipping.\n")); + } + } + + i2c_use_client(mxb->tea6420_1); + i2c_use_client(mxb->tea6420_2); + i2c_use_client(mxb->tea6415c); + i2c_use_client(mxb->tda9840); + i2c_use_client(mxb->saa7111a); + i2c_use_client(mxb->tuner); + + printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num); + + mxb_num++; + mxb_init_done(dev); + return 0; +} + +static int mxb_detach(struct saa7146_dev* dev) +{ + struct mxb* mxb = (struct mxb*)dev->ext_priv; + + DEB_EE(("dev:%p\n",dev)); + + i2c_release_client(mxb->tea6420_1); + i2c_release_client(mxb->tea6420_2); + i2c_release_client(mxb->tea6415c); + i2c_release_client(mxb->tda9840); + i2c_release_client(mxb->saa7111a); + i2c_release_client(mxb->tuner); + + saa7146_unregister_device(&mxb->video_dev,dev); + if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) { + saa7146_unregister_device(&mxb->vbi_dev,dev); + } + saa7146_vv_release(dev); + + mxb_num--; + + i2c_del_adapter(&mxb->i2c_adapter); + kfree(mxb); + + return 0; +} + +static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +{ + struct saa7146_dev *dev = fh->dev; + struct mxb* mxb = (struct mxb*)dev->ext_priv; + struct saa7146_vv *vv = dev->vv_data; + + switch(cmd) { + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + + DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index)); + if( i->index < 0 || i->index >= MXB_INPUTS) { + return -EINVAL; + } + memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); + + return 0; + } + /* the saa7146 provides some controls (brightness, contrast, saturation) + which gets registered *after* this function. because of this we have + to return with a value != 0 even if the function succeded.. */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == qc->id) { + *qc = mxb_controls[i]; + DEB_D(("VIDIOC_QUERYCTRL %d.\n",qc->id)); + return 0; + } + } + return -EAGAIN; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *vc = arg; + int i; + + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == vc->id) { + break; + } + } + + if( i < 0 ) { + return -EAGAIN; + } + + switch (vc->id ) { + case V4L2_CID_AUDIO_MUTE: { + vc->value = mxb->cur_mute; + DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value)); + return 0; + } + } + + DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value)); + return 0; + } + + case VIDIOC_S_CTRL: + { + struct v4l2_control *vc = arg; + int i = 0; + + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == vc->id) { + break; + } + } + + if( i < 0 ) { + return -EAGAIN; + } + + switch (vc->id ) { + case V4L2_CID_AUDIO_MUTE: { + mxb->cur_mute = vc->value; + if( 0 == vc->value ) { + /* switch the audio-source */ + mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][1]); + } else { + mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]); + } + DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n",vc->value)); + break; + } + } + return 0; + } + case VIDIOC_G_INPUT: + { + int *input = (int *)arg; + *input = mxb->cur_input; + + DEB_EE(("VIDIOC_G_INPUT %d.\n",*input)); + return 0; + } + case VIDIOC_S_INPUT: + { + int input = *(int *)arg; + struct tea6415c_multiplex vm; + int i = 0; + + DEB_EE(("VIDIOC_S_INPUT %d.\n",input)); + + if (input < 0 || input >= MXB_INPUTS) { + return -EINVAL; + } + + /* fixme: locke das setzen des inputs mit hilfe des mutexes + down(&dev->lock); + video_mux(dev,*i); + up(&dev->lock); + */ + + /* fixme: check if streaming capture + if ( 0 != dev->streaming ) { + DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n")); + return -EPERM; + } + */ + + mxb->cur_input = input; + + saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync); + + /* prepare switching of tea6415c and saa7111a; + have a look at the 'background'-file for further informations */ + switch( input ) { + + case TUNER: + { + i = 0; + vm.in = 3; + vm.out = 17; + + if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) { + printk("VIDIOC_S_INPUT: could not address tea6415c #1\n"); + return -EFAULT; + } + /* connect tuner-output always to multicable */ + vm.in = 3; + vm.out = 13; + break; + } + case AUX3_YC: + { + /* nothing to be done here. aux3_yc is + directly connected to the saa711a */ + i = 5; + break; + } + case AUX3: + { + /* nothing to be done here. aux3 is + directly connected to the saa711a */ + i = 1; + break; + } + case AUX1: + { + i = 0; + vm.in = 1; + vm.out = 17; + break; + } + } + + /* switch video in tea6415c only if necessary */ + switch( input ) { + case TUNER: + case AUX1: + { + if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) { + printk("VIDIOC_S_INPUT: could not address tea6415c #3\n"); + return -EFAULT; + } + break; + } + default: + { + break; + } + } + + /* switch video in saa7111a */ + if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) { + printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n"); + } + + /* switch the audio-source only if necessary */ + if( 0 == mxb->cur_mute ) { + mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][1]); + } + + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; + int byte = 0; + + if( 0 != t->index ) { + DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); + return -EINVAL; + } + + DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); + + memset(t,0,sizeof(*t)); + strcpy(t->name, "Television"); + + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ + t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ + /* FIXME: add the real signal strength here */ + t->signal = 0xffff; + t->afc = 0; + + mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte); + t->audmode = mxb->cur_mode; + + if( byte < 0 ) { + t->rxsubchans = V4L2_TUNER_SUB_MONO; + } else { + switch(byte) { + case TDA9840_MONO_DETECT: { + t->rxsubchans = V4L2_TUNER_SUB_MONO; + DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_MONO.\n")); + break; + } + case TDA9840_DUAL_DETECT: { + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_LANG1.\n")); + break; + } + case TDA9840_STEREO_DETECT: { + t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; + DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_STEREO.\n")); + break; + } + default: { /* TDA9840_INCORRECT_DETECT */ + t->rxsubchans = V4L2_TUNER_MODE_MONO; + DEB_D(("VIDIOC_G_TUNER: TDA9840_INCORRECT_DETECT => V4L2_TUNER_MODE_MONO\n")); + break; + } + } + } + + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *t = arg; + int result = 0; + int byte = 0; + + if( 0 != t->index ) { + DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index)); + return -EINVAL; + } + + switch(t->audmode) { + case V4L2_TUNER_MODE_STEREO: { + mxb->cur_mode = V4L2_TUNER_MODE_STEREO; + byte = TDA9840_SET_STEREO; + DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n")); + break; + } + case V4L2_TUNER_MODE_LANG1: { + mxb->cur_mode = V4L2_TUNER_MODE_LANG1; + byte = TDA9840_SET_LANG1; + DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n")); + break; + } + case V4L2_TUNER_MODE_LANG2: { + mxb->cur_mode = V4L2_TUNER_MODE_LANG2; + byte = TDA9840_SET_LANG2; + DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n")); + break; + } + default: { /* case V4L2_TUNER_MODE_MONO: {*/ + mxb->cur_mode = V4L2_TUNER_MODE_MONO; + byte = TDA9840_SET_MONO; + DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n")); + break; + } + } + + if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) { + printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte); + } + + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + if(0 != mxb->cur_input) { + DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",mxb->cur_input)); + return -EINVAL; + } + + *f = mxb->cur_freq; + + DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + if (0 != f->tuner) + return -EINVAL; + + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + + if(0 != mxb->cur_input) { + DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input)); + return -EINVAL; + } + + mxb->cur_freq = *f; + DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); + + /* tune in desired frequency */ + mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq); + + /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ + spin_lock(&dev->slock); + vv->vbi_fieldcount = 0; + spin_unlock(&dev->slock); + + return 0; + } + case MXB_S_AUDIO_CD: + { + int i = *(int*)arg; + + if( i < 0 || i >= MXB_AUDIOS ) { + DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i)); + return -EINVAL; + } + + DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i)); + + mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]); + + return 0; + } + case MXB_S_AUDIO_LINE: + { + int i = *(int*)arg; + + if( i < 0 || i >= MXB_AUDIOS ) { + DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i)); + return -EINVAL; + } + + DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i)); + mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]); + + return 0; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *a = arg; + + if( a->index < 0 || a->index > MXB_INPUTS ) { + DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index)); + return -EINVAL; + } + + DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index)); + memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); + + return 0; + } + case VIDIOC_S_AUDIO: + { + struct v4l2_audio *a = arg; + DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index)); + return 0; + } + default: +/* + DEB2(printk("does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} + +static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) +{ + struct mxb* mxb = (struct mxb*)dev->ext_priv; + int zero = 0; + int one = 1; + + if(V4L2_STD_PAL_I == std->id ) { + v4l2_std_id std = V4L2_STD_PAL_I; + DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n")); + /* set the 7146 gpio register -- I don't know what this does exactly */ + saa7146_write(dev, GPIO_CTRL, 0x00404050); + /* unset the 7111 gpio register -- I don't know what this does exactly */ + mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero); + mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std); + } else { + v4l2_std_id std = V4L2_STD_PAL_BG; + DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n")); + /* set the 7146 gpio register -- I don't know what this does exactly */ + saa7146_write(dev, GPIO_CTRL, 0x00404050); + /* set the 7111 gpio register -- I don't know what this does exactly */ + mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one); + mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std); + } + return 0; +} + +static struct saa7146_standard standard[] = { + { + .name = "PAL-BG", .id = V4L2_STD_PAL_BG, + .v_offset = 0x17, .v_field = 288, + .h_offset = 0x14, .h_pixels = 680, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "PAL-I", .id = V4L2_STD_PAL_I, + .v_offset = 0x17, .v_field = 288, + .h_offset = 0x14, .h_pixels = 680, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x16, .v_field = 240, + .h_offset = 0x06, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 0x14, .v_field = 288, + .h_offset = 0x14, .h_pixels = 720, + .v_max_out = 576, .h_max_out = 768, + } +}; + +static struct saa7146_pci_extension_data mxb = { + .ext_priv = "Multimedia eXtension Board", + .ext = &extension, +}; + +static struct pci_device_id pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x0000, + .subdevice = 0x0000, + .driver_data = (unsigned long)&mxb, + }, { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_ext_vv vv_data = { + .inputs = MXB_INPUTS, + .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE, + .stds = &standard[0], + .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), + .std_callback = &std_callback, + .ioctls = &ioctls[0], + .ioctl = mxb_ioctl, +}; + +static struct saa7146_extension extension = { + .name = MXB_IDENTIFIER, + .flags = SAA7146_USE_I2C_IRQ, + + .pci_tbl = &pci_tbl[0], + .module = THIS_MODULE, + + .probe = mxb_probe, + .attach = mxb_attach, + .detach = mxb_detach, + + .irq_mask = 0, + .irq_func = NULL, +}; + +static int __init mxb_init_module(void) +{ + if( 0 != saa7146_register_extension(&extension)) { + DEB_S(("failed to register extension.\n")); + return -ENODEV; + } + + return 0; +} + +static void __exit mxb_cleanup_module(void) +{ + saa7146_unregister_extension(&extension); +} + +module_init(mxb_init_module); +module_exit(mxb_cleanup_module); + +MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'"); +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/mxb.h b/linux/drivers/media/video/mxb.h new file mode 100644 index 000000000..400a57ba6 --- /dev/null +++ b/linux/drivers/media/video/mxb.h @@ -0,0 +1,42 @@ +#ifndef __MXB__ +#define __MXB__ + +#define BASE_VIDIOC_MXB 10 + +#define MXB_S_AUDIO_CD _IOW ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+0, int) +#define MXB_S_AUDIO_LINE _IOW ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+1, int) + +#define MXB_IDENTIFIER "Multimedia eXtension Board" + +#define MXB_AUDIOS 6 + +/* these are the available audio sources, which can switched + to the line- and cd-output individually */ +static struct v4l2_audio mxb_audios[MXB_AUDIOS] = { + { + .index = 0, + .name = "Tuner", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 1, + .name = "AUX1", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 2, + .name = "AUX2", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 3, + .name = "AUX3", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 4, + .name = "Radio (X9)", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 5, + .name = "CD-ROM (X10)", + .capability = V4L2_AUDCAP_STEREO, + } +}; +#endif diff --git a/linux/drivers/media/video/pvrusb2/Kconfig b/linux/drivers/media/video/pvrusb2/Kconfig new file mode 100644 index 000000000..262b033f4 --- /dev/null +++ b/linux/drivers/media/video/pvrusb2/Kconfig @@ -0,0 +1,14 @@ +config VIDEO_PVRUSB2 + tristate "Hauppauge WinTV-PVR USB2 support" + depends on VIDEO_DEV && USB && I2C && EXPERIMENTAL + select FW_LOADER + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_DECODER + select VIDEO_MSP3400 + ---help--- + This is a video4linux driver for Conexant 23416 based + usb2 personal video recorder devices. + + To compile this driver as a module, choose M here: the + module will be called pvrusb2 diff --git a/linux/drivers/media/video/pvrusb2/Makefile b/linux/drivers/media/video/pvrusb2/Makefile new file mode 100644 index 000000000..c83742fb1 --- /dev/null +++ b/linux/drivers/media/video/pvrusb2/Makefile @@ -0,0 +1,11 @@ +pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \ + pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \ + pvrusb2-encoder.o pvrusb2-video-v4l.o \ + pvrusb2-eeprom.o pvrusb2-tuner.o pvrusb2-demod.o \ + pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \ + pvrusb2-sysfs.o pvrusb2-context.o pvrusb2-io.o \ + pvrusb2-ioread.o pvrusb2-debugifc.o + +obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o + +EXTRA_CFLAGS += -I$(src)/.. diff --git a/v4l_experimental/pvrusb2/pvrusb2-audio.c b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c index 067a686e0..7e2fab330 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-audio.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-audio.c,v 1.9 2006/01/23 07:00:31 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> @@ -155,7 +155,7 @@ static int msp3400_check(struct pvr2_msp3400_handler *ctxt) unsigned long msk; unsigned int idx; - for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]); + for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]); idx++) { msk = 1 << idx; if (ctxt->stale_mask & msk) continue; @@ -172,7 +172,7 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt) unsigned long msk; unsigned int idx; - for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]); + for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]); idx++) { msk = 1 << idx; if (!(ctxt->stale_mask & msk)) continue; diff --git a/v4l_experimental/pvrusb2/pvrusb2-audio.h b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h index 0a278927e..536339b68 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-audio.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-audio.h,v 1.2 2006/01/01 08:26:03 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/v4l_experimental/pvrusb2/pvrusb2-context.c b/linux/drivers/media/video/pvrusb2/pvrusb2-context.c index 1f8b400a0..0f0e14d01 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-context.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -1,5 +1,5 @@ /* - * $Id: pvrusb2-context.c,v 1.3 2006/01/23 06:58:06 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -74,7 +74,9 @@ static void pvr2_context_setup(struct pvr2_context *mp) struct pvr2_context *pvr2_context_create( - struct usb_interface *intf,void (*setup_func)(struct pvr2_context *)) + struct usb_interface *intf, + const struct usb_device_id *devid, + void (*setup_func)(struct pvr2_context *)) { struct pvr2_context *mp = 0; mp = kmalloc(sizeof(*mp),GFP_KERNEL); @@ -83,7 +85,7 @@ struct pvr2_context *pvr2_context_create( pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp); mp->setup_func = setup_func; mutex_init(&mp->mutex); - mp->hdw = pvr2_hdw_create(intf); + mp->hdw = pvr2_hdw_create(intf,devid); if (!mp->hdw) { pvr2_context_destroy(mp); mp = 0; @@ -183,7 +185,7 @@ void pvr2_channel_done(struct pvr2_channel *cp) int pvr2_channel_claim_stream(struct pvr2_channel *cp, - struct pvr2_context_stream *sp) + struct pvr2_context_stream *sp) { int code = 0; pvr2_context_enter(cp->mc_head); do { diff --git a/v4l_experimental/pvrusb2/pvrusb2-context.h b/linux/drivers/media/video/pvrusb2/pvrusb2-context.h index 229a8ef0e..873622a0f 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-context.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-context.h @@ -1,5 +1,5 @@ /* - * $Id: pvrusb2-context.h,v 1.3 2006/01/23 06:58:06 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -77,6 +77,7 @@ void pvr2_context_enter(struct pvr2_context *); void pvr2_context_exit(struct pvr2_context *); struct pvr2_context *pvr2_context_create(struct usb_interface *intf, + const struct usb_device_id *devid, void (*setup_func)(struct pvr2_context *)); void pvr2_context_disconnect(struct pvr2_context *); diff --git a/v4l_experimental/pvrusb2/pvrusb2-debug.h b/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h index 70a143736..d95a8588e 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-debug.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -1,5 +1,5 @@ /* - * $Id: pvrusb2-debug.h,v 1.5 2006/01/14 22:09:52 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -22,7 +22,7 @@ extern int pvrusb2_debug; -#define pvr2_trace(msk, fmt, arg...) do {if(msk & pvrusb2_debug) printk(KERN_INFO "pvrusb2 " fmt "\n", ##arg); } while (0) +#define pvr2_trace(msk, fmt, arg...) do {if(msk & pvrusb2_debug) printk(KERN_INFO "pvrusb2: " fmt "\n", ##arg); } while (0) /* These are listed in *rough* order of decreasing usefulness and increasing noise level. */ diff --git a/v4l_experimental/pvrusb2/pvrusb2-debugifc.c b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c index f56b96f56..bcfe468eb 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-debugifc.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-debugifc.c,v 1.2 2006/01/01 08:26:03 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -41,7 +41,7 @@ static struct debugifc_mask_item mask_items[] = { static unsigned int debugifc_count_whitespace(const char *buf, - unsigned int count) + unsigned int count) { unsigned int scnt; char ch; @@ -58,7 +58,7 @@ static unsigned int debugifc_count_whitespace(const char *buf, static unsigned int debugifc_count_nonwhitespace(const char *buf, - unsigned int count) + unsigned int count) { unsigned int scnt; char ch; @@ -74,8 +74,8 @@ static unsigned int debugifc_count_nonwhitespace(const char *buf, static unsigned int debugifc_isolate_word(const char *buf,unsigned int count, - const char **wstrPtr, - unsigned int *wlenPtr) + const char **wstrPtr, + unsigned int *wlenPtr) { const char *wptr; unsigned int consume_cnt = 0; @@ -102,7 +102,7 @@ static unsigned int debugifc_isolate_word(const char *buf,unsigned int count, static int debugifc_parse_unsigned_number(const char *buf,unsigned int count, - u32 *num_ptr) + u32 *num_ptr) { u32 result = 0; u32 val; @@ -138,7 +138,7 @@ static int debugifc_parse_unsigned_number(const char *buf,unsigned int count, static int debugifc_match_keyword(const char *buf,unsigned int count, - const char *keyword) + const char *keyword) { unsigned int kl; if (!keyword) return 0; @@ -163,7 +163,7 @@ static unsigned long debugifc_find_mask(const char *buf,unsigned int count) static int debugifc_print_mask(char *buf,unsigned int sz, - unsigned long msk,unsigned long val) + unsigned long msk,unsigned long val) { struct debugifc_mask_item *mip; unsigned int idx; @@ -184,9 +184,9 @@ static int debugifc_print_mask(char *buf,unsigned int sz, } static unsigned int debugifc_parse_subsys_mask(const char *buf, - unsigned int count, - unsigned long *mskPtr, - unsigned long *valPtr) + unsigned int count, + unsigned long *mskPtr, + unsigned long *valPtr) { const char *wptr; unsigned int consume_cnt = 0; @@ -286,7 +286,7 @@ int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt) int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, - char *buf,unsigned int acnt) + char *buf,unsigned int acnt) { int bcnt = 0; int ccnt; @@ -338,7 +338,7 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, - unsigned int count) + unsigned int count) { const char *wptr; unsigned int wlen; @@ -444,7 +444,7 @@ int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf, - unsigned int count) + unsigned int count) { unsigned int bcnt = 0; int ret; diff --git a/v4l_experimental/pvrusb2/pvrusb2-debugifc.h b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h index 59f4373d6..990b02d35 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-debugifc.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-debugifc.h,v 1.1 2005/11/14 13:31:24 mchehab Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/v4l_experimental/pvrusb2/pvrusb2-demod.c b/linux/drivers/media/video/pvrusb2/pvrusb2-demod.c index f7545b773..dca787dfa 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-demod.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-demod.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-demod.c,v 1.5 2006/01/22 03:48:34 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/v4l_experimental/pvrusb2/pvrusb2-demod.h b/linux/drivers/media/video/pvrusb2/pvrusb2-demod.h index 0067872ea..4c4e40ffb 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-demod.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-demod.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-demod.h,v 1.1 2006/01/01 08:26:03 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/v4l_experimental/pvrusb2/pvrusb2-eeprom.c b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c index 9df9fd3eb..60ee45ca2 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-eeprom.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-eeprom.c,v 1.5 2006/01/14 19:09:50 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> @@ -86,21 +86,22 @@ */ -#define PVR_EEPROM_I2C_ADDR 0x50 - #include <media/tveeprom.h> -/* We seem to only be interested in the back half of the EEPROM */ +/* We seem to only be interested in the last 128 bytes of the EEPROM */ #define EEPROM_SIZE 128 -#define EEPROM_OFFS 128 /* Grab EEPROM contents, needed for direct method. */ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw) { struct i2c_msg msg[2]; u8 *eeprom; - u8 offs; + u8 iadd[2]; + u8 addr; + u16 eepromSize; + unsigned int offs; int ret; + int mode16 = 0; unsigned pcnt,tcnt; eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); if (!eeprom) { @@ -110,11 +111,28 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw) return 0; } - msg[0].addr = PVR_EEPROM_I2C_ADDR; + trace_eeprom("Value for eeprom addr from controller was 0x%x", + hdw->eeprom_addr); + addr = hdw->eeprom_addr; + /* Seems that if the high bit is set, then the *real* eeprom + address is shifted right now bit position (noticed this in + newer PVR USB2 hardware) */ + if (addr & 0x80) addr >>= 1; + + /* FX2 documentation states that a 16bit-addressed eeprom is + expected if the I2C address is an odd number (yeah, this is + strange bit it's what they do) */ + mode16 = (addr & 1); + eepromSize = (mode16 ? 4096 : 256); + trace_eeprom("Examining %d byte eeprom at location 0x%x" + " using %d bit addressing",eepromSize,addr, + mode16 ? 16 : 8); + + msg[0].addr = addr; msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = &offs; - msg[1].addr = PVR_EEPROM_I2C_ADDR; + msg[0].len = mode16 ? 2 : 1; + msg[0].buf = iadd; + msg[1].addr = hdw->eeprom_addr; msg[1].flags = I2C_M_RD; /* We have to do the actual eeprom data fetch ourselves, because @@ -125,7 +143,13 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw) for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { pcnt = 16; if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; - offs = tcnt + EEPROM_OFFS; + offs = tcnt + (eepromSize - EEPROM_SIZE); + if (mode16) { + iadd[0] = offs >> 8; + iadd[1] = offs; + } else { + iadd[0] = offs; + } msg[1].len = pcnt; msg[1].buf = eeprom+tcnt; if ((ret = i2c_transfer( @@ -163,7 +187,7 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) { struct i2c_client fake_client; /* Newer version expects a useless client interface */ - fake_client.addr = PVR_EEPROM_I2C_ADDR; + fake_client.addr = hdw->eeprom_addr; fake_client.adapter = &hdw->i2c_adap; tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom); } diff --git a/v4l_experimental/pvrusb2/pvrusb2-eeprom.h b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h index edc80b62e..061cecd91 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-eeprom.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-eeprom.h,v 1.1 2005/11/14 13:31:24 mchehab Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/v4l_experimental/pvrusb2/pvrusb2-encoder.c b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 046cd9f1f..97931d3c4 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-encoder.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-encoder.c,v 1.5 2006/01/14 20:11:08 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> @@ -147,7 +147,7 @@ static int pvr2_read_encoder_words(struct pvr2_hdw *hdw,int statusFl, static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd, - int args, ...) + int args, ...) { unsigned int poll_count; int ret = 0; @@ -308,14 +308,14 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) the ivtv driver). But, if I leave them in, then mplayer goes nuts with xrun errors. So for now we don't do this. It sure would be nice to know what these are for. */ -#ifdef notdef +#if 0 ret |= pvr2_write_encoder_vcmd(hdw, 0xdc, 1, 5); ret |= pvr2_write_encoder_vcmd(hdw, 0xdc, 2, 3, 1); ret |= pvr2_write_encoder_vcmd(hdw, 0xdc, 1, 8); #endif /* Strange compared to ivtv data. */ -#ifdef notdef +#if 0 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0x0120, 0x0120); ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, diff --git a/v4l_experimental/pvrusb2/pvrusb2-encoder.h b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h index 4a35e8ac0..01b5a0b89 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-encoder.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-encoder.h,v 1.1 2005/11/14 13:31:24 mchehab Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/v4l_experimental/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index c4b1cbdcd..1b161773b 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-hdw-internal.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-hdw-internal.h,v 1.6 2006/01/23 06:58:06 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -93,6 +93,10 @@ struct pvr2_decoder_ctrl { #define FW1_STATE_RELOAD 3 #define FW1_STATE_OK 4 +/* Known major hardware variants, keyed from device ID */ +#define PVR2_HDW_TYPE_29XXX 0 +#define PVR2_HDW_TYPE_24XXX 1 + /* This structure contains all state data directly needed to manipulate the hardware (as opposed to complying with a kernel interface) */ @@ -101,6 +105,9 @@ struct pvr2_hdw { struct usb_device *usb_dev; struct usb_interface *usb_intf; + /* Device type, one of PVR2_HDW_TYPE_xxxxx */ + unsigned int hdw_type; + /* Video spigot */ struct pvr2_stream *vid_stream; @@ -176,6 +183,10 @@ struct pvr2_hdw { // Which subsystems are manipulated to enable streaming unsigned long subsys_stream_mask; + // True if there is a request to trigger logging of state in each + // module. + int log_requested; + /* Tuner / frequency control stuff */ unsigned int tuner_type; int tuner_updated; @@ -188,6 +199,9 @@ struct pvr2_hdw { be no v4l junk here). Probably a better way to do this. */ int v4l_minor_number; + /* Location of eeprom or a negative number if none */ + int eeprom_addr; + enum pvr2_config config; /* Information about what audio signal we're hearing */ @@ -200,7 +214,7 @@ struct pvr2_hdw { }; int pvr2_hdw_set_ctl_value_internal(struct pvr2_hdw *hdw, - unsigned int ctl_id,int value); + unsigned int ctl_id,int value); int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw); diff --git a/v4l_experimental/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 20206cff9..b87651e5a 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-hdw.c,v 1.13 2006/01/23 06:58:06 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -35,6 +35,19 @@ #include "pvrusb2-encoder.h" #include "pvrusb2-debug.h" +struct usb_device_id pvr2_device_table[] = { + [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) }, + [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, pvr2_device_table); + +static const char *pvr2_device_names[] = { + [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx", + [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx", +}; + static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = 0}; DECLARE_MUTEX(pvr2_unit_sem); @@ -43,14 +56,17 @@ static int initusbreset = 1; static int procreload = 0; static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 }; static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; +static int init_pause_msec = 0; module_param(ctlchg, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value"); +module_param(init_pause_msec, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay"); module_param(initusbreset, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe"); module_param(procreload, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(procreload, - "Attempt init failure recovery with firmware reload"); + "Attempt init failure recovery with firmware reload"); module_param_array(tuner, int, NULL, 0444); MODULE_PARM_DESC(tuner,"specify installed tuner type"); module_param_array(tolerance, int, NULL, 0444); @@ -70,10 +86,6 @@ MODULE_PARM_DESC(tolerance,"specify stream error tolerance"); /* size of a firmware chunk */ #define FIRMWARE_CHUNK_SIZE 0x2000 -/* Various files we will load with firmware_entry */ -#define FIRMWARE1_FILE "pvrusb2.f1" -#define FIRMWARE2_FILE "pvrusb2.f2" - typedef int (*pvr2_ctl_set_func)(struct pvr2_hdw *,int ctl_id,int val); typedef int (*pvr2_ctl_get_func)(struct pvr2_hdw *,int ctl_id); @@ -169,7 +181,7 @@ static int pvr2_ctl_get_subsys_mask(struct pvr2_hdw *hdw,int ctl_id); static int pvr2_ctl_set_subsys_mask(struct pvr2_hdw *hdw,int ctl_id,int val); static int pvr2_ctl_get_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id); static int pvr2_ctl_set_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id, - int val); + int val); static struct pvr2_ctl_def control_defs[PVR2_CID_COUNT] = { @@ -296,7 +308,7 @@ static struct pvr2_ctl_def control_defs[PVR2_CID_COUNT] = [PVR2_CID_FREQUENCY] = { .name = "Tuner Frequency (Hz)", .min_value = 55250000L, - .max_value = 801250000L, + .max_value = 850000000L, .default_value = 175250000L, }, [PVR2_CID_HRES] = { @@ -338,7 +350,7 @@ static struct pvr2_ctl_def control_defs[PVR2_CID_COUNT] = [PVR2_CID_CHANPROG_FREQ] = { .name = "Channel Program Frequency", .min_value = 55250000L, - .max_value = 801250000L, + .max_value = 850000000L, .skip_init = !0, .set_func = pvr2_ctl_set_chanprog_id, .get_func = pvr2_ctl_get_chanprog_id, @@ -421,6 +433,63 @@ int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw) } +/* Attempt to locate one of the given set of files. Messages are logged + appropriate to what has been found. The return value will be 0 or + greater on success (it will be the index of the file name found) and + fw_entry will be filled in. Otherwise a negative error is returned on + failure. If the return value is -ENOENT then no viable firmware file + could be located. */ +static int pvr2_locate_firmware(struct pvr2_hdw *hdw, + const struct firmware **fw_entry, + const char *fwtypename, + unsigned int fwcount, + const char *fwnames[]) +{ + unsigned int idx; + int ret = -EINVAL; + for (idx = 0; idx < fwcount; idx++) { + ret = request_firmware(fw_entry, + fwnames[idx], + &hdw->usb_dev->dev); + if (!ret) { + trace_firmware("Located %s firmware: %s;" + " uploading...", + fwtypename, + fwnames[idx]); + return idx; + } + if (ret == -ENOENT) continue; + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "request_firmware fatal error with code=%d",ret); + return ret; + } + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "***WARNING***" + " Device %s firmware" + " seems to be missing.", + fwtypename); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Did you install the pvrusb2 firmware files" + " in their proper location?"); + if (fwcount == 1) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "request_firmware unable to locate %s file %s", + fwtypename,fwnames[0]); + } else { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "request_firmware unable to locate" + " one of the following %s files:", + fwtypename); + for (idx = 0; idx < fwcount; idx++) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "request_firmware: Failed to find %s", + fwnames[idx]); + } + } + return ret; +} + + /* * pvr2_upload_firmware1(). * @@ -438,27 +507,41 @@ int pvr2_upload_firmware1(struct pvr2_hdw *hdw) unsigned int pipe; int ret; u16 address; - const char *firmware_file = FIRMWARE1_FILE; - + static const char *fw_files_29xxx[] = { + "v4l-pvrusb2-29xxx-01.fw", + }; + static const char *fw_files_24xxx[] = { + "v4l-pvrusb2-24xxx-01.fw", + }; + static const struct { + const char **lst; + unsigned int cnt; + } fw_file_defs[] = { + [PVR2_HDW_TYPE_29XXX] = { + fw_files_29xxx, + sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]), + }, + [PVR2_HDW_TYPE_24XXX] = { + fw_files_24xxx, + sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]), + }, + }; hdw->fw1_state = FW1_STATE_FAILED; // default result trace_firmware("pvr2_upload_firmware1"); + ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller", + fw_file_defs[hdw->hdw_type].cnt, + fw_file_defs[hdw->hdw_type].lst); + if (ret < 0) { + if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING; + return ret; + } + usb_settoggle(hdw->usb_dev, 0 & 0xf, !(0 & USB_DIR_IN), 0); usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f)); pipe = usb_sndctrlpipe(hdw->usb_dev, 0); - ret = request_firmware(&fw_entry, firmware_file, &hdw->usb_dev->dev); - - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "request_firmware failed for '%s' code=%d", - firmware_file,ret); - if (ret == -ENOENT) { - hdw->fw1_state = FW1_STATE_MISSING; - } - return ret; - } if (fw_entry->size != 0x2000){ pvr2_trace(PVR2_TRACE_ERROR_LEGS,"wrong fx2 firmware size"); @@ -519,9 +602,20 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) unsigned int pipe, fw_len, fw_done; int actual_length; int ret = 0; + int fwidx; + static const char *fw_files[] = { + "v4l-cx2341x-enc.fw", + }; trace_firmware("pvr2_upload_firmware2"); + ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder", + sizeof(fw_files)/sizeof(fw_files[0]), + fw_files); + if (ret < 0) return ret; + fwidx = ret; + ret = 0; + /* First prepare firmware loading */ ret |= pvr2_hdw_cmd_soft_reset(hdw); ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/ @@ -546,34 +640,19 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) if (ret) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "firmware2 upload prep failed, ret=%d",ret); + release_firmware(fw_entry); return ret; } /* Now send firmware */ - ret = request_firmware(&fw_entry, FIRMWARE2_FILE, &hdw->usb_dev->dev); - - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "request_firmware failed for '%s'", FIRMWARE2_FILE); - if (ret == -ENOENT) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "***WARNING***" - " Device encoder firmware" - " seems to be missing."); - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Did you install the pvrusb2 firmware files" - " in their proper location?"); - } - return ret; - } - fw_len = fw_entry->size; if (fw_len % FIRMWARE_CHUNK_SIZE) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "size of %s must be a multiple of 8192B", - FIRMWARE2_FILE); + "size of %s firmware" + " must be a multiple of 8192B", + fw_files[fwidx]); release_firmware(fw_entry); return -1; } @@ -603,7 +682,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) } trace_firmware("upload of %s : %i / %i ", - FIRMWARE2_FILE,fw_done,fw_len); + fw_files[fwidx],fw_done,fw_len); kfree(fw_ptr); release_firmware(fw_entry); @@ -842,8 +921,8 @@ unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw) void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val) + unsigned long msk, + unsigned long val) { unsigned long val2; msk &= PVR2_SUBSYS_ALL; @@ -856,8 +935,8 @@ void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val) + unsigned long msk, + unsigned long val) { LOCK_TAKE(hdw->big_lock); do { pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val); @@ -906,7 +985,7 @@ int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag) int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw, - enum pvr2_config config) + enum pvr2_config config) { unsigned long sm = hdw->subsys_enabled_mask; if (!hdw->flag_ok) return -EIO; @@ -952,10 +1031,55 @@ static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw) } +static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw) +{ + /* Try a harmless request to fetch the eeprom's address over + endpoint 1. See what happens. Only the full FX2 image can + respond to this. If this probe fails then likely the FX2 + firmware needs be loaded. */ + int result; + LOCK_TAKE(hdw->ctl_lock); do { + hdw->cmd_buffer[0] = 0xeb; + result = pvr2_send_request_ex(hdw,HZ*1,!0, + hdw->cmd_buffer,1, + hdw->cmd_buffer,1); + if (result < 0) break; + } while(0); LOCK_GIVE(hdw->ctl_lock); + if (result) { + pvr2_trace(PVR2_TRACE_INIT, + "Probe of device endpoint 1 result status %d", + result); + } else { + pvr2_trace(PVR2_TRACE_INIT, + "Probe of device endpoint 1 succeeded"); + } + return result == 0; +} + + static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) { + int ret; unsigned int idx; - if (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints == 0) { + int reloadFl = 0; + if (!reloadFl) { + reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints + == 0); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "USB endpoint config looks strange" + "; possibly firmware needs to be loaded"); + } + } + if (!reloadFl) { + reloadFl = !pvr2_hdw_check_firmware(hdw); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "Check for FX2 firmware failed" + "; possibly firmware needs to be loaded"); + } + } + if (reloadFl) { if (pvr2_upload_firmware1(hdw) != 0) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Failure uploading firmware1"); @@ -987,8 +1111,16 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) pvr2_reset_ctl_endpoints(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; - pvr2_eeprom_analyze(hdw); + ret = pvr2_hdw_get_eeprom_addr(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; + if (ret < 0) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Unable to determine location of eeprom, skipping"); + } else { + hdw->eeprom_addr = ret; + pvr2_eeprom_analyze(hdw); + if (!pvr2_hdw_dev_ok(hdw)) return; + } if (!get_default_tuner_type(hdw)) { pvr2_trace(PVR2_TRACE_INIT, @@ -1059,21 +1191,17 @@ int pvr2_hdw_setup(struct pvr2_hdw *hdw) " and reconnect."); break; } + pvr2_trace( + PVR2_TRACE_ERROR_LEGS, + "Device initialization was not successful."); if (hdw->fw1_state == FW1_STATE_MISSING) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "***WARNING***" - " Device microcontroller firmware" - " seems to be missing."); - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Did you install the pvrusb2 firmware" - " files in their proper location?"); + "Giving up since device" + " microcontroller firmware" + " appears to be missing."); break; } - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Device initialization was not successful."); } if (procreload) { pvr2_trace( @@ -1099,22 +1227,37 @@ int pvr2_hdw_setup(struct pvr2_hdw *hdw) " in order to recover."); } } while (0); LOCK_GIVE(hdw->big_lock); + pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); return hdw->flag_init_ok; } /* Create and return a structure for interacting with the underlying hardware */ -struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf) +struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, + const struct usb_device_id *devid) { unsigned int idx,cnt1,cnt2; struct pvr2_hdw *hdw; + unsigned int hdw_type; __u8 ifnum; + hdw_type = devid - pvr2_device_table; + if (hdw_type >= + sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Bogus device type of %u reported",hdw_type); + return 0; + } + hdw = kmalloc(sizeof(*hdw),GFP_KERNEL); - pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p",hdw); + pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", + hdw,pvr2_device_names[hdw_type]); if (!hdw) goto fail; memset(hdw,0,sizeof(*hdw)); + hdw->hdw_type = hdw_type; + + hdw->eeprom_addr = -1; hdw->unit_number = -1; hdw->v4l_minor_number = -1; hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); @@ -1342,7 +1485,7 @@ int pvr2_hdw_get_ctl_max_value(struct pvr2_hdw *hdw,unsigned int ctl_id) /* Set current value for given control - normally this is just stored and the hardware isn't updated until the commit function is called. */ int pvr2_hdw_set_ctl_value_internal(struct pvr2_hdw *hdw, - unsigned int ctl_id,int value) + unsigned int ctl_id,int value) { if (ctl_id >= PVR2_CID_COUNT) return -EINVAL; if (value < control_defs[ctl_id].min_value) return -EINVAL; @@ -1377,8 +1520,8 @@ int pvr2_hdw_set_ctl_value(struct pvr2_hdw *hdw,unsigned int ctl_id,int value) /* Retrieve string name for a given control value (returns a null pointer for any invalid combinations). */ const char *pvr2_hdw_get_ctl_value_name(struct pvr2_hdw *hdw, - unsigned int ctl_id, - int value) + unsigned int ctl_id, + int value) { struct pvr2_ctl_def *cdef; if (ctl_id >= PVR2_CID_COUNT) return 0; @@ -1641,7 +1784,7 @@ static int pvr2_ctl_get_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id) static int pvr2_ctl_set_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id, - int val) + int val) { pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,~0,val); return 0; @@ -1697,6 +1840,16 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp) } +void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) +{ + LOCK_TAKE(hdw->big_lock); do { + hdw->log_requested = !0; + pvr2_i2c_core_check_stale(hdw); + hdw->log_requested = 0; + pvr2_i2c_core_sync(hdw); + } while (0); LOCK_GIVE(hdw->big_lock); +} + void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag) { int ret; @@ -1757,7 +1910,7 @@ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw) int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs, - char *buf,unsigned int cnt) + char *buf,unsigned int cnt) { int ret = -EINVAL; LOCK_TAKE(hdw->big_lock); do { @@ -1853,31 +2006,33 @@ static void pvr2_ctl_timeout(unsigned long data) } -int pvr2_send_request(struct pvr2_hdw *hdw, - void *write_data,unsigned int write_len, - void *read_data,unsigned int read_len) +int pvr2_send_request_ex(struct pvr2_hdw *hdw, + unsigned int timeout,int probe_fl, + void *write_data,unsigned int write_len, + void *read_data,unsigned int read_len) { unsigned int idx; - int status; + int status = 0; struct timer_list timer; if (!hdw->ctl_lock_held) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Attempted to execute control transfer" " without lock!!"); - status = -EINVAL; - goto done; + return -EDEADLK; } - if (!hdw->flag_ok) { + if ((!hdw->flag_ok) && !probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Attempted to execute control transfer" " when device not ok"); return -EIO; } if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Attempted to execute control transfer" - " when USB is disconnected"); - return -EIO; + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Attempted to execute control transfer" + " when USB is disconnected"); + } + return -ENOTTY; } /* Ensure that we have sane parameters */ @@ -1921,7 +2076,7 @@ int pvr2_send_request(struct pvr2_hdw *hdw, hdw->ctl_write_pend_flag = 0; hdw->ctl_read_pend_flag = 0; init_timer(&timer); - timer.expires = jiffies + HZ*4; + timer.expires = jiffies + timeout; timer.data = (unsigned long)hdw; timer.function = pvr2_ctl_timeout; @@ -1952,6 +2107,7 @@ int pvr2_send_request(struct pvr2_hdw *hdw, "Failed to submit write-control" " URB status=%d",status); hdw->ctl_write_pend_flag = 0; + goto done; } } @@ -1978,6 +2134,7 @@ int pvr2_send_request(struct pvr2_hdw *hdw, "Failed to submit read-control" " URB status=%d",status); hdw->ctl_read_pend_flag = 0; + goto done; } } @@ -1999,6 +2156,10 @@ int pvr2_send_request(struct pvr2_hdw *hdw, if (hdw->ctl_timeout_flag) { status = -ETIMEDOUT; + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Timed out control-write"); + } goto done; } @@ -2011,19 +2172,24 @@ int pvr2_send_request(struct pvr2_hdw *hdw, /* USB subsystem is reporting some kind of failure on the write */ status = hdw->ctl_write_urb->status; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-write URB failure, status=%d", - status); + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "control-write URB failure," + " status=%d", + status); + } goto done; } if (hdw->ctl_write_urb->actual_length < write_len) { /* Failed to write enough data */ status = -EIO; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-write URB short," - " expected=%d got=%d", - write_len, - hdw->ctl_write_urb->actual_length); + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "control-write URB short," + " expected=%d got=%d", + write_len, + hdw->ctl_write_urb->actual_length); + } goto done; } } @@ -2036,18 +2202,24 @@ int pvr2_send_request(struct pvr2_hdw *hdw, /* USB subsystem is reporting some kind of failure on the read */ status = hdw->ctl_read_urb->status; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-read URB failure, status=%d", - status); + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "control-read URB failure," + " status=%d", + status); + } goto done; } if (hdw->ctl_read_urb->actual_length < read_len) { /* Failed to read enough data */ status = -EIO; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-read URB short," - " expected=%d got=%d", - read_len,hdw->ctl_read_urb->actual_length); + if (!probe_fl) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "control-read URB short," + " expected=%d got=%d", + read_len, + hdw->ctl_read_urb->actual_length); + } goto done; } /* Transfer retrieved data out from internal buffer */ @@ -2059,13 +2231,22 @@ int pvr2_send_request(struct pvr2_hdw *hdw, done: hdw->cmd_debug_state = 0; - if (status < 0) { + if ((status < 0) && (!probe_fl)) { pvr2_hdw_render_useless_unlocked(hdw); } return status; } +int pvr2_send_request(struct pvr2_hdw *hdw, + void *write_data,unsigned int write_len, + void *read_data,unsigned int read_len) +{ + return pvr2_send_request_ex(hdw,HZ*4,0, + write_data,write_len, + read_data,read_len); +} + int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data) { int ret; @@ -2177,6 +2358,13 @@ void pvr2_hdw_device_reset(struct pvr2_hdw *hdw) pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Failed to lock USB device ret=%d",ret); } + if (init_pause_msec) { + pvr2_trace(PVR2_TRACE_INFO, + "Waiting %u msec for hardware to settle", + init_pause_msec); + msleep(init_pause_msec); + } + } @@ -2247,7 +2435,7 @@ int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl) void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *ptr) + struct pvr2_hdw_debug_info *ptr) { ptr->big_lock_held = hdw->big_lock_held; ptr->ctl_lock_held = hdw->ctl_lock_held; @@ -2327,6 +2515,21 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val) } +int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) +{ + int result; + LOCK_TAKE(hdw->ctl_lock); do { + hdw->cmd_buffer[0] = 0xeb; + result = pvr2_send_request(hdw, + hdw->cmd_buffer,1, + hdw->cmd_buffer,1); + if (result < 0) break; + result = hdw->cmd_buffer[0]; + } while(0); LOCK_GIVE(hdw->ctl_lock); + return result; +} + + /* Stuff for Emacs to see, in order to encourage consistent editing style: *** Local Variables: *** diff --git a/v4l_experimental/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h index d813d07d4..667c95a27 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-hdw.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-hdw.h,v 1.6 2006/01/14 21:11:17 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -145,7 +145,7 @@ #define PVR2_SUBSYS_ENC_RUN (1 << 4) #define PVR2_SUBSYS_CFG_ALL ( \ - PVR2_SUBSYS_ENC_FIRMWARE | \ + PVR2_SUBSYS_ENC_FIRMWARE | \ PVR2_SUBSYS_ENC_CFG ) #define PVR2_SUBSYS_RUN_ALL ( \ PVR2_SUBSYS_DIGITIZER_RUN | \ @@ -168,7 +168,8 @@ struct pvr2_hdw; /* Create and return a structure for interacting with the underlying hardware */ -struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf); +struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, + const struct usb_device_id *devid); /* Poll for background activity (if any) */ void pvr2_hdw_poll(struct pvr2_hdw *); @@ -235,7 +236,7 @@ const char *pvr2_hdw_get_ctl_name(struct pvr2_hdw *,unsigned int ctl_id); /* Retrieve string name for a given control value (returns a null pointer for any invalid combinations). */ const char *pvr2_hdw_get_ctl_value_name(struct pvr2_hdw *, - unsigned int ctl_id,int value); + unsigned int ctl_id,int value); /* Commit all control changes made up to this point */ int pvr2_hdw_commit_ctl(struct pvr2_hdw *); @@ -269,7 +270,7 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *); identified by bit positions within msk, and new state for each item is identified by corresponding bit positions within val. */ void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk,unsigned long val); + unsigned long msk,unsigned long val); /* Shortcut for pvr2_hdw_subsys_bit_chg(hdw,msk,msk) */ void pvr2_hdw_subsys_bit_set(struct pvr2_hdw *hdw,unsigned long msk); @@ -284,7 +285,7 @@ unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *); /* Adjust mask of what get shut down when streaming is stopped. This is a debugging aid. */ void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk,unsigned long val); + unsigned long msk,unsigned long val); /* Retrieve mask indicating which pieces of hardware are disabled when streaming is turned off. */ @@ -304,7 +305,7 @@ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *); value is the number of bytes retrieved or zero if we're past the end or an error otherwise (e.g. if firmware retrieval is not enabled). */ int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs, - char *buf,unsigned int cnt); + char *buf,unsigned int cnt); /* Retrieve previously stored v4l minor device number */ int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *); @@ -322,8 +323,17 @@ void pvr2_reset_ctl_endpoints(struct pvr2_hdw *hdw); /* Issue a command and get a response from the device. LOTS of higher level stuff is built on this. */ -int pvr2_send_request(struct pvr2_hdw *, void *, unsigned int, - void *, unsigned int); +int pvr2_send_request(struct pvr2_hdw *, + void *write_ptr,unsigned int write_len, + void *read_ptr,unsigned int read_len); + +/* Issue a command and get a response from the device. This extended + version includes a probe flag (which if set means that device errors + should not be logged or treated as fatal) and a timeout in jiffies. + This can be used to non-lethally probe the health of endpoint 1. */ +int pvr2_send_request_ex(struct pvr2_hdw *,unsigned int timeout,int probe_fl, + void *write_ptr,unsigned int write_len, + void *read_ptr,unsigned int read_len); /* Slightly higher level device communication functions. */ int pvr2_write_register(struct pvr2_hdw *, u16, u32); @@ -353,6 +363,9 @@ int pvr2_hdw_cmd_soft_reset(struct pvr2_hdw *); /* Stop / start video stream transport */ int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl); +/* Find I2C address of eeprom */ +int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *); + /* Direct manipulation of GPIO bits */ int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *); int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *); @@ -385,13 +398,18 @@ struct pvr2_hdw_debug_info { kind of locking and so it is not atomic and may yield inconsistent results. This is *purely* a debugging aid. */ void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *); + struct pvr2_hdw_debug_info *); + +/* Cause modules to log their state once */ +void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); /* Cause encoder firmware to be uploaded into the device. This is normally done autonomously, but the interface is exported here because it is also a debugging aid. */ int pvr2_upload_firmware2(struct pvr2_hdw *hdw); +/* List of device types that we can match */ +extern struct usb_device_id pvr2_device_table[]; #endif /* __PVRUSB2_HDW_H */ diff --git a/v4l_experimental/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c index ff8d38063..2d97653d5 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-i2c-chips-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-i2c-chips-v4l2.c,v 1.3 2006/01/22 03:55:03 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -37,6 +37,7 @@ #define OP_FREQ 3 #define OP_AUDIORATE 4 #define OP_SIZE 5 +#define OP_LOG 6 static const struct pvr2_i2c_op * const ops[] = { [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard, @@ -44,6 +45,7 @@ static const struct pvr2_i2c_op * const ops[] = { [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume, [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency, [OP_SIZE] = &pvr2_i2c_op_v4l2_size, + [OP_LOG] = &pvr2_i2c_op_v4l2_log, }; void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) @@ -54,7 +56,8 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) (1 << OP_BCSH) | (1 << OP_VOLUME) | (1 << OP_FREQ) | - (1 << OP_SIZE)); + (1 << OP_SIZE) | + (1 << OP_LOG)); if (id == I2C_DRIVERID_MSP3400) { if (pvr2_i2c_msp3400_setup(hdw,cp)) { diff --git a/v4l_experimental/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c index 92f2dfa6a..69864782b 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-i2c-cmd-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-i2c-cmd-v4l2.c,v 1.1 2006/01/01 08:26:03 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> @@ -218,6 +218,27 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = { }; +static void do_log(struct pvr2_hdw *hdw) +{ + pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()"); + pvr2_i2c_core_cmd(hdw,VIDIOC_LOG_STATUS,0); + +} + + +static int check_log(struct pvr2_hdw *hdw) +{ + return hdw->log_requested != 0; +} + + +const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log = { + .check = check_log, + .update = do_log, + .name = "v4l2_log", +}; + + /* Stuff for Emacs to see, in order to encourage consistent editing style: *** Local Variables: *** diff --git a/v4l_experimental/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h index 8c3945e93..fa0a3af7e 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-i2c-cmd-v4l2.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-i2c-cmd-v4l2.h,v 1.1 2006/01/01 08:26:03 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> @@ -31,6 +31,7 @@ extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size; +extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log; #endif /* __PVRUSB2_CMD_V4L2_H */ diff --git a/v4l_experimental/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index b45463a2d..8ec637e5e 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-i2c-core.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-i2c-core.c,v 1.5 2006/01/23 06:58:06 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -39,19 +39,26 @@ module_param(i2c_scan, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ - u8 i2c_addr, /* I2C address we're talking to */ - u8 *data, /* Data to write */ - u16 length) /* Size of data to write */ + u8 i2c_addr, /* I2C address we're talking to */ + u8 *data, /* Data to write */ + u16 length) /* Size of data to write */ { /* Return value - default 0 means success */ int ret; -#ifdef notdef +#if 0 trace_i2c("pvr2_i2c_write"); #endif if (!data) length = 0; - if (length > (sizeof(hdw->cmd_buffer) - 3)) return -ENOTSUPP; + if (length > (sizeof(hdw->cmd_buffer) - 3)) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Killing an I2C write to %u that is too large" + " (desired=%u limit=%u)", + i2c_addr, + length,(sizeof(hdw->cmd_buffer) - 3)); + return -ENOTSUPP; + } LOCK_TAKE(hdw->ctl_lock); @@ -80,7 +87,7 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ } } } -#ifdef notdef +#if 0 trace_i2c("i2c_write(%d) len=%d ret=%d stat=%d",i2c_addr,length,ret, hdw->cmd_buffer[0]); #endif @@ -91,16 +98,16 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ } static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */ - u8 i2c_addr, /* I2C address we're talking to */ - u8 *data, /* Data to write */ - u16 dlen, /* Size of data to write */ - u8 *res, /* Where to put data we read */ - u16 rlen) /* Amount of data to read */ + u8 i2c_addr, /* I2C address we're talking to */ + u8 *data, /* Data to write */ + u16 dlen, /* Size of data to write */ + u8 *res, /* Where to put data we read */ + u16 rlen) /* Amount of data to read */ { /* Return value - default 0 means success */ int ret; -#ifdef notdef +#if 0 trace_i2c("pvr2_i2c_read"); #endif @@ -138,7 +145,7 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */ } } -#ifdef notdef +#if 0 trace_i2c("i2c_read(%d) wlen=%d rlen=%d ret=%d stat=%d", i2c_addr,dlen,rlen,ret,hdw->cmd_buffer[0]); #endif @@ -160,8 +167,8 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */ /* This is a very, very limited I2C adapter implementation. We can only support what we actually know will work on the device... */ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], - int num) + struct i2c_msg msgs[], + int num) { int ret = -ENOTSUPP; struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data); @@ -282,14 +289,14 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, } static int pvr2_i2c_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { return 0; } static u32 pvr2_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } static int pvr2_i2c_core_singleton(struct i2c_client *cp, @@ -692,7 +699,7 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client) static struct i2c_algorithm pvr2_i2c_algo_template = { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) - .id = I2C_ALGO_BIT | I2C_HW_B_BT848, + .id = I2C_HW_B_BT848, #endif .master_xfer = pvr2_i2c_xfer, .algo_control = pvr2_i2c_control, @@ -702,11 +709,7 @@ static struct i2c_algorithm pvr2_i2c_algo_template = { static struct i2c_adapter pvr2_i2c_adap_template = { .owner = THIS_MODULE, .class = I2C_CLASS_TV_ANALOG, -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) - .id = I2C_ALGO_BIT | I2C_HW_B_BT848, -#else .id = I2C_HW_B_BT848, -#endif .client_register = pvr2_i2c_attach_inform, .client_unregister = pvr2_i2c_detach_inform, }; diff --git a/v4l_experimental/pvrusb2/pvrusb2-i2c-core.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h index 3e8f71962..e8af5b0ed 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-i2c-core.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-i2c-core.h,v 1.1 2006/01/01 08:26:03 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/v4l_experimental/pvrusb2/pvrusb2-io.c b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c index d53c63785..a6bc3befe 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-io.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-io.c,v 1.3 2006/01/23 06:58:06 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -36,7 +36,7 @@ // #define SANITY_CHECK_BUFFERS -#ifdef notdef +#if 0 #define BUFFER_CHECK(bp) do { \ if ((bp)->signature != BUFFER_SIG) { \ pvr2_trace(PVR2_TRACE_ERROR_LEGS, \ @@ -44,7 +44,7 @@ (bp),__FILE__,__LINE__); \ pvr2_buffer_describe(bp,"BadSig"); \ BUG(); \ - } \ + } \ } while (0) #endif @@ -56,7 +56,7 @@ (bp),__FILE__,__LINE__); \ pvr2_buffer_describe(bp,"BadSig"); \ BUG(); \ - } \ + } \ } while (0) #else #define BUFFER_CHECK(bp) do {} while(0) @@ -278,8 +278,8 @@ static void pvr2_buffer_wipe(struct pvr2_buffer *bp) } static int pvr2_buffer_init(struct pvr2_buffer *bp, - struct pvr2_stream *sp, - unsigned int id) + struct pvr2_stream *sp, + unsigned int id) { memset(bp,0,sizeof(*bp)); bp->signature = BUFFER_SIG; @@ -508,8 +508,8 @@ void pvr2_stream_destroy(struct pvr2_stream *sp) } void pvr2_stream_setup(struct pvr2_stream *sp, - struct usb_device *dev, - int endpoint, + struct usb_device *dev, + int endpoint, unsigned int tolerance) { mutex_lock(&sp->mutex); do { @@ -521,8 +521,8 @@ void pvr2_stream_setup(struct pvr2_stream *sp, } void pvr2_stream_set_callback(struct pvr2_stream *sp, - pvr2_stream_callback func, - void *data) + pvr2_stream_callback func, + void *data) { unsigned long irq_flags; mutex_lock(&sp->mutex); do { diff --git a/v4l_experimental/pvrusb2/pvrusb2-io.h b/linux/drivers/media/video/pvrusb2/pvrusb2-io.h index 5dc72b1ef..65e11385b 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-io.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-io.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-io.h,v 1.2 2006/01/09 06:54:46 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -42,11 +42,11 @@ const char *pvr2_buffer_state_decode(enum pvr2_buffer_state); struct pvr2_stream *pvr2_stream_create(void); void pvr2_stream_destroy(struct pvr2_stream *); void pvr2_stream_setup(struct pvr2_stream *, - struct usb_device *dev,int endpoint, + struct usb_device *dev,int endpoint, unsigned int tolerance); void pvr2_stream_set_callback(struct pvr2_stream *, - pvr2_stream_callback func, - void *data); + pvr2_stream_callback func, + void *data); /* Query / set the nominal buffer count */ int pvr2_stream_get_buffer_count(struct pvr2_stream *); diff --git a/v4l_experimental/pvrusb2/pvrusb2-ioread.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c index 375dd8acb..4182d75b7 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-ioread.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-ioread.c,v 1.2 2006/01/23 06:58:06 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/v4l_experimental/pvrusb2/pvrusb2-ioread.h b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h index ec2a23325..e6205f123 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-ioread.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-ioread.h,v 1.1 2005/11/14 13:31:24 mchehab Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/v4l_experimental/pvrusb2/pvrusb2-main.c b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c index 72b5132e6..c554671af 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-main.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-main.c,v 1.7 2006/01/22 03:51:19 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> @@ -62,11 +62,6 @@ MODULE_PARM_DESC(debug, "Debug trace mask"); static struct pvr2_sysfs_class *class_ptr = 0; -static struct usb_device_id pvr_table[] = { - { USB_DEVICE(0x2040, 0x2900) }, - { } -}; - static void pvr_setup_attach(struct pvr2_context *pvr) { /* Create association with v4l layer */ @@ -80,7 +75,7 @@ static int pvr_probe(struct usb_interface *intf, struct pvr2_context *pvr; /* Create underlying hardware interface */ - pvr = pvr2_context_create(intf,pvr_setup_attach); + pvr = pvr2_context_create(intf,devid,pvr_setup_attach); if (!pvr) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Failed to create hdw handler"); @@ -116,7 +111,7 @@ static struct usb_driver pvr_driver = { owner: THIS_MODULE, #endif name: "pvrusb2", - id_table: pvr_table, + id_table: pvr2_device_table, probe: pvr_probe, disconnect: pvr_disconnect }; @@ -166,7 +161,11 @@ static void __exit pvr_exit(void) module_init(pvr_init); module_exit(pvr_exit); -MODULE_DEVICE_TABLE (usb, pvr_table); +/* Mike Isely <mcisely@pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for + MODULE_DEVICE_TABLE(). We have to declare that attribute there + because that's where the device table actually is now and it seems + that certain gcc configurations get angry if MODULE_DEVICE_TABLE() + is used on what ends up being an external symbol. */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/v4l_experimental/pvrusb2/pvrusb2-sysfs.c b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7d17ee749..a9710b52c 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-sysfs.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-sysfs.c,v 1.2 2006/01/22 03:51:19 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -196,7 +196,7 @@ static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) } static int store_val_any(int id,struct pvr2_sysfs *sfp, - const char *buf,unsigned int count) + const char *buf,unsigned int count) { int val,minval,maxval; int ch,ret; @@ -293,7 +293,7 @@ static int store_val_any(int id,struct pvr2_sysfs *sfp, } static int store_val_multi(int id,struct pvr2_sysfs *sfp, - const char *buf,unsigned int count) + const char *buf,unsigned int count) { unsigned int count2; int ret; @@ -311,7 +311,7 @@ static int store_val_multi(int id,struct pvr2_sysfs *sfp, } static ssize_t store_val_int(int id,struct class_device *class_dev, - const char *buf,size_t count) + const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; @@ -322,7 +322,7 @@ static ssize_t store_val_int(int id,struct class_device *class_dev, } static ssize_t store_val_enum(int id,struct class_device *class_dev, - const char *buf,size_t count) + const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; @@ -646,7 +646,7 @@ static ssize_t unit_number_show(struct class_device *class_dev,char *buf) static void class_dev_create(struct pvr2_sysfs *sfp, - struct pvr2_sysfs_class *class_ptr) + struct pvr2_sysfs_class *class_ptr) { struct usb_device *usb_dev; struct class_device *class_dev; @@ -707,7 +707,7 @@ static void pvr2_sysfs_internal_check(struct pvr2_channel *chp) struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, - struct pvr2_sysfs_class *class_ptr) + struct pvr2_sysfs_class *class_ptr) { struct pvr2_sysfs *sfp; sfp = kmalloc(sizeof(*sfp),GFP_KERNEL); @@ -723,7 +723,7 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp, - int numenvp,char *buf,int size) + int numenvp,char *buf,int size) { /* Even though we don't do anything here, we still need this function because sysfs will still try to call it. */ @@ -766,6 +766,7 @@ static ssize_t debuginfo_show(struct class_device *class_dev,char *buf) struct pvr2_sysfs *sfp; sfp = (struct pvr2_sysfs *)class_dev->class_data; if (!sfp) return -EINVAL; + pvr2_hdw_trigger_module_log(sfp->channel.hdw); return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); } @@ -780,7 +781,7 @@ static ssize_t debugcmd_show(struct class_device *class_dev,char *buf) static ssize_t debugcmd_store(struct class_device *class_dev, - const char *buf,size_t count) + const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; diff --git a/v4l_experimental/pvrusb2/pvrusb2-sysfs.h b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h index 20dcc3256..ff9373b47 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-sysfs.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-sysfs.h,v 1.1 2005/11/14 13:31:24 mchehab Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -32,7 +32,7 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void); void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *); struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *, - struct pvr2_sysfs_class *); + struct pvr2_sysfs_class *); #endif /* __PVRUSB2_SYSFS_H */ diff --git a/v4l_experimental/pvrusb2/pvrusb2-tuner.c b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c index 4a6f99177..f829c0acc 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-tuner.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-tuner.c,v 1.12 2006/01/22 03:48:34 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/v4l_experimental/pvrusb2/pvrusb2-tuner.h b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h index 83d92d06d..556f12aa9 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-tuner.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-tuner.h,v 1.2 2006/01/01 08:26:03 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/v4l_experimental/pvrusb2/pvrusb2-util.h b/linux/drivers/media/video/pvrusb2/pvrusb2-util.h index e8c2cc940..e53aee416 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-util.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-util.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-util.h,v 1.1 2005/11/14 13:31:24 mchehab Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -23,18 +23,18 @@ #define PVR2_DECOMPOSE_LE(t,i,d) \ do { \ - (t)[i] = (d) & 0xff;\ - (t)[i+1] = ((d) >> 8) & 0xff;\ - (t)[i+2] = ((d) >> 16) & 0xff;\ - (t)[i+3] = ((d) >> 24) & 0xff;\ + (t)[i] = (d) & 0xff;\ + (t)[i+1] = ((d) >> 8) & 0xff;\ + (t)[i+2] = ((d) >> 16) & 0xff;\ + (t)[i+3] = ((d) >> 24) & 0xff;\ } while(0) #define PVR2_DECOMPOSE_BE(t,i,d) \ do { \ - (t)[i+3] = (d) & 0xff;\ - (t)[i+2] = ((d) >> 8) & 0xff;\ - (t)[i+1] = ((d) >> 16) & 0xff;\ - (t)[i] = ((d) >> 24) & 0xff;\ + (t)[i+3] = (d) & 0xff;\ + (t)[i+2] = ((d) >> 8) & 0xff;\ + (t)[i+1] = ((d) >> 16) & 0xff;\ + (t)[i] = ((d) >> 24) & 0xff;\ } while(0) #define PVR2_COMPOSE_LE(t,i) \ diff --git a/v4l_experimental/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 0a78a6646..017d30ad0 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-v4l2.c,v 1.9 2006/01/23 06:58:06 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> @@ -124,7 +124,7 @@ static struct v4l2_tuner pvr_v4l2_tuners[]= { .afc = 0, .reserved = {0,0,0,0} } -#ifdef notdef +#if 0 { .index = 1, .name = "Radio Tuner", @@ -306,7 +306,7 @@ static int cnv_cid_v4l2_pvr2(int id) return -1; } -#ifdef notdef +#if 0 static int cnv_cid_pvr2_v4l2(int id) { switch (id) { @@ -342,7 +342,7 @@ static int cnv_cid_pvr2_v4l2(int id) * */ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) + unsigned int cmd, void *arg) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_v4l2 *vp = fh->vhead; @@ -839,6 +839,12 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, break; } + case VIDIOC_LOG_STATUS: + { + pvr2_hdw_trigger_module_log(hdw); + break; + } + default : ret = v4l_compat_translate_ioctl(inode,file,cmd, arg,pvr2_v4l2_do_ioctl); @@ -871,8 +877,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) { pvr2_trace(PVR2_TRACE_INIT, - "Unregistering v4l video device (%s, minor=%d)", - pvr2_config_get_name(dip->config),dip->vdev->minor); + "unregistering device video%d [%s]", + dip->vdev->minor,pvr2_config_get_name(dip->config)); video_unregister_device(dip->vdev); } @@ -899,7 +905,7 @@ void pvr2_v4l2_internal_check(struct pvr2_channel *chp) int pvr2_v4l2_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { /* Temporary hack : use ivtv api until a v4l2 one is available. */ @@ -1047,7 +1053,7 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) static ssize_t pvr2_v4l2_read(struct file *file, - char __user *buff, size_t count, loff_t *ppos) + char __user *buff, size_t count, loff_t *ppos) { struct pvr2_v4l2_fh *fh = file->private_data; int ret; @@ -1159,10 +1165,10 @@ static struct video_device vdev_template = { static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, - struct pvr2_v4l2 *vp, - enum pvr2_config cfg) + struct pvr2_v4l2 *vp, + enum pvr2_config cfg) { -#ifdef notdef +#if 0 struct usb_device *usbdev; #endif int mindevnum; @@ -1171,7 +1177,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, dip->v4lp = vp; dip->config = cfg; -#ifdef notdef +#if 0 usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw); #endif @@ -1206,7 +1212,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, } memcpy(dip->vdev,&vdev_template,sizeof(vdev_template)); -#ifdef notdef +#if 0 /* ????? This relation may be problematic on a disconnect. Is this really needed? I can't seem to find a reason for it. This can't be a required thing - what if the video device being set @@ -1226,8 +1232,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, err("Failed to register pvrusb2 v4l video device"); } else { pvr2_trace(PVR2_TRACE_INIT, - "Registered pvrusb2 v4l device, minor=%d", - dip->vdev->minor); + "registered device video%d [%s]", + dip->vdev->minor,pvr2_config_get_name(dip->config)); } pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, dip->vdev->minor); diff --git a/v4l_experimental/pvrusb2/pvrusb2-v4l2.h b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h index 9dd446469..9a995e2d2 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-v4l2.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-v4l2.h,v 1.1 2005/11/14 13:31:24 mchehab Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * diff --git a/v4l_experimental/pvrusb2/pvrusb2-video-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index f4948a7a7..d0bc3682b 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-video-v4l.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-video-v4l.c,v 1.10 2006/01/22 03:48:34 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> @@ -131,7 +131,7 @@ static int decoder_check(struct pvr2_v4l_decoder *ctxt) unsigned long msk; unsigned int idx; - for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]); + for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]); idx++) { msk = 1 << idx; if (ctxt->stale_mask & msk) continue; @@ -148,7 +148,7 @@ static void decoder_update(struct pvr2_v4l_decoder *ctxt) unsigned long msk; unsigned int idx; - for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]); + for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]); idx++) { msk = 1 << idx; if (!(ctxt->stale_mask & msk)) continue; diff --git a/v4l_experimental/pvrusb2/pvrusb2-video-v4l.h b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h index b47e64791..1c0c98efb 100644 --- a/v4l_experimental/pvrusb2/pvrusb2-video-v4l.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2-video-v4l.h,v 1.3 2006/01/14 19:09:50 mcisely Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/v4l_experimental/pvrusb2/pvrusb2.h b/linux/drivers/media/video/pvrusb2/pvrusb2.h index f4e99ad3b..074533e9c 100644 --- a/v4l_experimental/pvrusb2/pvrusb2.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2.h @@ -1,6 +1,6 @@ /* * - * $Id: pvrusb2.h,v 1.1 2005/11/14 13:31:24 mchehab Exp $ + * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> diff --git a/linux/drivers/media/video/saa7134/saa7134-alsa.c b/linux/drivers/media/video/saa7134/saa7134-alsa.c index 5f1f32ecb..8a174f185 100644 --- a/linux/drivers/media/video/saa7134/saa7134-alsa.c +++ b/linux/drivers/media/video/saa7134/saa7134-alsa.c @@ -320,8 +320,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev) static int dsp_buffer_free(struct saa7134_dev *dev) { - if (!dev->dmasound.blksize) - BUG(); + BUG_ON(!dev->dmasound.blksize); videobuf_dma_free(&dev->dmasound.dma); diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index fb804441d..45eef4148 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -538,7 +538,7 @@ struct saa7134_board saa7134_boards[] = { .radio = { .name = name_radio, .amux = LINE2, - }, + }, }, [SAA7134_BOARD_MD7134] = { .name = "Medion 7134", @@ -2030,7 +2030,7 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_FLYTV_DIGIMATRIX] = { .name = "FlyTV mini Asus Digimatrix", .audio_clock = 0x00200000, - .tuner_type = TUNER_LG_NTSC_TALN_MINI, + .tuner_type = TUNER_LG_TALN, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -2708,7 +2708,7 @@ struct saa7134_board saa7134_boards[] = { }}, }, [SAA7134_BOARD_TEVION_DVBT_220RF] = { - .name = "Tevion DVB-T 220RF", + .name = "Tevion/KWorld DVB-T 220RF", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -2758,6 +2758,97 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }}, }, + [SAA7134_BOARD_AVERMEDIA_A169_B] = { + /* AVerMedia A169 */ + /* Rickard Osser <ricky@osser.se> */ + /* This card has two saa7134 chips on it, + but only one of them is currently working. */ + .name = "AVerMedia A169 B", + .audio_clock = 0x02187de7, + .tuner_type = TUNER_LG_TALN, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x0a60000, +#if 0 + .inputs = {{ + .name = name_tv, + .vmux = 4, + .amux = TV, + .tv = 1, + .gpio = 0x00a68300, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_comp2, /* Composite SVIDEO (B/W if signal is carried with SVIDEO) */ + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 9, /* 9 is correct as S-VIDEO according to a169.inf! */ + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x00a68300, + }, +#endif + }, + [SAA7134_BOARD_AVERMEDIA_A169_B1] = { + /* AVerMedia A169 */ + /* Rickard Osser <ricky@osser.se> */ + .name = "AVerMedia A169 B1", + .audio_clock = 0x02187de7, + .tuner_type = TUNER_LG_TALN, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0xca60000, + .inputs = {{ + .name = name_tv, + .vmux = 4, + .amux = TV, + .tv = 1, + .gpio = 0x04a61000, +#if 0 + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, +#endif + },{ + .name = name_comp2, /* Composite SVIDEO (B/W if signal is carried with SVIDEO) */ + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 9, /* 9 is correct as S-VIDEO1 according to a169.inf! */ + .amux = LINE1, + }}, +#if 0 + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x0ca61000, + }, +#endif + }, + [SAA7134_BOARD_MD7134_BRIDGE_2] = { + /* This card has two saa7134 chips on it, + but only one of them is currently working. + The programming for the primary decoder is + in SAA7134_BOARD_MD7134 */ + .name = "Medion 7134 Bridge #2", + .audio_clock = 0x00187de7, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3265,6 +3356,24 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x7350, .driver_data = SAA7134_BOARD_KWORLD_ATSC110, },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1461, + .subdevice = 0x7360, + .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1461, + .subdevice = 0x6360, + .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B1, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x16be, + .subdevice = 0x0005, + .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2, + },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -3407,9 +3516,9 @@ int saa7134_board_init1(struct saa7134_dev *dev) break; case SAA7134_BOARD_MD5044: printk("%s: seems there are two different versions of the MD5044\n" - "%s: (with the same ID) out there. If sound doesn't work for\n" - "%s: you try the audio_clock_override=0x200000 insmod option.\n", - dev->name,dev->name,dev->name); + "%s: (with the same ID) out there. If sound doesn't work for\n" + "%s: you try the audio_clock_override=0x200000 insmod option.\n", + dev->name,dev->name,dev->name); break; case SAA7134_BOARD_CINERGY400_CARDBUS: /* power-up tuner chip */ @@ -3456,6 +3565,13 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_UPMOST_PURPLE_TV: dev->has_remote = SAA7134_REMOTE_I2C; break; + case SAA7134_BOARD_AVERMEDIA_A169_B: + case SAA7134_BOARD_MD7134_BRIDGE_2: + printk("%s: %s: dual saa713x broadcast decoders\n" + "%s: Sorry, none of the inputs to this chip are supported yet.\n" + "%s: Dual decoder functionality is disabled for now, use the other chip.\n", + dev->name,card(dev).name,dev->name,dev->name); + break; } return 0; } diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c index e23c6a42d..53717ff9c 100644 --- a/linux/drivers/media/video/saa7134/saa7134-core.c +++ b/linux/drivers/media/video/saa7134/saa7134-core.c @@ -70,6 +70,11 @@ static unsigned int latency = UNSET; module_param(latency, int, 0444); MODULE_PARM_DESC(latency,"pci latency timer"); +static int no_overlay=-1; +module_param(no_overlay, int, 0444); +MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" + " [some VIA/SIS chipsets are known to have problem with overlay]"); + static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; @@ -316,8 +321,7 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf) { - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma); @@ -906,6 +910,22 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, latency = 0x0A; } #endif + if (pci_pci_problems & PCIPCI_FAIL) { + printk(KERN_INFO "%s: quirk: this driver and your " + "chipset may not work together" + " in overlay mode.\n",dev->name); + if (!no_overlay) { + printk(KERN_INFO "%s: quirk: overlay " + "mode will be disabled.\n", + dev->name); + no_overlay = 1; + } else { + printk(KERN_INFO "%s: quirk: overlay " + "mode will be forced. Use this" + " option at your own risk.\n", + dev->name); + } + } } if (UNSET != latency) { printk(KERN_INFO "%s: setting pci latency timer to %d\n", diff --git a/linux/drivers/media/video/saa7134/saa7134-oss.c b/linux/drivers/media/video/saa7134/saa7134-oss.c index 742692ab2..b57fa81cd 100644 --- a/linux/drivers/media/video/saa7134/saa7134-oss.c +++ b/linux/drivers/media/video/saa7134/saa7134-oss.c @@ -103,8 +103,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev) { int err; - if (!dev->dmasound.bufsize) - BUG(); + BUG_ON(!dev->dmasound.bufsize); videobuf_dma_init(&dev->dmasound.dma); err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); @@ -115,8 +114,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev) static int dsp_buffer_free(struct saa7134_dev *dev) { - if (!dev->dmasound.blksize) - BUG(); + BUG_ON(!dev->dmasound.blksize); videobuf_dma_free(&dev->dmasound.dma); dev->dmasound.blocks = 0; dev->dmasound.blksize = 0; diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c index daab08493..a034776ae 100644 --- a/linux/drivers/media/video/saa7134/saa7134-video.c +++ b/linux/drivers/media/video/saa7134/saa7134-video.c @@ -493,8 +493,7 @@ int res_locked(struct saa7134_dev *dev, unsigned int bit) static void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) { - if ((fh->resources & bits) != bits) - BUG(); + BUG_ON((fh->resources & bits) != bits); mutex_lock(&dev->lock); fh->resources &= ~bits; diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index b72306e59..9666b35c9 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -228,6 +228,9 @@ struct saa7134_format { #define SAA7134_BOARD_TEVION_DVBT_220RF 88 #define SAA7134_BOARD_ELSA_700TV 89 #define SAA7134_BOARD_KWORLD_ATSC110 90 +#define SAA7134_BOARD_AVERMEDIA_A169_B 91 +#define SAA7134_BOARD_AVERMEDIA_A169_B1 92 +#define SAA7134_BOARD_MD7134_BRIDGE_2 93 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 diff --git a/linux/drivers/media/video/tda9840.c b/linux/drivers/media/video/tda9840.c new file mode 100644 index 000000000..9cc13ec8e --- /dev/null +++ b/linux/drivers/media/video/tda9840.c @@ -0,0 +1,263 @@ + /* + tda9840 - i2c-driver for the tda9840 by SGS Thomson + + Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> + + The tda9840 is a stereo/dual sound processor with digital + identification. It can be found at address 0x84 on the i2c-bus. + + For detailed informations download the specifications directly + from SGS Thomson at http://www.st.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "compat.h" + +#include <linux/module.h> +#include <linux/ioctl.h> +#include <linux/i2c.h> + +#include "tda9840.h" + +static int debug = 0; /* insmod parameter */ +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); +#define dprintk(args...) \ + do { if (debug) { printk("%s: %s()[%d]: ",__stringify(KBUILD_MODNAME), __FUNCTION__, __LINE__); printk(args); } } while (0) + +#define SWITCH 0x00 +#define LEVEL_ADJUST 0x02 +#define STEREO_ADJUST 0x03 +#define TEST 0x04 + +/* addresses to scan, found only at 0x42 (7-Bit) */ +static unsigned short normal_i2c[] = { I2C_TDA9840, I2C_CLIENT_END }; + +/* magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +static int command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + int result; + int byte = *(int *)arg; + + switch (cmd) { + case TDA9840_SWITCH: + + dprintk("TDA9840_SWITCH: 0x%02x\n", byte); + + if (byte != TDA9840_SET_MONO + && byte != TDA9840_SET_MUTE + && byte != TDA9840_SET_STEREO + && byte != TDA9840_SET_LANG1 + && byte != TDA9840_SET_LANG2 + && byte != TDA9840_SET_BOTH + && byte != TDA9840_SET_BOTH_R + && byte != TDA9840_SET_EXTERNAL) { + return -EINVAL; + } + + result = i2c_smbus_write_byte_data(client, SWITCH, byte); + if (result) + dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result); + break; + + case TDA9840_LEVEL_ADJUST: + + dprintk("TDA9840_LEVEL_ADJUST: %d\n", byte); + + /* check for correct range */ + if (byte > 25 || byte < -20) + return -EINVAL; + + /* calculate actual value to set, see specs, page 18 */ + byte /= 5; + if (0 < byte) + byte += 0x8; + else + byte = -byte; + + result = i2c_smbus_write_byte_data(client, LEVEL_ADJUST, byte); + if (result) + dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result); + break; + + case TDA9840_STEREO_ADJUST: + + dprintk("TDA9840_STEREO_ADJUST: %d\n", byte); + + /* check for correct range */ + if (byte > 25 || byte < -24) + return -EINVAL; + + /* calculate actual value to set */ + byte /= 5; + if (0 < byte) + byte += 0x20; + else + byte = -byte; + + result = i2c_smbus_write_byte_data(client, STEREO_ADJUST, byte); + if (result) + dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result); + break; + + case TDA9840_DETECT: { + int *ret = (int *)arg; + + byte = i2c_smbus_read_byte_data(client, STEREO_ADJUST); + if (byte == -1) { + dprintk("i2c_smbus_read_byte_data() failed\n"); + return -EIO; + } + + if (0 != (byte & 0x80)) { + dprintk("TDA9840_DETECT: register contents invalid\n"); + return -EINVAL; + } + + dprintk("TDA9840_DETECT: byte: 0x%02x\n", byte); + *ret = ((byte & 0x60) >> 5); + result = 0; + break; + } + case TDA9840_TEST: + dprintk("TDA9840_TEST: 0x%02x\n", byte); + + /* mask out irrelevant bits */ + byte &= 0x3; + + result = i2c_smbus_write_byte_data(client, TEST, byte); + if (result) + dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result); + break; + default: + return -ENOIOCTLCMD; + } + + if (result) + return -EIO; + + return 0; +} + +static int detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + int result = 0; + + int byte = 0x0; + + /* let's see whether this adapter can support what we need */ + if (0 == i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { + return 0; + } + + /* allocate memory for client structure */ + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (0 == client) { + printk("not enough kernel memory\n"); + return -ENOMEM; + } + + /* fill client structure */ + memcpy(client, &client_template, sizeof(struct i2c_client)); + client->addr = address; + client->adapter = adapter; + + /* tell the i2c layer a new client has arrived */ + if (0 != (result = i2c_attach_client(client))) { + kfree(client); + return result; + } + + /* set initial values for level & stereo - adjustment, mode */ + byte = 0; + result = command(client, TDA9840_LEVEL_ADJUST, &byte); + result += command(client, TDA9840_STEREO_ADJUST, &byte); + byte = TDA9840_SET_MONO; + result = command(client, TDA9840_SWITCH, &byte); + if (result) { + dprintk("could not initialize tda9840\n"); + return -ENODEV; + } + + printk("tda9840: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]); + return 0; +} + +static int attach(struct i2c_adapter *adapter) +{ + /* let's see whether this is a know adapter we can attach to */ + if (adapter->id != I2C_HW_SAA7146) { + dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); + return -ENODEV; + } + + return i2c_probe(adapter, &addr_data, &detect); +} + +static int detach(struct i2c_client *client) +{ + int ret = i2c_detach_client(client); + kfree(client); + return ret; +} + +static struct i2c_driver driver = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) &&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)) + .owner = THIS_MODULE, +#endif +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) + .name = "tda9840", + .flags = I2C_DF_NOTIFY, +#else + .driver = { + .name = "tda9840", + }, +#endif + .id = I2C_DRIVERID_TDA9840, + .attach_adapter = attach, + .detach_client = detach, + .command = command, +}; + +static struct i2c_client client_template = { + .name = "tda9840", + .driver = &driver, +}; + +static int __init this_module_init(void) +{ + return i2c_add_driver(&driver); +} + +static void __exit this_module_exit(void) +{ + i2c_del_driver(&driver); +} + +module_init(this_module_init); +module_exit(this_module_exit); + +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_DESCRIPTION("tda9840 driver"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/tda9840.h b/linux/drivers/media/video/tda9840.h new file mode 100644 index 000000000..28021053b --- /dev/null +++ b/linux/drivers/media/video/tda9840.h @@ -0,0 +1,35 @@ +#ifndef __INCLUDED_TDA9840__ +#define __INCLUDED_TDA9840__ + +#define I2C_TDA9840 0x42 + +#define TDA9840_DETECT _IOR('v',1,int) +/* return values for TDA9840_DETCT */ +#define TDA9840_MONO_DETECT 0x0 +#define TDA9840_DUAL_DETECT 0x1 +#define TDA9840_STEREO_DETECT 0x2 +#define TDA9840_INCORRECT_DETECT 0x3 + +#define TDA9840_SWITCH _IOW('v',2,int) +/* modes than can be set with TDA9840_SWITCH */ +#define TDA9840_SET_MUTE 0x00 +#define TDA9840_SET_MONO 0x10 +#define TDA9840_SET_STEREO 0x2a +#define TDA9840_SET_LANG1 0x12 +#define TDA9840_SET_LANG2 0x1e +#define TDA9840_SET_BOTH 0x1a +#define TDA9840_SET_BOTH_R 0x16 +#define TDA9840_SET_EXTERNAL 0x7a + +/* values may range between +2.5 and -2.0; + the value has to be multiplied with 10 */ +#define TDA9840_LEVEL_ADJUST _IOW('v',3,int) + +/* values may range between +2.5 and -2.4; + the value has to be multiplied with 10 */ +#define TDA9840_STEREO_ADJUST _IOW('v',4,int) + +/* currently not implemented */ +#define TDA9840_TEST _IOW('v',5,int) + +#endif diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c new file mode 100644 index 000000000..12e83ad21 --- /dev/null +++ b/linux/drivers/media/video/tea6415c.c @@ -0,0 +1,232 @@ + /* + tea6415c - i2c-driver for the tea6415c by SGS Thomson + + Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> + + The tea6415c is a bus controlled video-matrix-switch + with 8 inputs and 6 outputs. + It is cascadable, i.e. it can be found at the addresses + 0x86 and 0x06 on the i2c-bus. + + For detailed informations download the specifications directly + from SGS Thomson at http://www.st.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License vs published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA. + */ + +#include "compat.h" + +#include <linux/module.h> +#include <linux/ioctl.h> +#include <linux/i2c.h> + +#include "tea6415c.h" + +static int debug = 0; /* insmod parameter */ +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); +#define dprintk(args...) \ + do { if (debug) { printk("%s: %s()[%d]: ",__stringify(KBUILD_MODNAME), __FUNCTION__, __LINE__); printk(args); } } while (0) + +#define TEA6415C_NUM_INPUTS 8 +#define TEA6415C_NUM_OUTPUTS 6 + +/* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */ +static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END }; + +/* magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +/* this function is called by i2c_probe */ +static int detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client = NULL; + int err = 0; + + /* let's see whether this adapter can support what we need */ + if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) { + return 0; + } + + /* allocate memory for client structure */ + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (0 == client) { + return -ENOMEM; + } + + /* fill client structure */ + memcpy(client, &client_template, sizeof(struct i2c_client)); + client->addr = address; + client->adapter = adapter; + + /* tell the i2c layer a new client has arrived */ + if (0 != (err = i2c_attach_client(client))) { + kfree(client); + return err; + } + + printk("tea6415c: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]); + + return 0; +} + +static int attach(struct i2c_adapter *adapter) +{ + /* let's see whether this is a know adapter we can attach to */ + if (adapter->id != I2C_HW_SAA7146) { + dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); + return -ENODEV; + } + + return i2c_probe(adapter, &addr_data, &detect); +} + +static int detach(struct i2c_client *client) +{ + int ret = i2c_detach_client(client); + kfree(client); + return ret; +} + +/* makes a connection between the input-pin 'i' and the output-pin 'o' + for the tea6415c-client 'client' */ +static int switch_matrix(struct i2c_client *client, int i, int o) +{ + u8 byte = 0; + int ret; + + dprintk("adr:0x%02x, i:%d, o:%d\n", client->addr, i, o); + + /* check if the pins are valid */ + if (0 == ((1 == i || 3 == i || 5 == i || 6 == i || 8 == i || 10 == i || 20 == i || 11 == i) + && (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o))) + return -1; + + /* to understand this, have a look at the tea6415c-specs (p.5) */ + switch (o) { + case 18: + byte = 0x00; + break; + case 14: + byte = 0x20; + break; + case 16: + byte = 0x10; + break; + case 17: + byte = 0x08; + break; + case 15: + byte = 0x18; + break; + case 13: + byte = 0x28; + break; + }; + + switch (i) { + case 5: + byte |= 0x00; + break; + case 8: + byte |= 0x04; + break; + case 3: + byte |= 0x02; + break; + case 20: + byte |= 0x06; + break; + case 6: + byte |= 0x01; + break; + case 10: + byte |= 0x05; + break; + case 1: + byte |= 0x03; + break; + case 11: + byte |= 0x07; + break; + }; + + ret = i2c_smbus_write_byte(client, byte); + if (ret) { + dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret); + return -EIO; + } + + return ret; +} + +static int command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg; + int result = 0; + + switch (cmd) { + case TEA6415C_SWITCH: + result = switch_matrix(client, v->in, v->out); + break; + default: + return -ENOIOCTLCMD; + } + + return result; +} + +static struct i2c_driver driver = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) &&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)) + .owner = THIS_MODULE, +#endif +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) + .name = "tea6415c", + .flags = I2C_DF_NOTIFY, +#else + .driver = { + .name = "tea6415c", + }, +#endif + .id = I2C_DRIVERID_TEA6415C, + .attach_adapter = attach, + .detach_client = detach, + .command = command, +}; + +static struct i2c_client client_template = { + .name = "tea6415c", + .driver = &driver, +}; + +static int __init this_module_init(void) +{ + return i2c_add_driver(&driver); +} + +static void __exit this_module_exit(void) +{ + i2c_del_driver(&driver); +} + +module_init(this_module_init); +module_exit(this_module_exit); + +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_DESCRIPTION("tea6415c driver"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/tea6415c.h b/linux/drivers/media/video/tea6415c.h new file mode 100644 index 000000000..f84ed8005 --- /dev/null +++ b/linux/drivers/media/video/tea6415c.h @@ -0,0 +1,39 @@ +#ifndef __INCLUDED_TEA6415C__ +#define __INCLUDED_TEA6415C__ + +/* possible i2c-addresses */ +#define I2C_TEA6415C_1 0x03 +#define I2C_TEA6415C_2 0x43 + +/* the tea6415c's design is quite brain-dead. although there are + 8 inputs and 6 outputs, these aren't enumerated in any way. because + I don't want to say "connect input pin 20 to output pin 17", I define + a "virtual" pin-order. */ + +/* input pins */ +#define TEA6415C_OUTPUT1 18 +#define TEA6415C_OUTPUT2 14 +#define TEA6415C_OUTPUT3 16 +#define TEA6415C_OUTPUT4 17 +#define TEA6415C_OUTPUT5 13 +#define TEA6415C_OUTPUT6 15 + +/* output pins */ +#define TEA6415C_INPUT1 5 +#define TEA6415C_INPUT2 8 +#define TEA6415C_INPUT3 3 +#define TEA6415C_INPUT4 20 +#define TEA6415C_INPUT5 6 +#define TEA6415C_INPUT6 10 +#define TEA6415C_INPUT7 1 +#define TEA6415C_INPUT8 11 + +struct tea6415c_multiplex +{ + int in; /* input-pin */ + int out; /* output-pin */ +}; + +#define TEA6415C_SWITCH _IOW('v',1,struct tea6415c_multiplex) + +#endif diff --git a/linux/drivers/media/video/tea6420.c b/linux/drivers/media/video/tea6420.c new file mode 100644 index 000000000..d22eac01b --- /dev/null +++ b/linux/drivers/media/video/tea6420.c @@ -0,0 +1,209 @@ + /* + tea6420 - i2c-driver for the tea6420 by SGS Thomson + + Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> + + The tea6420 is a bus controlled audio-matrix with 5 stereo inputs, + 4 stereo outputs and gain control for each output. + It is cascadable, i.e. it can be found at the adresses 0x98 + and 0x9a on the i2c-bus. + + For detailed informations download the specifications directly + from SGS Thomson at http://www.st.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "compat.h" + +#include <linux/module.h> +#include <linux/ioctl.h> +#include <linux/i2c.h> + +#include "tea6420.h" + +static int debug = 0; /* insmod parameter */ +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); +#define dprintk(args...) \ + do { if (debug) { printk("%s: %s()[%d]: ",__stringify(KBUILD_MODNAME), __FUNCTION__, __LINE__); printk(args); } } while (0) + +/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */ +static unsigned short normal_i2c[] = { I2C_TEA6420_1, I2C_TEA6420_2, I2C_CLIENT_END }; + +/* magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +/* make a connection between the input 'i' and the output 'o' + with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */ +static int tea6420_switch(struct i2c_client *client, int i, int o, int g) +{ + u8 byte = 0; + int ret; + + dprintk("adr:0x%02x, i:%d, o:%d, g:%d\n", client->addr, i, o, g); + + /* check if the paramters are valid */ + if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0) + return -1; + + byte = ((o - 1) << 5); + byte |= (i - 1); + + /* to understand this, have a look at the tea6420-specs (p.5) */ + switch (g) { + case 0: + byte |= (3 << 3); + break; + case 2: + byte |= (2 << 3); + break; + case 4: + byte |= (1 << 3); + break; + case 6: + break; + } + + ret = i2c_smbus_write_byte(client, byte); + if (ret) { + dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret); + return -EIO; + } + + return 0; +} + +/* this function is called by i2c_probe */ +static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + int err = 0, i = 0; + + /* let's see whether this adapter can support what we need */ + if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) { + return 0; + } + + /* allocate memory for client structure */ + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (0 == client) { + return -ENOMEM; + } + memset(client, 0x0, sizeof(struct i2c_client)); + + /* fill client structure */ + memcpy(client, &client_template, sizeof(struct i2c_client)); + client->addr = address; + client->adapter = adapter; + + /* tell the i2c layer a new client has arrived */ + if (0 != (err = i2c_attach_client(client))) { + kfree(client); + return err; + } + + /* set initial values: set "mute"-input to all outputs at gain 0 */ + err = 0; + for (i = 1; i < 5; i++) { + err += tea6420_switch(client, 6, i, 0); + } + if (err) { + dprintk("could not initialize tea6420\n"); + kfree(client); + return -ENODEV; + } + + printk("tea6420: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]); + + return 0; +} + +static int attach(struct i2c_adapter *adapter) +{ + /* let's see whether this is a know adapter we can attach to */ + if (adapter->id != I2C_HW_SAA7146) { + dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); + return -ENODEV; + } + + return i2c_probe(adapter, &addr_data, &tea6420_detect); +} + +static int detach(struct i2c_client *client) +{ + int ret = i2c_detach_client(client); + kfree(client); + return ret; +} + +static int command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg; + int result = 0; + + switch (cmd) { + case TEA6420_SWITCH: + result = tea6420_switch(client, a->in, a->out, a->gain); + break; + default: + return -ENOIOCTLCMD; + } + + return result; +} + +static struct i2c_driver driver = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) &&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)) + .owner = THIS_MODULE, +#endif +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) + .name = "tea6420", + .flags = I2C_DF_NOTIFY, +#else + .driver = { + .name = "tea6420", + }, +#endif + .id = I2C_DRIVERID_TEA6420, + .attach_adapter = attach, + .detach_client = detach, + .command = command, +}; + +static struct i2c_client client_template = { + .name = "tea6420", + .driver = &driver, +}; + +static int __init this_module_init(void) +{ + return i2c_add_driver(&driver); +} + +static void __exit this_module_exit(void) +{ + i2c_del_driver(&driver); +} + +module_init(this_module_init); +module_exit(this_module_exit); + +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_DESCRIPTION("tea6420 driver"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/tea6420.h b/linux/drivers/media/video/tea6420.h new file mode 100644 index 000000000..ea664df15 --- /dev/null +++ b/linux/drivers/media/video/tea6420.h @@ -0,0 +1,17 @@ +#ifndef __INCLUDED_TEA6420__ +#define __INCLUDED_TEA6420__ + +/* possible addresses */ +#define I2C_TEA6420_1 0x4c +#define I2C_TEA6420_2 0x4d + +struct tea6420_multiplex +{ + int in; /* input of audio switch */ + int out; /* output of audio switch */ + int gain; /* gain of connection */ +}; + +#define TEA6420_SWITCH _IOW('v',1,struct tea6420_multiplex) + +#endif diff --git a/linux/drivers/media/video/tuner-simple.c b/linux/drivers/media/video/tuner-simple.c index e6e808259..57db5b1aa 100644 --- a/linux/drivers/media/video/tuner-simple.c +++ b/linux/drivers/media/video/tuner-simple.c @@ -390,6 +390,9 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) case TUNER_PHILIPS_FMD1216ME_MK3: buffer[3] = 0x19; break; + case TUNER_TNF_5335MF: + buffer[3] = 0x11; + break; case TUNER_PHILIPS_FM1256_IH3: div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ buffer[3] = 0x19; diff --git a/linux/drivers/media/video/tuner-types.c b/linux/drivers/media/video/tuner-types.c index c56ded3ec..560879ce9 100644 --- a/linux/drivers/media/video/tuner-types.c +++ b/linux/drivers/media/video/tuner-types.c @@ -941,17 +941,27 @@ static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = { /* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */ -static struct tuner_range tuner_lg_taln_mini_ntsc_ranges[] = { +static struct tuner_range tuner_lg_taln_ntsc_ranges[] = { { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, { 16 * 373.25 /*MHz*/, 0x8e, 0x02, }, { 16 * 999.99 , 0x8e, 0x08, }, }; -static struct tuner_params tuner_lg_taln_mini_params[] = { +static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = { + { 16 * 150.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 425.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_lg_taln_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_taln_mini_ntsc_ranges, - .count = ARRAY_SIZE(tuner_lg_taln_mini_ntsc_ranges), + .ranges = tuner_lg_taln_ntsc_ranges, + .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges), + },{ + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_taln_pal_secam_ranges, + .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges), }, }; @@ -999,12 +1009,22 @@ static struct tuner_params tuner_tuv1236d_params[] = { #endif }; -/* ------------ TUNER_TNF_5335MF - Philips NTSC ------------ */ +/* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */ +/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF + * but it is expected to work also with other Tenna/Ymec + * models based on TI SN 761677 chip on both PAL and NTSC + */ + +static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 471.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, + { 16 * 169.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 469.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, }; static struct tuner_params tuner_tnf_5335mf_params[] = { @@ -1013,6 +1033,11 @@ static struct tuner_params tuner_tnf_5335mf_params[] = { .ranges = tuner_tnf_5335mf_ntsc_ranges, .count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges), }, + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tnf_5335_d_if_pal_ranges, + .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges), + }, }; /* 70-79 */ @@ -1388,10 +1413,10 @@ struct tunertype tuners[] = { .params = tuner_ymec_tvf66t5_b_dff_params, .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params), }, - [TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */ - .name = "LG NTSC (TALN mini series)", - .params = tuner_lg_taln_mini_params, - .count = ARRAY_SIZE(tuner_lg_taln_mini_params), + [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */ + .name = "LG TALN series", + .params = tuner_lg_taln_params, + .count = ARRAY_SIZE(tuner_lg_taln_params), }, [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ .name = "Philips TD1316 Hybrid Tuner", @@ -1403,8 +1428,8 @@ struct tunertype tuners[] = { .params = tuner_tuv1236d_params, .count = ARRAY_SIZE(tuner_tuv1236d_params), }, - [TUNER_TNF_5335MF] = { /* Philips NTSC */ - .name = "Tena TNF 5335 MF", + [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */ + .name = "Tena TNF 5335 and similar models", .params = tuner_tnf_5335mf_params, .count = ARRAY_SIZE(tuner_tnf_5335mf_params), }, @@ -1422,6 +1447,7 @@ struct tunertype tuners[] = { [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ .name = "Thomson FE6600", .params = tuner_thomson_fe6600_params, + .count = ARRAY_SIZE(tuner_thomson_fe6600_params), }, }; diff --git a/linux/drivers/media/video/video-buf.c b/linux/drivers/media/video/video-buf.c index c4e2c58a2..4a83c6943 100644 --- a/linux/drivers/media/video/video-buf.c +++ b/linux/drivers/media/video/video-buf.c @@ -61,8 +61,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) pg = vmalloc_to_page(virt); if (NULL == pg) goto err; - if (PageHighMem(pg)) - BUG(); + BUG_ON(PageHighMem(pg)); sglist[i].page = pg; sglist[i].length = PAGE_SIZE; } diff --git a/linux/include/linux/dvb/video.h b/linux/include/linux/dvb/video.h index 1f7fa0351..faebfda39 100644 --- a/linux/include/linux/dvb/video.h +++ b/linux/include/linux/dvb/video.h @@ -135,7 +135,7 @@ typedef struct video_spu { typedef struct video_spu_palette { /* SPU Palette information */ int length; - uint8_t *palette; + uint8_t __user *palette; } video_spu_palette_t; diff --git a/linux/include/linux/videodev2.h b/linux/include/linux/videodev2.h index 1b76d3e9a..2995bf836 100644 --- a/linux/include/linux/videodev2.h +++ b/linux/include/linux/videodev2.h @@ -592,7 +592,7 @@ struct v4l2_framebuffer struct v4l2_clip { struct v4l2_rect c; - struct v4l2_clip *next; + struct v4l2_clip __user *next; }; struct v4l2_window diff --git a/linux/include/media/tuner.h b/linux/include/media/tuner.h index c18cac6c8..a5471fa67 100644 --- a/linux/include/media/tuner.h +++ b/linux/include/media/tuner.h @@ -111,7 +111,7 @@ #define TUNER_LG_TDVS_H062F 64 /* DViCO FusionHDTV 5 */ #define TUNER_YMEC_TVF66T5_B_DFF 65 /* Acorp Y878F */ -#define TUNER_LG_NTSC_TALN_MINI 66 +#define TUNER_LG_TALN 66 #define TUNER_PHILIPS_TD1316 67 #define TUNER_PHILIPS_TUV1236D 68 /* ATI HDTV Wonder */ diff --git a/mailimport b/mailimport new file mode 100755 index 000000000..e6e4df411 --- /dev/null +++ b/mailimport @@ -0,0 +1,167 @@ +#!/bin/bash +# Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) +# This code is placed under the terms of the GNU General Public License +# +#This script is capable to mass import patches on a mbox file, test for it, allow +#comment editing and applying it. +# +#This script requires: +#1) git, since it uses gitimport to break a mbox into patches; +#2) hg mailqueue. It is easier to manage patches using mq, allowing to work with +# the patches before applying to the tree. + +#uncomment to use mq +#usemq=1 + +#uncomment to stop at the first error while testing a patch with --dry-run +#exitonerror=1 + +head=v4l/scripts/hghead.pl + +if [ "$1" == "" ]; then + echo "Usage: $0 <mbox>" + exit +fi +MBOX=$1 + +if [ "$TMPDIR" == "" ]; then + TMPDIR=/tmp +fi + +if [ "$EDITOR" == "" ]; then + EDITOR=nano +fi + +DIR=$TMPDIR/mailimport$$ +mkdir $DIR +if [ "$?" != "0" ]; then + echo "*** Error at mkdir $DIR" + exit; +fi +trap "rm -rf $DIR" EXIT +TMP2=$DIR/patchheader + +apply_patch () { + next=$1 + + unset cont + until [ "$cont" == "0" ]; do + cont=1 + pdir=linux + echo patch -s -t -p1 --dry-run -l -N -d $pdir -i $next + patch -s -t -p1 --dry-run -l -N -d $pdir -i $next + if [ "$?" != "0" ]; then + pdir=. + echo patch -s -t -p1 --dry-run -l -N -d $pdir -i $next + patch -s -t -p1 --dry-run -l -N -d $pdir -i $next + fi + + if [ "$?" != "0" ]; then + echo "*** ERROR: Patch didn't applied well" + if [ "$exitonerror" != "" ]; then + $head $next + exit + fi + echo "** Edit file $next" + sleep 1 + $EDITOR $next + else + echo "Patch applied OK against $pdir" + cont=0 + fi + done + + $EDITOR $next + + unset cont + until [ "$cont" == "0" ]; do + cont=0 + $head $next >$TMP2 + + if [ "`grep '^Bad:' $TMP2`" != "" ]; then + echo "*** ERROR: Patch bad formed. Please fix." + sleep 1 + $EDITOR $next + cont=1 + fi + done + + make whitespace + + committer=`grep "Committer:" $TMP2|sed s/"#Committer: "//` + + if [ "$usemq" != "" ]; then + name=`cat $next | perl -ne ' + if (s/Subject:\s+(.*)/$1/) { + m/\s*(.*)\s*\n/; + $_="$1"; + + tr/[A-Z]/[a-z]/; + s/[^a-z0-9]/_/g; + s/_+$//; + s/_+/_/g; + s/^v4l_dvb_\d+[a-z]*_//g; + + printf "%s.patch",$_; + exit; + }'` + + cat $next| grep -v "^#" >$TMPDIR/$name + + echo hg -m "`cat $TMP2|grep -v "^#"`" qnew $name + hg qnew -m "`cat $TMP2|grep -v "^#"`" $name + hg qrefresh + else + patch -s -t -p1 -l -N -d $pdir -i $next + if [ "$?" != "0" ]; then + echo "*** ERROR at: patch -s -t -p1 -l -N -d $pdir -i $next" + exit + fi + cur=`pwd` + cd $pdir + hg addremove `diffstat -p1 -l $next` + if [ "$?" != "0" ]; then + echo "*** ERROR at hg addremove" + exit + fi + # Commit the changed files + hg commit -u "$committer" -m "`cat $TMP2|grep -v "^#"`" `diffstat -p1 -l $next` + if [ "$?" != "0" ]; then + echo "*** ERROR at hg commit" + cd $cur + exit + fi + cd $cur + fi +} + +echo git-mailsplit $MBOX $DIR +echo -n "Number of patches at file: " +git-mailsplit $MBOX $DIR +echo + +for i in $DIR/*; do + cat $i| git-mailinfo $DIR/msg $DIR/patch>$DIR/author + cat $DIR/msg|grep -vi ^CC: >$DIR/msg2 + + cat $DIR/author|perl -ne "if (m/Author[:]\\s*(.*)\\n/) { \$auth=\$1; } else \ + { if (m/Email[:]\\s*(.*)\\n/) { print \"From: \$auth \<\$1\>\n\"; } else \ + { if (m/Subject[:]\\s*(.*)\\n/) { \ + \$sub=\$1; \ + \$sub=~ s;^(media|dvb|v4l|video|drivers|[-_/: \\t])*(.*);\$2;; \ + print \"Subject: \$sub\\n\"; \ + } else \ + { print; } } \ + }" >$DIR/author2 + + out=$DIR/patch.diff + + cat $DIR/author2 + + echo "Signed-off-by: $CHANGE_LOG_NAME <$CHANGE_LOG_EMAIL_ADDRESS>" >>$DIR/msg2 + + echo "cat $DIR/author2 $DIR/msg2 $DIR/patch >$out" + cat $DIR/author2 $DIR/msg2 $DIR/patch >$out + + apply_patch $out +done diff --git a/v4l/Make.config b/v4l/Make.config index 1c89d0fa1..89a4f0050 100644 --- a/v4l/Make.config +++ b/v4l/Make.config @@ -19,13 +19,17 @@ CONFIG_VIDEO_ALSA := y CONFIG_VIDEO_ADV_DEBUG := y -CONFIG_VIDEO_PVRUSB2 := n +CONFIG_VIDEO_PVRUSB2 := m CONFIG_VIDEO_IVTV := n CONFIG_DVB_FIRESAT := n -CONFIG_VIDEO_CPIA2 := m +CONFIG_VIDEO_CPIA2 := m + +CONFIG_VIDEO_CX88_IVTV := n + +CONFIG_VIDEO_MXB := m # doesn't build on older kernels @@ -111,4 +115,4 @@ ifeq ($(CONFIG_DVB_CORE),m) endif CONFIG_VIDEO_IVTV := $(if $(wildcard $(src)/ivtv-svnversion.h),m) -CONFIG_VIDEO_PVRUSB2 := $(if $(wildcard $(src)/.pvrusb2-merge),m) +CONFIG_VIDEO_CX88_IVTV := $(if $(wildcard $(src)/cx88-ivtv.c),m) diff --git a/v4l/Makefile b/v4l/Makefile index 426851c60..f04195162 100644 --- a/v4l/Makefile +++ b/v4l/Makefile @@ -88,9 +88,14 @@ ifeq ($(CONFIG_VIDEO_DEV),m) obj-m += videodev.o endif +obj-$(CONFIG_VIDEO_MXB) += mxb.o tea6420.o tea6415c.o tda9840.o +obj-$(CONFIG_VIDEO_DPC) += dpc7146.o +obj-$(CONFIG_VIDEO_HEXIUM_ORION)+= hexium_orion.o +obj-$(CONFIG_VIDEO_HEXIUM_GEMINI)+= hexium_gemini.o obj-$(CONFIG_VIDEO_BTTV) += btcx-risc.o ir-common.o bttv.o tveeprom.o obj-$(CONFIG_VIDEO_CX88) += btcx-risc.o cx88xx.o cx8800.o cx8802.o \ cx88-blackbird.o tveeprom.o +obj-$(CONFIG_VIDEO_CX88_IVTV) += cx88-ivtv.o obj-$(CONFIG_TVP5150) += tvp5150.o obj-$(CONFIG_EM28XX) += em28xx.o tveeprom.o obj-$(CONFIG_VIDEO_DECODER) += saa7115.o cx25840.o saa7127.o bt832.o @@ -310,8 +315,8 @@ endif inst_video += ir-kbd-i2c.ko msp3400.ko inst_video += tvp5150.ko saa7134-alsa.ko saa7134-oss.ko inst_video += saa7115.ko cx25840.ko saa7127.ko compat_ioctl32.ko -inst_cx88 := cx8800.ko cx8802.ko cx88-alsa.ko -inst_cx88 += cx88-blackbird.ko cx88xx.ko cx88-dvb.ko cx88-vp3054-i2c.ko +inst_cx88 := cx88xx.ko cx8800.ko cx8802.ko cx88-alsa.ko cx88-dvb.ko +inst_cx88 += cx88-blackbird.ko cx88-vp3054-i2c.ko cx88-ivtv.ko inst_saa7134 := saa6752hs.ko saa7134.ko saa7134-empress.ko saa7134-dvb.ko inst_em28xx := em28xx.ko inst_bt8xx := bt878.ko dvb-bt8xx.ko dst.ko dst_ca.ko @@ -354,11 +359,6 @@ qconfig:: links .version ./scripts/make_kconfig.pl /usr/src/linux-2.6.14 $(ARCH) $(KDIR)/scripts/kconfig/qconf Kconfig -pvrusb2:: - @echo creating pvrusb2 symbolic links... - @find ../v4l_experimental/pvrusb2 -name '*.[ch]' -type f -exec ln -sf '{}' . \; - @echo 'm' > .pvrusb2-merge - ivtv-checkout:: @if [ ! -d ivtv ]; then \ echo retrieving the latest ivtv sources from ivtvdriver.org; \ @@ -378,6 +378,10 @@ ivtv:: ivtv-links @echo '#define IVTV_DRIVER_VERSION_COMMENT "(v4l-dvb + ivtv virtual merge)"' > ivtv-svnversion.h @echo ivtv trunk merged. Run make to build the entire tree. +cx88-ivtv:: + @echo creating cx88-ivtv symbolic links... + @ln -sf ../v4l_experimental/cx88-ivtv.c . + links:: @echo creating symbolic links... @find ../linux/drivers/media -name '*.[ch]' -type f -exec ln -sf '{}' . \; @@ -533,7 +537,7 @@ clean:: @find . -name '*.c' -type l -exec rm '{}' \; @find . -name '*.h' -type l -exec rm '{}' \; -rm -f *~ *.o *.ko .*.o.cmd .*.ko.cmd *.mod.c av7110_firm.h fdump \ - ivtv-svnversion.h .pvrusb2-merge \ + ivtv-svnversion.h \ Kconfig Kconfig.kern .config .config.cmd distclean:: clean diff --git a/v4l/scripts/hghead.pl b/v4l/scripts/hghead.pl new file mode 100755 index 000000000..ddaef0767 --- /dev/null +++ b/v4l/scripts/hghead.pl @@ -0,0 +1,152 @@ +#!/usr/bin/perl +use strict; +use Date::Parse; + +################################################################# +# analyse diffs + +my $in = shift; +my $line; +my $subject; +my $from=0; +my $sub_ok=0; +my $init=0; +my $num=0; +my $maint_ok=0; +my $noblank=1; +my $maintainer_name=$ENV{CHANGE_LOG_NAME}; +my $maintainer_email=$ENV{CHANGE_LOG_EMAIL_ADDRESS}; +my $from=""; +my $body=""; +my $signed=""; +my $fromname=""; + +open IN, "<$in"; + +while ($line = <IN>) { + if ($line =~ m/Index.*/) { + last; + } + if ($line =~ m/^diff .*/) { + last; + } + if ($line =~ m/^\-\-\- .*/) { + last; + } + if ($line =~ m/^\-\-\-.*/) { + last; + } + if ($line =~ m/^\+\+\+ .*/) { + last; + } + + if ($line =~ m/^Date:\s*(.*)/) { + my $time = str2time($1); +# my $timestr = gmtime($time); + + if ($time) { + print "# Date: $time\n"; + } + next; + } + if ($line =~ m/^From:/) { + if ($line =~ m/^From:[\s\"]*([^\"]*)[\s\"]*<(.*)>/) { + if ($1 eq "") { + next; + } + my $name=$1; + my $email=$2; + $name =~ s/\s+$//; + $email =~ s/\s+$//; + $fromname="$name <$email>"; + $from= "From: $fromname\n"; + next; + } + print "Bad: author line have a wrong syntax\n"; + die; + } + + if ($line =~ m/^Subject:\s*(.*\n)/) { + $subject=$1; + next; + } + + if ($line =~ m;^ .*\/.*\| *[0-9]*;) { + next; + } + if ($line =~m/\d+\s*file.* changed, /) { + next; + } + + if ($line =~ m/^Signed-off-by:.*/) { + $noblank=1; + if ($line =~ m/$maintainer_name/) { + $maint_ok=1; + } + + $signed="$signed$line"; + next; + } + if ($line =~ m/^Acked-by:.*/) { + $signed="$signed$line"; + next; + } + + if ($line =~ m/^[a-zA-Z\-]*:/) { + if ($line =~ m/Changeset:\s*(.*)\n/) { + $num=$1; + } + print "# $line"; + next; + } + + if ($line =~ m|^(V4L\/DVB\s*\(.+\)\s*:.*\n)|) { + $subject=$1; + $line="\n"; + } + + if ($sub_ok == 0) { + $sub_ok=1; + substr( $subject, 0, 1 ) = uc (substr ($subject, 0, 1)); + if ($subject =~ m|V4L\/DVB\s*(.+)|) { + $subject=$1; + } + if ($line =~ m/^\n/) { + next; + } + } + + if ($noblank) { + if ($line =~ m/^\n/) { + next; + } + } + if (!$init) { + $init=1; + $noblank=0; + } + $body="$body$line"; +} +close IN; + +if ($from eq "") { + print "Bad: author doesn't exist!\n"; + die; +} + +if (!$maint_ok) { + $signed=$signed."Signed-off-by: $maintainer_name <$maintainer_email>\n"; +} + +if (!$signed =~ m/$from/) { + print "Bad: Author didn't signed his patch!\n"; + die; +} + +$body=~s/\n+$//; +$body=~s/^\n+$//; + +# First from is used by hg to recognize commiter name +print "#Committer: $maintainer_name <$maintainer_email>\n"; +print "$subject\n$from\n$body\n\n$signed"; + diff --git a/v4l_experimental/cx88-ivtv.c b/v4l_experimental/cx88-ivtv.c index c28c1d413..a747e2372 100644 --- a/v4l_experimental/cx88-ivtv.c +++ b/v4l_experimental/cx88-ivtv.c @@ -25,8 +25,8 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> - #include "compat.h" +#include <media/v4l2-common.h> #include "cx88.h" MODULE_DESCRIPTION("ivtv ioctl emulation module for blackbird TV cards"); @@ -111,10 +111,10 @@ static int ivtv_do_ioctl(struct inode *inode, struct file *file, /* int err; */ if (debug > 1) - cx88_print_ioctl(dev->core->name,cmd); + v4l_print_ioctl(dev->core->name,cmd); #if 1 printk( KERN_INFO "IVTV IOCTL: 0x%x\n", cmd ); - cx88_print_ioctl(dev->core->name,cmd); + v4l_print_ioctl(dev->core->name,cmd); #endif dprintk( 1, "IVTV IOCTL: 0x%x\n", cmd ); diff --git a/v4l_experimental/pvrusb2/.cvsignore b/v4l_experimental/pvrusb2/.cvsignore deleted file mode 100644 index 88be5bcbc..000000000 --- a/v4l_experimental/pvrusb2/.cvsignore +++ /dev/null @@ -1,7 +0,0 @@ -*.ko -*.o.flags -*.mod.c -.*.cmd -.version -.snapshot -.tmp_versions diff --git a/v4l_experimental/pvrusb2/Makefile b/v4l_experimental/pvrusb2/Makefile deleted file mode 100644 index 0c43d6977..000000000 --- a/v4l_experimental/pvrusb2/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -BUILD_DIR := $(shell pwd)/../.. - -all: - $(MAKE) -C $(BUILD_DIR) pvrusb2 - -install: - $(MAKE) -C $(BUILD_DIR) install - -%:: - $(MAKE) -C $(BUILD_DIR) $(MAKECMDGOALS) |