Commit 7b1e171b authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] dvb: Update saa7146 capture core

From: Michael Hunold <hunold@linuxtv.org>

fix a bunch of race conditions and locking bugs in video and vbi capture
code on device closure

use vmalloc_32() instead of vmalloc() in saa7146_vmalloc_build_pgtable().
this makes sure that the pagetable is in lowmem kernel memory

i2c timeout fix by Gerd Knorr 

SAA7146_I2C_SHORT_DELAY flag to speed up I2C access by Oliver Endriss

move saa7146_set_gpio() from saa7146_vv to saa7146_core, it's needed by DVB
budget drivers

add "new" saa7146_wait_for_debi_done() function, remove other versions from
av7110 and budget.ci

make budget-ci use this gpio function and the new wait_...() function,

make saa7146_pgtable_build_single() deliver a return code, make sanity
checks of the arguments

sanitize enabling of video input pins and i2c pins, use some default
values, so the hardware is always in a sane state

remove SAA7146_EXT_SWAP_ODD_EVEN flag + handling, fix the hardware
initialization instead

change minimal picture size to 48x32 just like other drivers

set up arbitrition control for video dma3 correctly

remove unnecessary code for capture to framebuffer memory, it's handled in
the generic code
parent c9a94895
...@@ -44,11 +44,66 @@ static void dump_registers(struct saa7146_dev* dev) ...@@ -44,11 +44,66 @@ static void dump_registers(struct saa7146_dev* dev)
} }
#endif #endif
/****************************************************************************
* gpio and debi helper functions
****************************************************************************/
/* write "data" to the gpio-pin "pin" */
void saa7146_set_gpio(struct saa7146_dev *dev, u8 pin, u8 data)
{
u32 value = 0;
/* sanity check */
if(pin > 3)
return;
/* read old register contents */
value = saa7146_read(dev, GPIO_CTRL );
value &= ~(0xff << (8*pin));
value |= (data << (8*pin));
saa7146_write(dev, GPIO_CTRL, value);
}
/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
int saa7146_wait_for_debi_done(struct saa7146_dev *dev)
{
int start;
/* wait for registers to be programmed */
start = jiffies;
while (1) {
if (saa7146_read(dev, MC2) & 2)
break;
if (jiffies-start > HZ/20) {
DEB_S(("timed out while waiting for registers getting programmed\n"));
return -ETIMEDOUT;
}
}
/* wait for transfer to complete */
start = jiffies;
while (1) {
if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
break;
saa7146_read(dev, MC2);
if (jiffies-start > HZ/4) {
DEB_S(("timed out while waiting for transfer completion\n"));
return -ETIMEDOUT;
}
}
return 0;
}
/**************************************************************************** /****************************************************************************
* general helper functions * general helper functions
****************************************************************************/ ****************************************************************************/
/* this is videobuf_vmalloc_to_sg() from video-buf.c */ /* this is videobuf_vmalloc_to_sg() from video-buf.c
make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
may be triggered on highmem machines */
static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
{ {
struct scatterlist *sglist; struct scatterlist *sglist;
...@@ -84,7 +139,7 @@ char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa ...@@ -84,7 +139,7 @@ char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa
{ {
struct scatterlist *slist = NULL; struct scatterlist *slist = NULL;
int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
char *mem = vmalloc(length); char *mem = vmalloc_32(length);
int slen = 0; int slen = 0;
if (NULL == mem) { if (NULL == mem) {
...@@ -103,7 +158,9 @@ char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa ...@@ -103,7 +158,9 @@ char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa
} }
slen = pci_map_sg(pci,slist,pages,PCI_DMA_FROMDEVICE); slen = pci_map_sg(pci,slist,pages,PCI_DMA_FROMDEVICE);
saa7146_pgtable_build_single(pci, pt, slist, slen); if (0 != saa7146_pgtable_build_single(pci, pt, slist, slen)) {
return NULL;
}
/* fixme: here's a memory leak: slist never gets freed by any other /* fixme: here's a memory leak: slist never gets freed by any other
function ...*/ function ...*/
...@@ -139,7 +196,7 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) ...@@ -139,7 +196,7 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
return 0; return 0;
} }
void saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
struct scatterlist *list, int sglen ) struct scatterlist *list, int sglen )
{ {
u32 *ptr, fill; u32 *ptr, fill;
...@@ -148,6 +205,11 @@ void saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *p ...@@ -148,6 +205,11 @@ void saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *p
BUG_ON( 0 == sglen); BUG_ON( 0 == sglen);
if (list->offset > PAGE_SIZE) {
DEB_D(("offset > PAGE_SIZE. this should not happen."));
return -EINVAL;
}
/* if we have a user buffer, the first page may not be /* if we have a user buffer, the first page may not be
aligned to a page boundary. */ aligned to a page boundary. */
pt->offset = list->offset; pt->offset = list->offset;
...@@ -177,6 +239,7 @@ void saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *p ...@@ -177,6 +239,7 @@ void saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *p
printk("ptr1 %d: 0x%08x\n",i,ptr[i]); printk("ptr1 %d: 0x%08x\n",i,ptr[i]);
} }
*/ */
return 0;
} }
/********************************************************************************/ /********************************************************************************/
...@@ -322,7 +385,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent ...@@ -322,7 +385,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
saa7146_write(dev, MC1, MASK_31); saa7146_write(dev, MC1, MASK_31);
*/ */
/* disable alle irqs */ /* disable all irqs */
saa7146_write(dev, IER, 0); saa7146_write(dev, IER, 0);
/* shut down all dma transfers */ /* shut down all dma transfers */
...@@ -381,8 +444,8 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent ...@@ -381,8 +444,8 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
dev->module = THIS_MODULE; dev->module = THIS_MODULE;
init_waitqueue_head(&dev->i2c_wq); init_waitqueue_head(&dev->i2c_wq);
/* set some default values */ /* set some sane pci arbitrition values */
saa7146_write(dev, BCS_CTRL, 0x80400040); saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
if( 0 != ext->probe) { if( 0 != ext->probe) {
if( 0 != ext->probe(dev) ) { if( 0 != ext->probe(dev) ) {
...@@ -508,6 +571,7 @@ EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc); ...@@ -508,6 +571,7 @@ EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);
EXPORT_SYMBOL_GPL(saa7146_pgtable_free); EXPORT_SYMBOL_GPL(saa7146_pgtable_free);
EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single); EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable); EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
EXPORT_SYMBOL_GPL(saa7146_setgpio); EXPORT_SYMBOL_GPL(saa7146_setgpio);
......
...@@ -86,7 +86,7 @@ void saa7146_buffer_next(struct saa7146_dev *dev, ...@@ -86,7 +86,7 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
return; return;
} }
DEB_EE(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi)); DEB_INT(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi));
#if DEBUG_SPINLOCKS #if DEBUG_SPINLOCKS
BUG_ON(!spin_is_locked(&dev->slock)); BUG_ON(!spin_is_locked(&dev->slock));
...@@ -98,10 +98,10 @@ void saa7146_buffer_next(struct saa7146_dev *dev, ...@@ -98,10 +98,10 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
if (!list_empty(&q->queue)) if (!list_empty(&q->queue))
next = list_entry(q->queue.next,struct saa7146_buf, vb.queue); next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
q->curr = buf; q->curr = buf;
DEB_D(("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev,q->queue.next)); DEB_INT(("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev,q->queue.next));
buf->activate(dev,buf,next); buf->activate(dev,buf,next);
} else { } else {
DEB_D(("no next buffer. stopping.\n")); DEB_INT(("no next buffer. stopping.\n"));
if( 0 != vbi ) { if( 0 != vbi ) {
/* turn off video-dma3 */ /* turn off video-dma3 */
saa7146_write(dev,MC1, MASK_20); saa7146_write(dev,MC1, MASK_20);
...@@ -229,10 +229,10 @@ static int fops_open(struct inode *inode, struct file *file) ...@@ -229,10 +229,10 @@ static int fops_open(struct inode *inode, struct file *file)
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
DEB_S(("initializing vbi...\n")); DEB_S(("initializing vbi...\n"));
saa7146_vbi_uops.open(dev,fh); saa7146_vbi_uops.open(dev,file);
} else { } else {
DEB_S(("initializing video...\n")); DEB_S(("initializing video...\n"));
saa7146_video_uops.open(dev,fh); saa7146_video_uops.open(dev,file);
} }
result = 0; result = 0;
...@@ -255,9 +255,9 @@ static int fops_release(struct inode *inode, struct file *file) ...@@ -255,9 +255,9 @@ static int fops_release(struct inode *inode, struct file *file)
return -ERESTARTSYS; return -ERESTARTSYS;
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
saa7146_vbi_uops.release(dev,fh,file); saa7146_vbi_uops.release(dev,file);
} else { } else {
saa7146_video_uops.release(dev,fh,file); saa7146_video_uops.release(dev,file);
} }
module_put(dev->ext->module); module_put(dev->ext->module);
...@@ -372,7 +372,7 @@ void vv_callback(struct saa7146_dev *dev, unsigned long status) ...@@ -372,7 +372,7 @@ void vv_callback(struct saa7146_dev *dev, unsigned long status)
{ {
u32 isr = status; u32 isr = status;
DEB_EE(("dev:%p, isr:0x%08x\n",dev,(u32)status)); DEB_INT(("dev:%p, isr:0x%08x\n",dev,(u32)status));
if (0 != (isr & (MASK_27))) { if (0 != (isr & (MASK_27))) {
DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); DEB_INT(("irq: RPS0 (0x%08x).\n",isr));
...@@ -410,6 +410,12 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) ...@@ -410,6 +410,12 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
DEB_EE(("dev:%p\n",dev)); DEB_EE(("dev:%p\n",dev));
/* set default values for video parts of the saa7146 */
saa7146_write(dev, BCS_CTRL, 0x80400040);
/* enable video-port pins */
saa7146_write(dev, MC1, (MASK_10 | MASK_26));
/* save per-device extension data (one extension can /* save per-device extension data (one extension can
handle different devices that might need different handle different devices that might need different
configuration data) */ configuration data) */
......
...@@ -660,24 +660,6 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy ...@@ -660,24 +660,6 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy
vv->current_hps_sync = sync; vv->current_hps_sync = sync;
} }
/* write "data" to the gpio-pin "pin" */
void saa7146_set_gpio(struct saa7146_dev *dev, u8 pin, u8 data)
{
u32 value = 0;
/* sanity check */
if(pin > 3)
return;
/* read old register contents */
value = saa7146_read(dev, GPIO_CTRL );
value &= ~(0xff << (8*pin));
value |= (data << (8*pin));
saa7146_write(dev, GPIO_CTRL, value);
}
/* reprogram hps, enable(1) / disable(0) video */ /* reprogram hps, enable(1) / disable(0) video */
void saa7146_set_overlay(struct saa7146_dev *dev, struct saa7146_fh *fh, int v) void saa7146_set_overlay(struct saa7146_dev *dev, struct saa7146_fh *fh, int v)
{ {
...@@ -710,13 +692,15 @@ void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_vi ...@@ -710,13 +692,15 @@ void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_vi
/* calculate starting address */ /* calculate starting address */
where = (which-1)*0x18; where = (which-1)*0x18;
/*
if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) { if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) {
saa7146_write(dev, where, vdma->base_even); saa7146_write(dev, where, vdma->base_even);
saa7146_write(dev, where+0x04, vdma->base_odd); saa7146_write(dev, where+0x04, vdma->base_odd);
} else { } else {
*/
saa7146_write(dev, where, vdma->base_odd); saa7146_write(dev, where, vdma->base_odd);
saa7146_write(dev, where+0x04, vdma->base_even); saa7146_write(dev, where+0x04, vdma->base_even);
} // }
saa7146_write(dev, where+0x08, vdma->prot_addr); saa7146_write(dev, where+0x08, vdma->prot_addr);
saa7146_write(dev, where+0x0c, vdma->pitch); saa7146_write(dev, where+0x0c, vdma->pitch);
saa7146_write(dev, where+0x10, vdma->base_page); saa7146_write(dev, where+0x10, vdma->base_page);
...@@ -971,12 +955,13 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar) ...@@ -971,12 +955,13 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar)
unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
/*
if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) { if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) {
unsigned long tmp = e_wait; unsigned long tmp = e_wait;
e_wait = o_wait; e_wait = o_wait;
o_wait = tmp; o_wait = tmp;
} }
*/
/* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/ /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/
WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait); WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait);
WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait); WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);
......
...@@ -301,7 +301,8 @@ int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg msgs[], i ...@@ -301,7 +301,8 @@ int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg msgs[], i
goto out; goto out;
} }
if (count > 3) short_delay = 1; if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) )
short_delay = 1;
do { do {
/* reset the i2c-device if necessary */ /* reset the i2c-device if necessary */
...@@ -403,19 +404,29 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c ...@@ -403,19 +404,29 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
{ {
DEB_EE(("bitrate: 0x%08x\n",bitrate)); DEB_EE(("bitrate: 0x%08x\n",bitrate));
/* enable i2c-port pins */
saa7146_write(dev, MC1, (MASK_08 | MASK_24));
dev->i2c_bitrate = bitrate; dev->i2c_bitrate = bitrate;
saa7146_i2c_reset(dev); saa7146_i2c_reset(dev);
if( NULL != i2c_adapter ) { if( NULL != i2c_adapter ) {
memset(i2c_adapter,0,sizeof(struct i2c_adapter)); memset(i2c_adapter,0,sizeof(struct i2c_adapter));
strcpy(i2c_adapter->name, dev->name); strcpy(i2c_adapter->name, dev->name);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
i2c_adapter->data = dev;
#else
i2c_set_adapdata(i2c_adapter,dev); i2c_set_adapdata(i2c_adapter,dev);
i2c_adapter->class = I2C_ADAP_CLASS_TV_ANALOG; #endif
i2c_adapter->algo = &saa7146_algo; i2c_adapter->algo = &saa7146_algo;
i2c_adapter->algo_data = NULL; i2c_adapter->algo_data = NULL;
i2c_adapter->id = I2C_ALGO_SAA7146; i2c_adapter->id = I2C_ALGO_SAA7146;
i2c_adapter->timeout = SAA7146_I2C_TIMEOUT; i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
i2c_adapter->retries = SAA7146_I2C_RETRIES; i2c_adapter->retries = SAA7146_I2C_RETRIES;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
#else
i2c_adapter->class = I2C_ADAP_CLASS_TV_ANALOG;
#endif
} }
return 0; return 0;
......
...@@ -41,7 +41,11 @@ static int vbi_workaround(struct saa7146_dev *dev) ...@@ -41,7 +41,11 @@ static int vbi_workaround(struct saa7146_dev *dev)
/* wait for vbi_a or vbi_b*/ /* wait for vbi_a or vbi_b*/
if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
DEB_D(("...using port b\n")); DEB_D(("...using port b\n"));
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);
/*
WRITE_RPS1(CMD_PAUSE | MASK_09); WRITE_RPS1(CMD_PAUSE | MASK_09);
*/
} else { } else {
DEB_D(("...using port a\n")); DEB_D(("...using port a\n"));
WRITE_RPS1(CMD_PAUSE | MASK_10); WRITE_RPS1(CMD_PAUSE | MASK_10);
...@@ -137,10 +141,10 @@ void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, s ...@@ -137,10 +141,10 @@ void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, s
unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
/* /*
vdma3.base_even = (u32)dev->ov_fb.base+2048*70; vdma3.base_even = 0xc8000000+2560*70;
vdma3.base_odd = (u32)dev->ov_fb.base; vdma3.base_odd = 0xc8000000;
vdma3.prot_addr = (u32)dev->ov_fb.base+2048*164; vdma3.prot_addr = 0xc8000000+2560*164;
vdma3.pitch = 2048; vdma3.pitch = 2560;
vdma3.base_page = 0; vdma3.base_page = 0;
vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above! vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above!
*/ */
...@@ -244,7 +248,9 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb,enum v4l ...@@ -244,7 +248,9 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb,enum v4l
err = videobuf_iolock(dev->pci,&buf->vb,NULL); err = videobuf_iolock(dev->pci,&buf->vb,NULL);
if (err) if (err)
goto oops; goto oops;
saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen); err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen);
if (0 != err)
return err;
} }
buf->vb.state = STATE_PREPARED; buf->vb.state = STATE_PREPARED;
buf->activate = buffer_activate; buf->activate = buffer_activate;
...@@ -303,7 +309,7 @@ static struct videobuf_queue_ops vbi_qops = { ...@@ -303,7 +309,7 @@ static struct videobuf_queue_ops vbi_qops = {
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
static void vbi_stop(struct saa7146_fh *fh) static void vbi_stop(struct saa7146_fh *fh, struct file *file)
{ {
struct saa7146_dev *dev = fh->dev; struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
...@@ -321,23 +327,29 @@ static void vbi_stop(struct saa7146_fh *fh) ...@@ -321,23 +327,29 @@ static void vbi_stop(struct saa7146_fh *fh)
/* shut down dma 3 transfers */ /* shut down dma 3 transfers */
saa7146_write(dev, MC1, MASK_20); saa7146_write(dev, MC1, MASK_20);
if (vv->vbi_q.curr) {
saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
}
videobuf_queue_cancel(file,&fh->vbi_q);
vv->vbi_streaming = NULL; vv->vbi_streaming = NULL;
del_timer(&vv->vbi_q.timeout); del_timer(&vv->vbi_q.timeout);
del_timer(&fh->vbi_read_timeout); del_timer(&fh->vbi_read_timeout);
DEB_VBI(("out\n"));
spin_unlock_irqrestore(&dev->slock, flags); spin_unlock_irqrestore(&dev->slock, flags);
} }
static void vbi_read_timeout(unsigned long data) static void vbi_read_timeout(unsigned long data)
{ {
struct saa7146_fh *fh = (struct saa7146_fh *)data; struct file *file = (struct file*)data;
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev; struct saa7146_dev *dev = fh->dev;
DEB_VBI(("dev:%p, fh:%p\n",dev, fh)); DEB_VBI(("dev:%p, fh:%p\n",dev, fh));
vbi_stop(fh); vbi_stop(fh, file);
} }
static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
...@@ -354,10 +366,21 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) ...@@ -354,10 +366,21 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
init_waitqueue_head(&vv->vbi_wq); init_waitqueue_head(&vv->vbi_wq);
} }
static void vbi_open(struct saa7146_dev *dev, struct saa7146_fh *fh) static void vbi_open(struct saa7146_dev *dev, struct file *file)
{ {
struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
int ret = 0;
DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
/* adjust arbitrition control for video dma 3 */
arbtr_ctrl &= ~0x1f0000;
arbtr_ctrl |= 0x1d0000;
saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
saa7146_write(dev, MC2, (MASK_04|MASK_20));
memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt)); memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt));
fh->vbi_fmt.sampling_rate = 27000000; fh->vbi_fmt.sampling_rate = 27000000;
...@@ -380,21 +403,32 @@ static void vbi_open(struct saa7146_dev *dev, struct saa7146_fh *fh) ...@@ -380,21 +403,32 @@ static void vbi_open(struct saa7146_dev *dev, struct saa7146_fh *fh)
init_timer(&fh->vbi_read_timeout); init_timer(&fh->vbi_read_timeout);
fh->vbi_read_timeout.function = vbi_read_timeout; fh->vbi_read_timeout.function = vbi_read_timeout;
fh->vbi_read_timeout.data = (unsigned long)fh; fh->vbi_read_timeout.data = (unsigned long)file;
/* fixme: enable this again, if the dvb-c w/ analog module work properly */ /* initialize the brs */
/* if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
vbi_workaround(dev); saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19));
*/ } else {
saa7146_write(dev, BRS_CTRL, 0x00000001);
if (0 != (ret = vbi_workaround(dev))) {
DEB_VBI(("vbi workaround failed!\n"));
/* return ret;*/
}
}
/* upload brs register */
saa7146_write(dev, MC2, (MASK_08|MASK_24));
} }
static void vbi_close(struct saa7146_dev *dev, struct saa7146_fh *fh, struct file *file) static void vbi_close(struct saa7146_dev *dev, struct file *file)
{ {
struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
if( fh == vv->vbi_streaming ) { if( fh == vv->vbi_streaming ) {
vbi_stop(fh); vbi_stop(fh, file);
} }
} }
......
...@@ -116,7 +116,7 @@ static int try_win(struct saa7146_dev *dev, struct v4l2_window *win) ...@@ -116,7 +116,7 @@ static int try_win(struct saa7146_dev *dev, struct v4l2_window *win)
DEB_D(("no fb fmt set.\n")); DEB_D(("no fb fmt set.\n"));
return -EINVAL; return -EINVAL;
} }
if (win->w.width < 64 || win->w.height < 64) { if (win->w.width < 48 || win->w.height < 32) {
DEB_D(("min width/height. (%d,%d)\n",win->w.width,win->w.height)); DEB_D(("min width/height. (%d,%d)\n",win->w.width,win->w.height));
return -EINVAL; return -EINVAL;
} }
...@@ -661,7 +661,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu ...@@ -661,7 +661,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
*/ */
} else { } else {
struct saa7146_pgtable *pt = &buf->pt[0]; struct saa7146_pgtable *pt = &buf->pt[0];
saa7146_pgtable_build_single(pci, pt, list, length); return saa7146_pgtable_build_single(pci, pt, list, length);
} }
return 0; return 0;
...@@ -704,7 +704,7 @@ static int video_begin(struct saa7146_fh *fh) ...@@ -704,7 +704,7 @@ static int video_begin(struct saa7146_fh *fh)
return 0; return 0;
} }
static int video_end(struct saa7146_fh *fh) static int video_end(struct saa7146_fh *fh, struct file *file)
{ {
struct saa7146_dev *dev = fh->dev; struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
...@@ -735,82 +735,9 @@ static int video_end(struct saa7146_fh *fh) ...@@ -735,82 +735,9 @@ static int video_end(struct saa7146_fh *fh)
saa7146_write(dev, MC1, 0x00700000); saa7146_write(dev, MC1, 0x00700000);
vv->streaming = NULL; vv->streaming = NULL;
spin_unlock_irqrestore(&dev->slock, flags);
return 0;
}
/* capturing to framebuffer */
int overlay_reqbufs(struct saa7146_dev *dev, struct v4l2_requestbuffers *req)
{
/* struct saa7146_fh *fh = file->private_data;
if (req->count > VIDEO_MAX_FRAME)
req->count = VIDEO_MAX_FRAME;
*size = fh->video_fmt.sizeimage;
*/
return 0;
}
int overlay_querybuf(struct saa7146_dev *dev, struct v4l2_buffer *buf)
{
return 0;
}
int overlay_qbuf(struct saa7146_dev *dev, struct v4l2_buffer *b)
{
/* if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
DEB_D(("index %d out of bounds.\n",b->index));
goto -EINVAL;
}
buf = q->bufs[b->index];
if (NULL == buf) {
printk("videobuf_qbuf: NULL == buf\n");
goto done;
}
if (0 == buf->baddr) {
printk("videobuf_qbuf: 0 == buf->baddr\n");
goto done;
}
if (buf->state == STATE_QUEUED ||
buf->state == STATE_ACTIVE) {
printk("videobuf_qbuf: already queued or activated.\n");
goto done;
}
field = videobuf_next_field(q); spin_unlock_irqrestore(&dev->slock, flags);
retval = q->ops->buf_prepare(file,buf,field);
if (0 != retval) {
printk("videobuf_qbuf: buf_prepare() failed.\n");
goto done;
}
list_add_tail(&buf->stream,&q->stream);
if (q->streaming) {
spin_lock_irqsave(q->irqlock,flags);
q->ops->buf_queue(file,buf);
spin_unlock_irqrestore(q->irqlock,flags);
}
retval = 0;
done:
up(&q->lock);
return retval;
*/
return 0;
}
int overlay_dqbuf(struct saa7146_dev *dev, struct v4l2_buffer *buf)
{
return 0;
}
int overlay_streamon(struct saa7146_dev *dev)
{
return 0;
}
int overlay_streamoff(struct saa7146_dev *dev)
{
return 0; return 0;
} }
...@@ -818,7 +745,7 @@ int overlay_streamoff(struct saa7146_dev *dev) ...@@ -818,7 +745,7 @@ int overlay_streamoff(struct saa7146_dev *dev)
/* /*
* This function is _not_ called directly, but from * This function is _not_ called directly, but from
* video_generic_ioctl (and maybe others). userspace * video_generic_ioctl (and maybe others). userspace
* copying is done already, arg is a kernel fhinter. * copying is done already, arg is a kernel pointer.
*/ */
int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
...@@ -1141,38 +1068,24 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1141,38 +1068,24 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
case VIDIOC_REQBUFS: { case VIDIOC_REQBUFS: {
struct v4l2_requestbuffers *req = arg; struct v4l2_requestbuffers *req = arg;
DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type)); DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type));
/*
if( req->type == V4L2_BUF_TYPE_VIDEO_OVERLAY ) {
return overlay_reqbufs(dev,req);
}
*/
return videobuf_reqbufs(file,q,req); return videobuf_reqbufs(file,q,req);
} }
case VIDIOC_QUERYBUF: { case VIDIOC_QUERYBUF: {
struct v4l2_buffer *buf = arg; struct v4l2_buffer *buf = arg;
DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset)); DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset));
/* if( buf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY ) { return videobuf_querybuf(q,buf);
return overlay_querybuf(dev,buf);
}
*/ return videobuf_querybuf(q,buf);
} }
case VIDIOC_QBUF: { case VIDIOC_QBUF: {
struct v4l2_buffer *buf = arg; struct v4l2_buffer *buf = arg;
int ret = 0; int ret = 0;
/* if( buf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY ) { ret = videobuf_qbuf(file,q,buf);
return overlay_qbuf(dev,buf);
}
*/ ret = videobuf_qbuf(file,q,buf);
DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index)); DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index));
return ret; return ret;
} }
case VIDIOC_DQBUF: { case VIDIOC_DQBUF: {
struct v4l2_buffer *buf = arg; struct v4l2_buffer *buf = arg;
int ret = 0; int ret = 0;
/* if( buf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY ) { ret = videobuf_dqbuf(file,q,buf);
return overlay_dqbuf(dev,buf);
}
*/ ret = videobuf_dqbuf(file,q,buf);
DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index)); DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index));
return ret; return ret;
} }
...@@ -1180,29 +1093,18 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1180,29 +1093,18 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
int *type = arg; int *type = arg;
DEB_D(("VIDIOC_STREAMON, type:%d\n",*type)); DEB_D(("VIDIOC_STREAMON, type:%d\n",*type));
if( 0 != ops->capture_begin ) { if( 0 != (err = video_begin(fh))) {
if( 0 != (err = ops->capture_begin(fh))) {
return err; return err;
} }
}
/* if( *type == V4L2_BUF_TYPE_VIDEO_OVERLAY ) {
err = overlay_streamon(dev);
} else { */
err = videobuf_streamon(file,q); err = videobuf_streamon(file,q);
/* } */
return err; return err;
} }
case VIDIOC_STREAMOFF: { case VIDIOC_STREAMOFF: {
int *type = arg; int *type = arg;
DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type)); DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type));
if( 0 != ops->capture_end ) { err = videobuf_streamoff(file,q);
ops->capture_end(fh); video_end(fh, file);
}
/* if( *type == V4L2_BUF_TYPE_VIDEO_OVERLAY ) {
return overlay_streamoff(dev);
}
*/ err = videobuf_streamoff(file,q);
return err; return err;
} }
case VIDIOCGMBUF: case VIDIOCGMBUF:
...@@ -1267,8 +1169,8 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb, enum v4 ...@@ -1267,8 +1169,8 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb, enum v4
DEB_CAP(("vbuf:%p\n",vb)); DEB_CAP(("vbuf:%p\n",vb));
/* sanity checks */ /* sanity checks */
if (fh->video_fmt.width < 64 || if (fh->video_fmt.width < 48 ||
fh->video_fmt.height < 64 || fh->video_fmt.height < 32 ||
fh->video_fmt.width > vv->standard->h_max_out || fh->video_fmt.width > vv->standard->h_max_out ||
fh->video_fmt.height > vv->standard->v_max_out) { fh->video_fmt.height > vv->standard->v_max_out) {
DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height)); DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height));
...@@ -1407,8 +1309,9 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv) ...@@ -1407,8 +1309,9 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
} }
static void video_open(struct saa7146_dev *dev, struct saa7146_fh *fh) static void video_open(struct saa7146_dev *dev, struct file *file)
{ {
struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
struct saa7146_format *sfmt; struct saa7146_format *sfmt;
fh->video_fmt.width = 384; fh->video_fmt.width = 384;
...@@ -1429,8 +1332,9 @@ static void video_open(struct saa7146_dev *dev, struct saa7146_fh *fh) ...@@ -1429,8 +1332,9 @@ static void video_open(struct saa7146_dev *dev, struct saa7146_fh *fh)
} }
static void video_close(struct saa7146_dev *dev, struct saa7146_fh *fh, struct file *file) static void video_close(struct saa7146_dev *dev, struct file *file)
{ {
struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
unsigned long flags; unsigned long flags;
...@@ -1443,10 +1347,8 @@ static void video_close(struct saa7146_dev *dev, struct saa7146_fh *fh, struct f ...@@ -1443,10 +1347,8 @@ static void video_close(struct saa7146_dev *dev, struct saa7146_fh *fh, struct f
} }
if( fh == vv->streaming ) { if( fh == vv->streaming ) {
video_end(fh); video_end(fh, file);
} }
videobuf_queue_cancel(file,&fh->video_q);
} }
...@@ -1489,7 +1391,7 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p ...@@ -1489,7 +1391,7 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p
return -EAGAIN; return -EAGAIN;
} }
ret = videobuf_read_one(file,&fh->video_q , data, count, ppos); ret = videobuf_read_one(file,&fh->video_q , data, count, ppos);
video_end(fh); video_end(fh, file);
/* restart overlay if it was active before */ /* restart overlay if it was active before */
if( 0 != restart_overlay ) { if( 0 != restart_overlay ) {
...@@ -1505,6 +1407,4 @@ struct saa7146_use_ops saa7146_video_uops = { ...@@ -1505,6 +1407,4 @@ struct saa7146_use_ops saa7146_video_uops = {
.release = video_close, .release = video_close,
.irq_done = video_irq_done, .irq_done = video_irq_done,
.read = video_read, .read = video_read,
.capture_begin = video_begin,
.capture_end = video_end,
}; };
...@@ -87,6 +87,7 @@ struct saa7146_extension ...@@ -87,6 +87,7 @@ struct saa7146_extension
{ {
char name[32]; /* name of the device */ char name[32]; /* name of the device */
#define SAA7146_USE_I2C_IRQ 0x1 #define SAA7146_USE_I2C_IRQ 0x1
#define SAA7146_I2C_SHORT_DELAY 0x2
int flags; int flags;
/* pairs of subvendor and subdevice ids for /* pairs of subvendor and subdevice ids for
...@@ -162,9 +163,10 @@ int saa7146_unregister_extension(struct saa7146_extension*); ...@@ -162,9 +163,10 @@ int saa7146_unregister_extension(struct saa7146_extension*);
struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc); struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc);
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt); int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt); void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
void saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length ); int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt); char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data); void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
int saa7146_wait_for_debi_done(struct saa7146_dev *dev);
/* some memory sizes */ /* some memory sizes */
#define SAA7146_I2C_MEM ( 1*PAGE_SIZE) #define SAA7146_I2C_MEM ( 1*PAGE_SIZE)
...@@ -187,6 +189,9 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data); ...@@ -187,6 +189,9 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
#define SAA7146_GPIO_OUTLO 0x40 #define SAA7146_GPIO_OUTLO 0x40
#define SAA7146_GPIO_OUTHI 0x50 #define SAA7146_GPIO_OUTHI 0x50
/* debi defines */
#define DEBINOSWAP 0x000e0000
/* define for the register programming sequencer (rps) */ /* define for the register programming sequencer (rps) */
#define CMD_NOP 0x00000000 /* No operation */ #define CMD_NOP 0x00000000 /* No operation */
#define CMD_CLR_EVENT 0x00000000 /* Clear event */ #define CMD_CLR_EVENT 0x00000000 /* Clear event */
......
...@@ -149,7 +149,7 @@ struct saa7146_extension_ioctls ...@@ -149,7 +149,7 @@ struct saa7146_extension_ioctls
}; };
/* flags */ /* flags */
#define SAA7146_EXT_SWAP_ODD_EVEN 0x1 /* needs odd/even fields swapped */ // #define SAA7146_EXT_SWAP_ODD_EVEN 0x1 /* needs odd/even fields swapped */
#define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */ #define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */
struct saa7146_ext_vv struct saa7146_ext_vv
...@@ -171,12 +171,10 @@ struct saa7146_ext_vv ...@@ -171,12 +171,10 @@ struct saa7146_ext_vv
struct saa7146_use_ops { struct saa7146_use_ops {
void (*init)(struct saa7146_dev *, struct saa7146_vv *); void (*init)(struct saa7146_dev *, struct saa7146_vv *);
void(*open)(struct saa7146_dev *, struct saa7146_fh *); void(*open)(struct saa7146_dev *, struct file *);
void (*release)(struct saa7146_dev *, struct saa7146_fh *,struct file *); void (*release)(struct saa7146_dev *, struct file *);
void (*irq_done)(struct saa7146_dev *, unsigned long status); void (*irq_done)(struct saa7146_dev *, unsigned long status);
ssize_t (*read)(struct file *, char *, size_t, loff_t *); ssize_t (*read)(struct file *, char *, size_t, loff_t *);
int (*capture_begin)(struct saa7146_fh *);
int (*capture_end)(struct saa7146_fh *);
}; };
/* from saa7146_fops.c */ /* from saa7146_fops.c */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment