summaryrefslogtreecommitdiff
path: root/linux/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers')
-rw-r--r--linux/drivers/media/common/saa7146_fops.c80
-rw-r--r--linux/drivers/media/common/saa7146_hlp.c70
-rw-r--r--linux/drivers/media/common/saa7146_vbi.c12
-rw-r--r--linux/drivers/media/common/saa7146_video.c127
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);