From: Michael Hunold - fix memory leak in page table handling - minor coding style changes - add simple resource management for video dmas (borrowed from saa7134) - use resource management to lock video and vbi access which sometimes share the same video dmas - honour return codes of extension functions in various places, when resources could not be locked - remove remains of dead code which were commented out anyway - add new flag FORMAT_IS_PLANAR to indicate planar capture formats, needed for resource allocation --- drivers/media/common/saa7146_core.c | 21 ++--- drivers/media/common/saa7146_fops.c | 80 ++++++++++++++++++-- drivers/media/common/saa7146_hlp.c | 71 ++++++------------ drivers/media/common/saa7146_vbi.c | 10 ++ drivers/media/common/saa7146_video.c | 136 ++++++++++++++++++++++++++++------- include/media/saa7146.h | 2 include/media/saa7146_vv.h | 29 +++++-- 7 files changed, 250 insertions(+), 99 deletions(-) diff -puN drivers/media/common/saa7146_core.c~dvb-02-update-saa7146 drivers/media/common/saa7146_core.c --- 25/drivers/media/common/saa7146_core.c~dvb-02-update-saa7146 2004-01-18 16:26:08.000000000 -0800 +++ 25-akpm/drivers/media/common/saa7146_core.c 2004-01-18 16:26:08.000000000 -0800 @@ -137,7 +137,6 @@ static struct scatterlist* vmalloc_to_sg char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) { - struct scatterlist *slist = NULL; int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; char *mem = vmalloc_32(length); int slen = 0; @@ -146,35 +145,36 @@ char *saa7146_vmalloc_build_pgtable(stru return NULL; } - if (!(slist = vmalloc_to_sg(mem, pages))) { + if (!(pt->slist = vmalloc_to_sg(mem, pages))) { vfree(mem); return NULL; } if (saa7146_pgtable_alloc(pci, pt)) { - kfree(slist); + kfree(pt->slist); + pt->slist = NULL; vfree(mem); return NULL; } - slen = pci_map_sg(pci,slist,pages,PCI_DMA_FROMDEVICE); - if (0 != saa7146_pgtable_build_single(pci, pt, slist, slen)) { + slen = pci_map_sg(pci,pt->slist,pages,PCI_DMA_FROMDEVICE); + if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) { return NULL; } - /* fixme: here's a memory leak: slist never gets freed by any other - function ...*/ return mem; } void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) { -//fm DEB_EE(("pci:%p, pt:%p\n",pci,pt)); - if (NULL == pt->cpu) return; pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); pt->cpu = NULL; + if (NULL != pt->slist) { + kfree(pt->slist); + pt->slist = NULL; + } } int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) @@ -182,11 +182,8 @@ int saa7146_pgtable_alloc(struct pci_dev u32 *cpu; dma_addr_t dma_addr; -//fm DEB_EE(("pci:%p, pt:%p\n",pci,pt)); - cpu = pci_alloc_consistent(pci, SAA7146_PGTABLE_SIZE, &dma_addr); if (NULL == cpu) { -//fm ERR(("pci_alloc_consistent() failed.")); return -ENOMEM; } pt->size = SAA7146_PGTABLE_SIZE; diff -puN drivers/media/common/saa7146_fops.c~dvb-02-update-saa7146 drivers/media/common/saa7146_fops.c --- 25/drivers/media/common/saa7146_fops.c~dvb-02-update-saa7146 2004-01-18 16:26:08.000000000 -0800 +++ 25-akpm/drivers/media/common/saa7146_fops.c 2004-01-18 16:26:08.000000000 -0800 @@ -2,6 +2,65 @@ #define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vv_data->vbi_minor != -1) +/****************************************************************************/ +/* resource management functions, shamelessly stolen from saa7134 driver */ + +int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + DEB_D(("getting lock...\n")); + down(&dev->lock); + DEB_D(("got lock\n")); + if (vv->resources & bit) { + DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit)); + /* no, someone else uses it */ + up(&dev->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + vv->resources |= bit; + DEB_D(("res: get %d\n",bit)); + up(&dev->lock); + return 1; +} + +int saa7146_res_check(struct saa7146_fh *fh, unsigned int bit) +{ + return (fh->resources & bit); +} + +int saa7146_res_locked(struct saa7146_dev *dev, unsigned int bit) +{ + struct saa7146_vv *vv = dev->vv_data; + return (vv->resources & bit); +} + +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(); + + DEB_D(("getting lock...\n")); + down(&dev->lock); + DEB_D(("got lock\n")); + fh->resources &= ~bits; + vv->resources &= ~bits; + DEB_D(("res: put %d\n",bits)); + up(&dev->lock); +} + + /********************************************************************************/ /* common dma functions */ @@ -216,29 +275,32 @@ static int fops_open(struct inode *inode } memset(fh,0,sizeof(*fh)); - // FIXME: do we need to increase *our* usage count? - - if( 0 == try_module_get(dev->ext->module)) { - result = -EINVAL; - goto out; - } - file->private_data = fh; fh->dev = dev; fh->type = type; if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { DEB_S(("initializing vbi...\n")); - saa7146_vbi_uops.open(dev,file); + result = saa7146_vbi_uops.open(dev,file); } else { DEB_S(("initializing video...\n")); - saa7146_video_uops.open(dev,file); + result = saa7146_video_uops.open(dev,file); + } + + if (0 != result) { + goto out; + } + + if( 0 == try_module_get(dev->ext->module)) { + result = -EINVAL; + goto out; } result = 0; out: if( fh != 0 && result != 0 ) { kfree(fh); + file->private_data = NULL; } up(&saa7146_devices_lock); return result; diff -puN drivers/media/common/saa7146_hlp.c~dvb-02-update-saa7146 drivers/media/common/saa7146_hlp.c --- 25/drivers/media/common/saa7146_hlp.c~dvb-02-update-saa7146 2004-01-18 16:26:08.000000000 -0800 +++ 25-akpm/drivers/media/common/saa7146_hlp.c 2004-01-18 16:26:08.000000000 -0800 @@ -152,8 +152,7 @@ static int calculate_h_scale_registers(s if( 1 == xpsc ) { xacm = 1; dcgx = 0; - } - else { + } else { xacm = 0; /* get best match in the table of attenuations for horizontal scaling */ @@ -268,8 +267,7 @@ static int calculate_v_scale_registers(s ype = ysci / 16; ypo = ype + (ysci / 64); - } - else { + } else { yacm = 1; /* calculate scaling increment */ @@ -285,8 +283,7 @@ static int calculate_v_scale_registers(s ... */ if ( ysci < 512) { yacl = 0; - } - else { + } else { yacl = ( ysci / (1024 - ysci) ); } @@ -488,33 +485,31 @@ static void saa7146_disable_clipping(str saa7146_write(dev, MC2, (MASK_05 | MASK_21)); /* disable video dma2 */ - saa7146_write(dev, MC1, (MASK_21)); + saa7146_write(dev, MC1, MASK_21); } -static void saa7146_set_clipping_rect(struct saa7146_dev *dev, struct saa7146_fh *fh) +static void saa7146_set_clipping_rect(struct saa7146_fh *fh) { + struct saa7146_dev *dev = fh->dev; enum v4l2_field field = fh->ov.win.field; - int clipcount = fh->ov.nclips; - struct saa7146_video_dma vdma2; - - u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); - u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); - - // fixme: is this used at all? SAA7146_CLIPPING_RECT_INVERTED; - u32 type = SAA7146_CLIPPING_RECT; + u32 clip_format; + u32 arbtr_ctrl; /* check clipcount, disable clipping if clipcount == 0*/ - if( clipcount == 0 ) { + if( fh->ov.nclips == 0 ) { saa7146_disable_clipping(dev); return; } + clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); + arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); + calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field); /* set clipping format */ clip_format &= 0xffff0008; - clip_format |= (type << 4); + clip_format |= (SAA7146_CLIPPING_RECT << 4); /* prepare video dma2 */ saa7146_write(dev, BASE_EVEN2, vdma2.base_even); @@ -660,25 +655,28 @@ void saa7146_set_hps_source_and_sync(str vv->current_hps_sync = sync; } -/* reprogram hps, enable(1) / disable(0) video */ -void saa7146_set_overlay(struct saa7146_dev *dev, struct saa7146_fh *fh, int v) +int saa7146_enable_overlay(struct saa7146_fh *fh) { + struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - /* enable ? */ - if( 0 == v) { - /* disable video dma1 */ - saa7146_write(dev, MC1, MASK_22); - return; - } - saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field); saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field); saa7146_set_output_format(dev, vv->ov_fmt->trans); - saa7146_set_clipping_rect(dev, fh); + saa7146_set_clipping_rect(fh); /* enable video dma1 */ saa7146_write(dev, MC1, (MASK_06 | MASK_22)); + return 0; +} + +void saa7146_disable_overlay(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + + /* disable clipping + video dma1 */ + saa7146_disable_clipping(dev); + saa7146_write(dev, MC1, MASK_22); } void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) @@ -692,15 +690,8 @@ void saa7146_write_out_dma(struct saa714 /* calculate starting address */ where = (which-1)*0x18; -/* - if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) { - saa7146_write(dev, where, vdma->base_even); - saa7146_write(dev, where+0x04, vdma->base_odd); - } else { -*/ saa7146_write(dev, where, vdma->base_odd); saa7146_write(dev, where+0x04, vdma->base_even); -// } saa7146_write(dev, where+0x08, vdma->prot_addr); saa7146_write(dev, where+0x0c, vdma->pitch); saa7146_write(dev, where+0x10, vdma->base_page); @@ -937,7 +928,7 @@ static int calculate_video_dma_grab_plan } saa7146_write_out_dma(dev, 1, &vdma1); - if( sfmt->swap != 0 ) { + if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) { saa7146_write_out_dma(dev, 3, &vdma2); saa7146_write_out_dma(dev, 2, &vdma3); } else { @@ -955,13 +946,6 @@ static void program_capture_engine(struc 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; -/* - if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) { - unsigned long tmp = e_wait; - e_wait = o_wait; - o_wait = tmp; - } -*/ /* 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 | e_wait); @@ -1038,7 +1022,6 @@ void saa7146_set_capture(struct saa7146_ saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field); saa7146_set_output_format(dev, sfmt->trans); - saa7146_disable_clipping(dev); if ( vv->last_field == V4L2_FIELD_INTERLACED ) { } else if ( vv->last_field == V4L2_FIELD_TOP ) { diff -puN drivers/media/common/saa7146_vbi.c~dvb-02-update-saa7146 drivers/media/common/saa7146_vbi.c --- 25/drivers/media/common/saa7146_vbi.c~dvb-02-update-saa7146 2004-01-18 16:26:08.000000000 -0800 +++ 25-akpm/drivers/media/common/saa7146_vbi.c 2004-01-18 16:26:08.000000000 -0800 @@ -366,7 +366,7 @@ static void vbi_init(struct saa7146_dev init_waitqueue_head(&vv->vbi_wq); } -static void vbi_open(struct saa7146_dev *dev, struct file *file) +static int vbi_open(struct saa7146_dev *dev, struct file *file) { struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; @@ -375,6 +375,12 @@ static void vbi_open(struct saa7146_dev DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); + ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS); + if (0 == ret) { + DEB_S(("cannot get vbi RESOURCE_DMA3_BRS resource\n")); + return -EBUSY; + } + /* adjust arbitrition control for video dma 3 */ arbtr_ctrl &= ~0x1f0000; arbtr_ctrl |= 0x1d0000; @@ -419,6 +425,7 @@ static void vbi_open(struct saa7146_dev /* upload brs register */ saa7146_write(dev, MC2, (MASK_08|MASK_24)); + return 0; } static void vbi_close(struct saa7146_dev *dev, struct file *file) @@ -430,6 +437,7 @@ static void vbi_close(struct saa7146_dev if( fh == vv->vbi_streaming ) { vbi_stop(fh, file); } + saa7146_res_free(fh, RESOURCE_DMA3_BRS); } static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) diff -puN drivers/media/common/saa7146_video.c~dvb-02-update-saa7146 drivers/media/common/saa7146_video.c --- 25/drivers/media/common/saa7146_video.c~dvb-02-update-saa7146 2004-01-18 16:26:08.000000000 -0800 +++ 25-akpm/drivers/media/common/saa7146_video.c 2004-01-18 16:26:08.000000000 -0800 @@ -12,48 +12,55 @@ static struct saa7146_format formats[] = .pixelformat = V4L2_PIX_FMT_RGB332, .trans = RGB08_COMPOSED, .depth = 8, + .flags = 0, }, { - .name = "RGB-16 (5/B-6/G-5/R)", /* really? */ + .name = "RGB-16 (5/B-6/G-5/R)", .pixelformat = V4L2_PIX_FMT_RGB565, .trans = RGB16_COMPOSED, .depth = 16, + .flags = 0, }, { .name = "RGB-24 (B-G-R)", .pixelformat = V4L2_PIX_FMT_BGR24, .trans = RGB24_COMPOSED, .depth = 24, + .flags = 0, }, { .name = "RGB-32 (B-G-R)", .pixelformat = V4L2_PIX_FMT_BGR32, .trans = RGB32_COMPOSED, .depth = 32, + .flags = 0, }, { .name = "Greyscale-8", .pixelformat = V4L2_PIX_FMT_GREY, .trans = Y8, .depth = 8, + .flags = 0, }, { .name = "YUV 4:2:2 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YUV422P, .trans = YUV422_DECOMPOSED, .depth = 16, - .swap = 1, + .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, }, { .name = "YVU 4:2:0 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YVU420, .trans = YUV420_DECOMPOSED, .depth = 12, - .swap = 1, + .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, }, { .name = "YUV 4:2:0 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YUV420, .trans = YUV420_DECOMPOSED, .depth = 12, + .flags = FORMAT_IS_PLANAR, }, { .name = "YUV 4:2:2 (U-Y-V-Y)", .pixelformat = V4L2_PIX_FMT_UYVY, .trans = YUV422_COMPOSED, .depth = 16, + .flags = 0, } }; @@ -243,13 +250,13 @@ int saa7146_start_preview(struct saa7146 { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - int err = 0; + int ret = 0, err = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); /* check if we have overlay informations */ if( NULL == fh->ov.fh ) { - DEB_D(("not overlay data available. try S_FMT first.\n")); + DEB_D(("no overlay data available. try S_FMT first.\n")); return -EAGAIN; } @@ -280,7 +287,11 @@ int saa7146_start_preview(struct saa7146 fh->ov.win.w.left,fh->ov.win.w.top, vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field])); - saa7146_set_overlay(dev, fh, 1); + if (0 != (ret = saa7146_enable_overlay(fh))) { + vv->ov_data = NULL; + DEB_D(("enabling overlay failed: %d\n",ret)); + return ret; + } return 0; } @@ -290,7 +301,7 @@ int saa7146_stop_preview(struct saa7146_ struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - DEB_EE(("saa7146.o: saa7146_stop_preview()\n")); + DEB_EE(("dev:%p, fh:%p\n",dev,fh)); /* check if overlay is running */ if( 0 == vv->ov_data ) { @@ -300,11 +311,11 @@ int saa7146_stop_preview(struct saa7146_ if( fh != vv->ov_data->fh ) { DEB_D(("overlay is active, but for another open.\n")); - return -EBUSY; + return 0; } - saa7146_set_overlay(dev, fh, 0); vv->ov_data = NULL; + saa7146_disable_overlay(fh); return 0; } @@ -675,21 +686,37 @@ static int video_begin(struct saa7146_fh { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; + struct saa7146_format *fmt = NULL; unsigned long flags; + unsigned int resource; + int ret = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); if( fh == vv->streaming ) { DEB_S(("already capturing.\n")); - return 0; + return -EBUSY; } if( vv->streaming != 0 ) { DEB_S(("already capturing, but in another open.\n")); return -EBUSY; } - /* fixme: check for planar formats here, if we will interfere with - vbi capture for example */ + fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); + /* we need to have a valid format set here */ + BUG_ON(NULL == fmt); + + if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { + resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; + } else { + resource = RESOURCE_DMA1_HPS; + } + + ret = saa7146_res_get(fh, resource); + if (0 == ret) { + DEB_S(("cannot get capture resource %d\n",resource)); + return -EBUSY; + } spin_lock_irqsave(&dev->slock,flags); @@ -708,8 +735,10 @@ static int video_end(struct saa7146_fh * { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; + struct saa7146_format *fmt = NULL; unsigned long flags; - + unsigned int resource; + u32 dmas = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); if( vv->streaming != fh ) { @@ -717,6 +746,19 @@ static int video_end(struct saa7146_fh * return -EINVAL; } + fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); + /* we need to have a valid format set here */ + BUG_ON(NULL == fmt); + + if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { + resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; + dmas = MASK_22 | MASK_21 | MASK_20; + } else { + resource = RESOURCE_DMA1_HPS; + dmas = MASK_20; + } + saa7146_res_free(fh, resource); + spin_lock_irqsave(&dev->slock,flags); /* disable rps0 */ @@ -725,14 +767,8 @@ static int video_end(struct saa7146_fh * /* disable rps0 irqs */ IER_DISABLE(dev, MASK_27); - // fixme: only used formats here! - /* fixme: look at planar formats here, especially at the - shutdown of planar formats! */ - /* shut down all used video dma transfers */ - /* fixme: what about the budget-dvb cards? they use - video-dma3, but video_end should not get called anyway ...*/ - saa7146_write(dev, MC1, 0x00700000); + saa7146_write(dev, MC1, dmas); vv->streaming = NULL; @@ -849,8 +885,12 @@ int saa7146_video_do_ioctl(struct inode return -EINVAL; } - down(&dev->lock); + /* planar formats are not allowed for overlay video, clipping and video dma would clash */ + if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { + DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat)); + } + down(&dev->lock); if( vv->ov_data != NULL ) { ov_fh = vv->ov_data->fh; saa7146_stop_preview(ov_fh); @@ -1002,7 +1042,9 @@ int saa7146_video_do_ioctl(struct inode return -EBUSY; } + DEB_D(("before getting lock...\n")); down(&dev->lock); + DEB_D(("got lock\n")); if( vv->ov_data != NULL ) { ov_fh = vv->ov_data->fh; @@ -1047,22 +1089,33 @@ int saa7146_video_do_ioctl(struct inode if( 0 != on ) { if( vv->ov_data != NULL ) { if( fh != vv->ov_data->fh) { + DEB_D(("overlay already active in another open\n")); return -EAGAIN; } } + + if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { + DEB_D(("cannot get overlay resources\n")); + return -EBUSY; + } + spin_lock_irqsave(&dev->slock,flags); err = saa7146_start_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); - } else { + return err; + } + if( vv->ov_data != NULL ) { if( fh != vv->ov_data->fh) { + DEB_D(("overlay is active, but in another open\n")); return -EAGAIN; } } spin_lock_irqsave(&dev->slock,flags); err = saa7146_stop_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); - } + /* free resources */ + saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); return err; } case VIDIOC_REQBUFS: { @@ -1093,7 +1146,13 @@ int saa7146_video_do_ioctl(struct inode int *type = arg; DEB_D(("VIDIOC_STREAMON, type:%d\n",*type)); - if( 0 != (err = video_begin(fh))) { + if( fh == vv->streaming ) { + DEB_D(("already capturing.\n")); + return 0; + } + + err = video_begin(fh); + if( 0 != err) { return err; } err = videobuf_streamon(file,q); @@ -1103,6 +1162,12 @@ int saa7146_video_do_ioctl(struct inode int *type = arg; DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type)); + + if( fh != vv->streaming ) { + DEB_D(("this open is not capturing.\n")); + return -EINVAL; + } + err = videobuf_streamoff(file,q); video_end(fh, file); return err; @@ -1309,7 +1374,7 @@ static void video_init(struct saa7146_de } -static void video_open(struct saa7146_dev *dev, struct file *file) +static int video_open(struct saa7146_dev *dev, struct file *file) { struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; struct saa7146_format *sfmt; @@ -1329,6 +1394,8 @@ static void video_open(struct saa7146_de sizeof(struct saa7146_buf)); init_MUTEX(&fh->video_q.lock); + + return 0; } @@ -1381,20 +1448,35 @@ static ssize_t video_read(struct file *f DEB_EE(("called.\n")); + /* fixme: should we allow read() captures while streaming capture? */ + if( 0 != vv->streaming ) { + DEB_S(("already capturing.\n")); + return -EBUSY; + } + + /* stop any active overlay */ if( vv->ov_data != NULL ) { ov_fh = vv->ov_data->fh; saa7146_stop_preview(ov_fh); + saa7146_res_free(ov_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); restart_overlay = 1; } - if( 0 != video_begin(fh)) { - return -EAGAIN; + ret = video_begin(fh); + if( 0 != ret) { + goto out; } + ret = videobuf_read_one(file,&fh->video_q , data, count, ppos); video_end(fh, file); +out: /* restart overlay if it was active before */ if( 0 != restart_overlay ) { + if (0 == saa7146_res_get(ov_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { + DEB_D(("cannot get overlay resources again!\n")); + BUG(); + } saa7146_start_preview(ov_fh); } diff -puN include/media/saa7146.h~dvb-02-update-saa7146 include/media/saa7146.h --- 25/include/media/saa7146.h~dvb-02-update-saa7146 2004-01-18 16:26:08.000000000 -0800 +++ 25-akpm/include/media/saa7146.h 2004-01-18 16:26:08.000000000 -0800 @@ -67,6 +67,8 @@ struct saa7146_pgtable { dma_addr_t dma; /* used for offsets for u,v planes for planar capture modes */ unsigned long offset; + /* used for custom pagetables (used for example by budget dvb cards) */ + struct scatterlist *slist; }; struct saa7146_pci_extension_data { diff -puN include/media/saa7146_vv.h~dvb-02-update-saa7146 include/media/saa7146_vv.h --- 25/include/media/saa7146_vv.h~dvb-02-update-saa7146 2004-01-18 16:26:08.000000000 -0800 +++ 25-akpm/include/media/saa7146_vv.h 2004-01-18 16:26:08.000000000 -0800 @@ -26,12 +26,15 @@ struct saa7146_video_dma { u32 num_line_byte; }; +#define FORMAT_BYTE_SWAP 0x1 +#define FORMAT_IS_PLANAR 0x2 + struct saa7146_format { char *name; - int pixelformat; + u32 pixelformat; u32 trans; u8 depth; - int swap; + u8 flags; }; struct saa7146_standard @@ -97,6 +100,8 @@ struct saa7146_fh { struct videobuf_queue vbi_q; struct v4l2_vbi_format vbi_fmt; struct timer_list vbi_read_timeout; + + unsigned int resources; /* resource management for device open */ }; struct saa7146_vv @@ -136,6 +141,8 @@ struct saa7146_vv int current_hps_sync; struct saa7146_dma d_clipping; /* pointer to clipping memory */ + + unsigned int resources; /* resource management for device */ }; #define SAA7146_EXCLUSIVE 0x1 @@ -149,7 +156,6 @@ struct saa7146_extension_ioctls }; /* flags */ -// #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 */ struct saa7146_ext_vv @@ -171,7 +177,7 @@ struct saa7146_ext_vv struct saa7146_use_ops { void (*init)(struct saa7146_dev *, struct saa7146_vv *); - void(*open)(struct saa7146_dev *, struct file *); + int(*open)(struct saa7146_dev *, struct file *); void (*release)(struct saa7146_dev *, struct file *); void (*irq_done)(struct saa7146_dev *, unsigned long status); ssize_t (*read)(struct file *, char *, size_t, loff_t *); @@ -189,9 +195,10 @@ void saa7146_dma_free(struct saa7146_dev int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv); int saa7146_vv_release(struct saa7146_dev* dev); - /* from saa7146_hlp.c */ -void saa7146_set_overlay(struct saa7146_dev *dev, struct saa7146_fh *fh, int v); +int saa7146_enable_overlay(struct saa7146_fh *fh); +void saa7146_disable_overlay(struct saa7146_fh *fh); + void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next); void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) ; void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sync); @@ -205,6 +212,16 @@ int saa7146_stop_preview(struct saa7146_ /* from saa7146_vbi.c */ extern struct saa7146_use_ops saa7146_vbi_uops; +/* resource management functions */ +int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit); +int saa7146_res_check(struct saa7146_fh *fh, unsigned int bit); +int saa7146_res_locked(struct saa7146_dev *dev, unsigned int bit); +void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits); + +#define RESOURCE_DMA1_HPS 0x1 +#define RESOURCE_DMA2_CLP 0x2 +#define RESOURCE_DMA3_BRS 0x4 + /* saa7146 source inputs */ #define SAA7146_HPS_SOURCE_PORT_A 0x00 #define SAA7146_HPS_SOURCE_PORT_B 0x01 _