diff options
Diffstat (limited to 'linux/drivers')
-rw-r--r-- | linux/drivers/media/common/saa7146_fops.c | 80 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146_hlp.c | 70 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146_vbi.c | 12 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146_video.c | 127 |
4 files changed, 199 insertions, 90 deletions
diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c index f29c6c2a7..d22311d28 100644 --- a/linux/drivers/media/common/saa7146_fops.c +++ b/linux/drivers/media/common/saa7146_fops.c @@ -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, struct file *file) } 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 --git a/linux/drivers/media/common/saa7146_hlp.c b/linux/drivers/media/common/saa7146_hlp.c index 0fa8cd7ab..16375072b 100644 --- a/linux/drivers/media/common/saa7146_hlp.c +++ b/linux/drivers/media/common/saa7146_hlp.c @@ -488,33 +488,31 @@ static void saa7146_disable_clipping(struct saa7146_dev *dev) 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 ) { - saa7146_disable_clipping(dev); + 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 +658,28 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy 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 +693,8 @@ void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_vi /* 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, 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 +931,7 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71 } 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 +949,6 @@ 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 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 +1025,6 @@ void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struc 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 --git a/linux/drivers/media/common/saa7146_vbi.c b/linux/drivers/media/common/saa7146_vbi.c index da9332f97..01ed438a9 100644 --- a/linux/drivers/media/common/saa7146_vbi.c +++ b/linux/drivers/media/common/saa7146_vbi.c @@ -367,7 +367,7 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) 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; @@ -376,6 +376,12 @@ static void vbi_open(struct saa7146_dev *dev, struct file *file) 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,7 +425,8 @@ static void vbi_open(struct saa7146_dev *dev, struct file *file) } /* upload brs register */ - saa7146_write(dev, MC2, (MASK_08|MASK_24)); + saa7146_write(dev, MC2, (MASK_08|MASK_24)); + return 0; } static void vbi_close(struct saa7146_dev *dev, struct file *file) @@ -431,6 +438,7 @@ static void vbi_close(struct saa7146_dev *dev, struct file *file) 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 --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c index 9462086c6..5a404407c 100644 --- a/linux/drivers/media/common/saa7146_video.c +++ b/linux/drivers/media/common/saa7146_video.c @@ -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_fh *fh) { 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 *fh) 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; } @@ -289,8 +300,8 @@ int saa7146_stop_preview(struct saa7146_fh *fh) { 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,12 +311,12 @@ int saa7146_stop_preview(struct saa7146_fh *fh) 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,7 +686,10 @@ static int video_begin(struct saa7146_fh *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)); @@ -687,10 +701,23 @@ static int video_begin(struct saa7146_fh *fh) DEB_S(("already capturing, but in another open.\n")); return -EBUSY; } + + fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); + /* we need to have a valid format set here */ + BUG_ON(NULL == fmt); - /* fixme: check for planar formats here, if we will interfere with - vbi capture for example */ + 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); /* clear out beginning of streaming bit (rps register 0)*/ @@ -708,8 +735,10 @@ static int video_end(struct saa7146_fh *fh, struct file *file) { 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 *fh, struct file *file) 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 = 0x00700000; + } else { + resource = RESOURCE_DMA1_HPS; + dmas = 0x00100000; + } + saa7146_res_free(fh, resource); + spin_lock_irqsave(&dev->slock,flags); /* disable rps0 */ @@ -725,14 +767,8 @@ static int video_end(struct saa7146_fh *fh, struct file *file) /* 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; @@ -1001,8 +1037,10 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int 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; saa7146_stop_preview(ov_fh); @@ -1046,22 +1084,33 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int 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 { - if( vv->ov_data != NULL ) { - if( fh != vv->ov_data->fh) { - return -EAGAIN; - } + 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); } + 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: { @@ -1091,9 +1140,10 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int case VIDIOC_STREAMON: { int *type = arg; DEB_D(("VIDIOC_STREAMON, type:%d\n",*type)); - - if( 0 != (err = video_begin(fh))) { - return err; + + err = video_begin(fh); + if( 0 != err) { + return err; } err = videobuf_streamon(file,q); return err; @@ -1308,7 +1358,7 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv) } -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; @@ -1328,6 +1378,7 @@ static void video_open(struct saa7146_dev *dev, struct file *file) sizeof(struct saa7146_buf)); init_MUTEX(&fh->video_q.lock); + return 0; } @@ -1374,7 +1425,7 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; ssize_t ret = 0; - + int restart_overlay = 0; struct saa7146_fh *ov_fh = NULL; @@ -1386,9 +1437,11 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p restart_overlay = 1; } - if( 0 != video_begin(fh)) { - return -EAGAIN; + ret = video_begin(fh); + if( 0 != ret) { + return ret; } + ret = videobuf_read_one(file,&fh->video_q , data, count, ppos); video_end(fh, file); |