Commit 9dab501b authored by Michael Hunold's avatar Michael Hunold Committed by Linus Torvalds

[PATCH] V4L: Update the saa7146 driver

 - [DVB] saa7146 driver updates:
   - remove bogus v_calc and h_calc parameters, which can be easily
     retrieved from other values
   - add class parameter to i2c initialization
   - let resource handling provide more useful informations
   - sanitize overlay/capture locking
parent 196c4ebd
...@@ -10,14 +10,14 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) ...@@ -10,14 +10,14 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
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;
if (fh->resources & bit) if (fh->resources & bit) {
DEB_D(("already allocated! want: 0x%02x, cur:0x%02x\n",bit,vv->resources));
/* have it already allocated */ /* have it already allocated */
return 1; return 1;
}
/* is it free? */ /* is it free? */
DEB_D(("getting lock...\n"));
down(&dev->lock); down(&dev->lock);
DEB_D(("got lock\n"));
if (vv->resources & bit) { if (vv->resources & bit) {
DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit)); DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
/* no, someone else uses it */ /* no, someone else uses it */
...@@ -27,7 +27,7 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) ...@@ -27,7 +27,7 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
/* it's free, grab it */ /* it's free, grab it */
fh->resources |= bit; fh->resources |= bit;
vv->resources |= bit; vv->resources |= bit;
DEB_D(("res: get %d\n",bit)); DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
up(&dev->lock); up(&dev->lock);
return 1; return 1;
} }
...@@ -51,12 +51,10 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) ...@@ -51,12 +51,10 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
if ((fh->resources & bits) != bits) if ((fh->resources & bits) != bits)
BUG(); BUG();
DEB_D(("getting lock...\n"));
down(&dev->lock); down(&dev->lock);
DEB_D(("got lock\n"));
fh->resources &= ~bits; fh->resources &= ~bits;
vv->resources &= ~bits; vv->resources &= ~bits;
DEB_D(("res: put %d\n",bits)); DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
up(&dev->lock); up(&dev->lock);
} }
......
...@@ -536,13 +536,13 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e ...@@ -536,13 +536,13 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e
/* set vertical scale */ /* set vertical scale */
hps_v_scale = 0; /* all bits get set by the function-call */ hps_v_scale = 0; /* all bits get set by the function-call */
hps_v_gain = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/ hps_v_gain = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/
calculate_v_scale_registers(dev, field, vv->standard->v_calc, height, &hps_v_scale, &hps_v_gain); calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain);
/* set horizontal scale */ /* set horizontal scale */
hps_ctrl = 0; hps_ctrl = 0;
hps_h_prescale = 0; /* all bits get set in the function */ hps_h_prescale = 0; /* all bits get set in the function */
hps_h_scale = 0; hps_h_scale = 0;
calculate_h_scale_registers(dev, vv->standard->h_calc, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale); calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
/* set hyo and hxo */ /* set hyo and hxo */
calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl); calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl);
......
...@@ -400,7 +400,7 @@ static struct i2c_algorithm saa7146_algo = { ...@@ -400,7 +400,7 @@ static struct i2c_algorithm saa7146_algo = {
.functionality = saa7146_i2c_func, .functionality = saa7146_i2c_func,
}; };
int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate) int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, unsigned int class, u32 bitrate)
{ {
DEB_EE(("bitrate: 0x%08x\n",bitrate)); DEB_EE(("bitrate: 0x%08x\n",bitrate));
...@@ -417,16 +417,13 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c ...@@ -417,16 +417,13 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
i2c_adapter->data = dev; i2c_adapter->data = dev;
#else #else
i2c_set_adapdata(i2c_adapter,dev); i2c_set_adapdata(i2c_adapter,dev);
i2c_adapter->class = class;
#endif #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;
......
...@@ -5,6 +5,12 @@ static int memory = 32; ...@@ -5,6 +5,12 @@ static int memory = 32;
MODULE_PARM(memory,"i"); MODULE_PARM(memory,"i");
MODULE_PARM_DESC(memory, "maximum memory usage for capture buffers (default: 32Mb)"); MODULE_PARM_DESC(memory, "maximum memory usage for capture buffers (default: 32Mb)");
#define IS_CAPTURE_ACTIVE(fh) \
(((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh))
#define IS_OVERLAY_ACTIVE(fh) \
(((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh))
/* format descriptions for capture and preview */ /* format descriptions for capture and preview */
static struct saa7146_format formats[] = { static struct saa7146_format formats[] = {
{ {
...@@ -260,24 +266,31 @@ int saa7146_start_preview(struct saa7146_fh *fh) ...@@ -260,24 +266,31 @@ int saa7146_start_preview(struct saa7146_fh *fh)
return -EAGAIN; return -EAGAIN;
} }
/* check if overlay is running */ /* check if streaming capture is running */
if( 0 != vv->ov_data ) { if (IS_CAPTURE_ACTIVE(fh) != 0) {
if( fh != vv->ov_data->fh ) { DEB_D(("streaming capture is active.\n"));
DEB_D(("overlay is running in another open.\n")); return -EBUSY;
return -EAGAIN;
} }
/* check if overlay is running */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
if (vv->video_fh == fh) {
DEB_D(("overlay is already active.\n")); DEB_D(("overlay is already active.\n"));
return 0; return 0;
} }
DEB_D(("overlay is already active in another open.\n"));
return -EBUSY;
}
if( 0 != vv->streaming ) { if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
DEB_D(("streaming capture is active.\n")); DEB_D(("cannot get necessary overlay resources\n"));
return -EBUSY; return -EBUSY;
} }
err = try_win(dev,&fh->ov.win); err = try_win(dev,&fh->ov.win);
if (0 != err) { if (0 != err) {
return err; saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
return -EBUSY;
} }
vv->ov_data = &fh->ov; vv->ov_data = &fh->ov;
...@@ -288,11 +301,14 @@ int saa7146_start_preview(struct saa7146_fh *fh) ...@@ -288,11 +301,14 @@ int saa7146_start_preview(struct saa7146_fh *fh)
vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field])); vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field]));
if (0 != (ret = saa7146_enable_overlay(fh))) { if (0 != (ret = saa7146_enable_overlay(fh))) {
vv->ov_data = NULL;
DEB_D(("enabling overlay failed: %d\n",ret)); DEB_D(("enabling overlay failed: %d\n",ret));
saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
return ret; return ret;
} }
vv->video_status = STATUS_OVERLAY;
vv->video_fh = fh;
return 0; return 0;
} }
...@@ -303,20 +319,30 @@ int saa7146_stop_preview(struct saa7146_fh *fh) ...@@ -303,20 +319,30 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
DEB_EE(("dev:%p, fh:%p\n",dev,fh)); DEB_EE(("dev:%p, fh:%p\n",dev,fh));
/* check if overlay is running */ /* check if streaming capture is running */
if( 0 == vv->ov_data ) { if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("overlay is not active.\n")); DEB_D(("streaming capture is active.\n"));
return 0; return -EBUSY;
} }
if( fh != vv->ov_data->fh ) { /* check if overlay is running at all */
DEB_D(("overlay is active, but for another open.\n")); if ((vv->video_status & STATUS_OVERLAY) == 0) {
DEB_D(("no active overlay.\n"));
return 0; return 0;
} }
vv->ov_data = NULL; if (vv->video_fh != fh) {
DEB_D(("overlay is active, but in another open.\n"));
return -EBUSY;
}
vv->video_status = 0;
vv->video_fh = NULL;
saa7146_disable_overlay(fh); saa7146_disable_overlay(fh);
saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
return 0; return 0;
} }
...@@ -325,15 +351,14 @@ static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f) ...@@ -325,15 +351,14 @@ static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
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;
unsigned long flags;
int err; int err;
switch (f->type) { switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE:
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh)); DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
if( fh == vv->streaming ) { if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_EE(("streaming capture is active")); DEB_EE(("streaming capture is active\n"));
return -EAGAIN; return -EBUSY;
} }
err = try_fmt(fh,f); err = try_fmt(fh,f);
if (0 != err) if (0 != err)
...@@ -359,16 +384,13 @@ static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f) ...@@ -359,16 +384,13 @@ static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
/* fh->ov.fh is used to indicate that we have valid overlay informations, too */ /* fh->ov.fh is used to indicate that we have valid overlay informations, too */
fh->ov.fh = fh; fh->ov.fh = fh;
/* check if we have an active overlay */ up(&dev->lock);
if( vv->ov_data != NULL ) {
if( fh == vv->ov_data->fh) { /* check if our current overlay is active */
spin_lock_irqsave(&dev->slock,flags); if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh); saa7146_stop_preview(fh);
saa7146_start_preview(fh); saa7146_start_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags);
}
} }
up(&dev->lock);
return 0; return 0;
default: default:
DEB_D(("unknown format type '%d'\n",f->type)); DEB_D(("unknown format type '%d'\n",f->type));
...@@ -480,8 +502,6 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) ...@@ -480,8 +502,6 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
const struct v4l2_queryctrl* ctrl; const struct v4l2_queryctrl* ctrl;
unsigned long flags;
int restart_overlay = 0;
ctrl = ctrl_by_id(c->id); ctrl = ctrl_by_id(c->id);
if (NULL == ctrl) { if (NULL == ctrl) {
...@@ -489,6 +509,8 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) ...@@ -489,6 +509,8 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
return -EINVAL; return -EINVAL;
} }
down(&dev->lock);
switch (ctrl->type) { switch (ctrl->type) {
case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_MENU:
...@@ -528,35 +550,31 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) ...@@ -528,35 +550,31 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
break; break;
} }
case V4L2_CID_HFLIP: case V4L2_CID_HFLIP:
/* fixme: we can supfhrt changing VFLIP and HFLIP here... */ /* fixme: we can support changing VFLIP and HFLIP here... */
if( 0 != vv->streaming ) { if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_HFLIP while active capture.\n")); DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
up(&dev->lock);
return -EINVAL; return -EINVAL;
} }
vv->hflip = c->value; vv->hflip = c->value;
restart_overlay = 1;
break; break;
case V4L2_CID_VFLIP: case V4L2_CID_VFLIP:
if( 0 != vv->streaming ) { if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_VFLIP while active capture.\n")); DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
up(&dev->lock);
return -EINVAL; return -EINVAL;
} }
vv->vflip = c->value; vv->vflip = c->value;
restart_overlay = 1;
break; break;
default: { default: {
return -EINVAL; return -EINVAL;
} }
} }
if( 0 != restart_overlay ) { up(&dev->lock);
if( 0 != vv->ov_data ) {
if( fh == vv->ov_data->fh ) { if (IS_OVERLAY_ACTIVE(fh) != 0) {
spin_lock_irqsave(&dev->slock,flags);
saa7146_stop_preview(fh); saa7146_stop_preview(fh);
saa7146_start_preview(fh); saa7146_start_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags);
}
}
} }
return 0; return 0;
} }
...@@ -687,21 +705,30 @@ static int video_begin(struct saa7146_fh *fh) ...@@ -687,21 +705,30 @@ static int video_begin(struct saa7146_fh *fh)
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;
struct saa7146_format *fmt = NULL; struct saa7146_format *fmt = NULL;
unsigned long flags;
unsigned int resource; unsigned int resource;
int ret = 0; int ret = 0, err = 0;
DEB_EE(("dev:%p, fh:%p\n",dev,fh)); DEB_EE(("dev:%p, fh:%p\n",dev,fh));
if( fh == vv->streaming ) { if ((vv->video_status & STATUS_CAPTURE) != 0) {
if (vv->video_fh == fh) {
DEB_S(("already capturing.\n")); DEB_S(("already capturing.\n"));
return -EBUSY; return 0;
} }
if( vv->streaming != 0 ) { DEB_S(("already capturing in another open.\n"));
DEB_S(("already capturing, but in another open.\n"));
return -EBUSY; return -EBUSY;
} }
if ((vv->video_status & STATUS_OVERLAY) != 0) {
DEB_S(("warning: suspending overlay video for streaming capture.\n"));
vv->ov_suspend = vv->video_fh;
err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
if (0 != err) {
DEB_D(("suspending video failed. aborting\n"));
return err;
}
}
fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
/* we need to have a valid format set here */ /* we need to have a valid format set here */
BUG_ON(NULL == fmt); BUG_ON(NULL == fmt);
...@@ -715,19 +742,22 @@ static int video_begin(struct saa7146_fh *fh) ...@@ -715,19 +742,22 @@ static int video_begin(struct saa7146_fh *fh)
ret = saa7146_res_get(fh, resource); ret = saa7146_res_get(fh, resource);
if (0 == ret) { if (0 == ret) {
DEB_S(("cannot get capture resource %d\n",resource)); DEB_S(("cannot get capture resource %d\n",resource));
if (vv->ov_suspend != NULL) {
saa7146_start_preview(vv->ov_suspend);
vv->ov_suspend = NULL;
}
return -EBUSY; return -EBUSY;
} }
spin_lock_irqsave(&dev->slock,flags);
/* clear out beginning of streaming bit (rps register 0)*/ /* clear out beginning of streaming bit (rps register 0)*/
saa7146_write(dev, MC2, MASK_27 ); saa7146_write(dev, MC2, MASK_27 );
/* enable rps0 irqs */ /* enable rps0 irqs */
IER_ENABLE(dev, MASK_27); IER_ENABLE(dev, MASK_27);
vv->streaming = fh; vv->video_fh = fh;
spin_unlock_irqrestore(&dev->slock,flags); vv->video_status = STATUS_CAPTURE;
return 0; return 0;
} }
...@@ -741,9 +771,14 @@ static int video_end(struct saa7146_fh *fh, struct file *file) ...@@ -741,9 +771,14 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
u32 dmas = 0; u32 dmas = 0;
DEB_EE(("dev:%p, fh:%p\n",dev,fh)); DEB_EE(("dev:%p, fh:%p\n",dev,fh));
if( vv->streaming != fh ) { if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
DEB_S(("not capturing.\n")); DEB_S(("not capturing.\n"));
return -EINVAL; return 0;
}
if (vv->video_fh != fh) {
DEB_S(("capturing, but in another open.\n"));
return -EBUSY;
} }
fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
...@@ -757,8 +792,6 @@ static int video_end(struct saa7146_fh *fh, struct file *file) ...@@ -757,8 +792,6 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
resource = RESOURCE_DMA1_HPS; resource = RESOURCE_DMA1_HPS;
dmas = MASK_22; dmas = MASK_22;
} }
saa7146_res_free(fh, resource);
spin_lock_irqsave(&dev->slock,flags); spin_lock_irqsave(&dev->slock,flags);
/* disable rps0 */ /* disable rps0 */
...@@ -770,13 +803,20 @@ static int video_end(struct saa7146_fh *fh, struct file *file) ...@@ -770,13 +803,20 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
/* shut down all used video dma transfers */ /* shut down all used video dma transfers */
saa7146_write(dev, MC1, dmas); saa7146_write(dev, MC1, dmas);
vv->streaming = NULL;
spin_unlock_irqrestore(&dev->slock, flags); spin_unlock_irqrestore(&dev->slock, flags);
return 0; vv->video_fh = NULL;
vv->video_status = 0;
saa7146_res_free(fh, resource);
if (vv->ov_suspend != NULL) {
saa7146_start_preview(vv->ov_suspend);
vv->ov_suspend = NULL;
} }
return 0;
}
/* /*
* This function is _not_ called directly, but from * This function is _not_ called directly, but from
...@@ -790,7 +830,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -790,7 +830,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
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;
unsigned long flags;
int err = 0, result = 0, ee = 0; int err = 0, result = 0, ee = 0;
struct saa7146_use_ops *ops; struct saa7146_use_ops *ops;
...@@ -867,17 +906,12 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -867,17 +906,12 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
{ {
struct v4l2_framebuffer *fb = arg; struct v4l2_framebuffer *fb = arg;
struct saa7146_format *fmt; struct saa7146_format *fmt;
struct saa7146_fh *ov_fh = NULL;
int restart_overlay = 0;
DEB_EE(("VIDIOC_S_FBUF\n")); DEB_EE(("VIDIOC_S_FBUF\n"));
/* if(!capable(CAP_SYS_ADMIN) &&
if(!capable(CAP_SYS_ADMIN)) { // && !capable(CAP_SYS_RAWIO)) { !capable(CAP_SYS_RAWIO))
DEB_D(("VIDIOC_S_FBUF: not CAP_SYS_ADMIN or CAP_SYS_RAWIO.\n"));
return -EPERM; return -EPERM;
}
*/
/* check args */ /* check args */
fmt = format_by_fourcc(dev,fb->fmt.pixelformat); fmt = format_by_fourcc(dev,fb->fmt.pixelformat);
...@@ -890,13 +924,16 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -890,13 +924,16 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat)); DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat));
} }
down(&dev->lock); /* check if overlay is running */
if( vv->ov_data != NULL ) { if (IS_OVERLAY_ACTIVE(fh) != 0) {
ov_fh = vv->ov_data->fh; if (vv->video_fh != fh) {
saa7146_stop_preview(ov_fh); DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));
restart_overlay = 1; return -EBUSY;
}
} }
down(&dev->lock);
/* ok, accept it */ /* ok, accept it */
vv->ov_fb = *fb; vv->ov_fb = *fb;
vv->ov_fmt = fmt; vv->ov_fmt = fmt;
...@@ -904,10 +941,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -904,10 +941,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.bytesperline =
vv->ov_fb.fmt.width*fmt->depth/8; vv->ov_fb.fmt.width*fmt->depth/8;
if( 0 != restart_overlay ) {
saa7146_start_preview(ov_fh);
}
up(&dev->lock); up(&dev->lock);
return 0; return 0;
...@@ -966,11 +999,13 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -966,11 +999,13 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
return get_control(fh,arg); return get_control(fh,arg);
} }
case VIDIOC_S_CTRL: case VIDIOC_S_CTRL:
{ {
DEB_EE(("VIDIOC_S_CTRL\n")); DEB_EE(("VIDIOC_S_CTRL\n"));
down(&dev->lock);
err = set_control(fh,arg); err = set_control(fh,arg);
up(&dev->lock);
return err; return err;
} }
case VIDIOC_G_PARM: case VIDIOC_G_PARM:
...@@ -1029,29 +1064,27 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1029,29 +1064,27 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
case VIDIOC_S_STD: case VIDIOC_S_STD:
{ {
v4l2_std_id *id = arg; v4l2_std_id *id = arg;
int i;
int restart_overlay = 0;
int found = 0; int found = 0;
int i, err;
struct saa7146_fh *ov_fh = NULL;
DEB_EE(("VIDIOC_S_STD\n")); DEB_EE(("VIDIOC_S_STD\n"));
if( 0 != vv->streaming ) { if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
DEB_D(("cannot change video standard while streaming capture is active\n"));
return -EBUSY; return -EBUSY;
} }
DEB_D(("before getting lock...\n")); if ((vv->video_status & STATUS_OVERLAY) != 0) {
down(&dev->lock); vv->ov_suspend = vv->video_fh;
DEB_D(("got lock\n")); err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
if (0 != err) {
if( vv->ov_data != NULL ) { DEB_D(("suspending video failed. aborting\n"));
ov_fh = vv->ov_data->fh; return err;
saa7146_stop_preview(ov_fh); }
restart_overlay = 1;
} }
down(&dev->lock);
for(i = 0; i < dev->ext_vv_data->num_stds; i++) for(i = 0; i < dev->ext_vv_data->num_stds; i++)
if (*id & dev->ext_vv_data->stds[i].id) if (*id & dev->ext_vv_data->stds[i].id)
break; break;
...@@ -1062,11 +1095,13 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1062,11 +1095,13 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
found = 1; found = 1;
} }
if( 0 != restart_overlay ) {
saa7146_start_preview(ov_fh);
}
up(&dev->lock); up(&dev->lock);
if (vv->ov_suspend != NULL) {
saa7146_start_preview(vv->ov_suspend);
vv->ov_suspend = NULL;
}
if( 0 == found ) { if( 0 == found ) {
DEB_EE(("VIDIOC_S_STD: standard not found.\n")); DEB_EE(("VIDIOC_S_STD: standard not found.\n"));
return -EINVAL; return -EINVAL;
...@@ -1076,49 +1111,20 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1076,49 +1111,20 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
return 0; return 0;
} }
case VIDIOC_OVERLAY: case VIDIOC_OVERLAY:
{ {
int on = *(int *)arg; int on = *(int *)arg;
int err = 0; int err = 0;
if( NULL == vv->ov_fmt && on != 0 ) {
DEB_D(("VIDIOC_OVERLAY: no framebuffer informations. call S_FBUF first!\n"));
return -EAGAIN;
}
DEB_D(("VIDIOC_OVERLAY on:%d\n",on)); DEB_D(("VIDIOC_OVERLAY on:%d\n",on));
if( 0 != on ) { if (on != 0) {
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); err = saa7146_start_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags);
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;
}
} else { } else {
DEB_D(("overlay is not active\n"));
return 0;
}
spin_lock_irqsave(&dev->slock,flags);
err = saa7146_stop_preview(fh); 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; return err;
} }
case VIDIOC_REQBUFS: { case VIDIOC_REQBUFS: {
...@@ -1149,11 +1155,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1149,11 +1155,6 @@ 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( fh == vv->streaming ) {
DEB_D(("already capturing.\n"));
return 0;
}
err = video_begin(fh); err = video_begin(fh);
if( 0 != err) { if( 0 != err) {
return err; return err;
...@@ -1166,13 +1167,26 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1166,13 +1167,26 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type)); DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type));
if( fh != vv->streaming ) { /* ugly: we need to copy some checks from video_end(),
DEB_D(("this open is not capturing.\n")); because videobuf_streamoff() relies on the capture running.
return -EINVAL; check and fix this */
if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
DEB_S(("not capturing.\n"));
return 0;
}
if (vv->video_fh != fh) {
DEB_S(("capturing, but in another open.\n"));
return -EBUSY;
} }
err = videobuf_streamoff(file,q); err = videobuf_streamoff(file,q);
if (0 != err) {
DEB_D(("warning: videobuf_streamoff() failed.\n"));
video_end(fh, file); video_end(fh, file);
} else {
err = video_end(fh, file);
}
return err; return err;
} }
case VIDIOCGMBUF: case VIDIOCGMBUF:
...@@ -1406,20 +1420,16 @@ static void video_close(struct saa7146_dev *dev, struct file *file) ...@@ -1406,20 +1420,16 @@ static void video_close(struct saa7146_dev *dev, struct file *file)
{ {
struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; 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; int err;
if( 0 != vv->ov_data ) { if (IS_CAPTURE_ACTIVE(fh) != 0) {
if( fh == vv->ov_data->fh ) { err = video_end(fh, file);
spin_lock_irqsave(&dev->slock,flags); } else if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh); err = saa7146_stop_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags);
saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
}
} }
if( fh == vv->streaming ) { /* hmm, why is this function declared void? */
video_end(fh, file); /* return err */
}
} }
...@@ -1447,23 +1457,16 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p ...@@ -1447,23 +1457,16 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
ssize_t ret = 0; ssize_t ret = 0;
int restart_overlay = 0;
struct saa7146_fh *ov_fh = NULL;
DEB_EE(("called.\n")); DEB_EE(("called.\n"));
if ((vv->video_status & STATUS_CAPTURE) != 0) {
/* fixme: should we allow read() captures while streaming capture? */ /* fixme: should we allow read() captures while streaming capture? */
if( 0 != vv->streaming ) { if (vv->video_fh == fh) {
DEB_S(("already capturing.\n")); DEB_S(("already capturing.\n"));
return -EBUSY; return -EBUSY;
} }
DEB_S(("already capturing in another open.\n"));
/* stop any active overlay */ return -EBUSY;
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;
} }
ret = video_begin(fh); ret = video_begin(fh);
...@@ -1472,16 +1475,16 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p ...@@ -1472,16 +1475,16 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p
} }
ret = videobuf_read_one(file,&fh->video_q , data, count, ppos); ret = videobuf_read_one(file,&fh->video_q , data, count, ppos);
if (ret != 0) {
video_end(fh, file); video_end(fh, file);
} else {
ret = video_end(fh, file);
}
out: out:
/* restart overlay if it was active before */ /* restart overlay if it was active before */
if( 0 != restart_overlay ) { if (vv->ov_suspend != NULL) {
if (0 == saa7146_res_get(ov_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { saa7146_start_preview(vv->ov_suspend);
DEB_D(("cannot get overlay resources again!\n")); vv->ov_suspend = NULL;
BUG();
}
saa7146_start_preview(ov_fh);
} }
return ret; return ret;
......
...@@ -154,7 +154,7 @@ struct saa7146_dev ...@@ -154,7 +154,7 @@ struct saa7146_dev
}; };
/* from saa7146_i2c.c */ /* from saa7146_i2c.c */
int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, unsigned int class, u32 bitrate);
int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg msgs[], int num, int retries); int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg msgs[], int num, int retries);
/* from saa7146_core.c */ /* from saa7146_core.c */
......
...@@ -44,11 +44,9 @@ struct saa7146_standard ...@@ -44,11 +44,9 @@ struct saa7146_standard
int v_offset; /* number of lines of vertical offset before processing */ int v_offset; /* number of lines of vertical offset before processing */
int v_field; /* number of lines in a field for HPS to process */ int v_field; /* number of lines in a field for HPS to process */
int v_calc; /* number of vertical active lines */
int h_offset; /* horizontal offset of processing window */ int h_offset; /* horizontal offset of processing window */
int h_pixels; /* number of horizontal pixels to process */ int h_pixels; /* number of horizontal pixels to process */
int h_calc; /* number of horizontal active pixels */
int v_max_out; int v_max_out;
int h_max_out; int h_max_out;
...@@ -104,6 +102,9 @@ struct saa7146_fh { ...@@ -104,6 +102,9 @@ struct saa7146_fh {
unsigned int resources; /* resource management for device open */ unsigned int resources; /* resource management for device open */
}; };
#define STATUS_OVERLAY 0x01
#define STATUS_CAPTURE 0x02
struct saa7146_vv struct saa7146_vv
{ {
int vbi_minor; int vbi_minor;
...@@ -117,14 +118,17 @@ struct saa7146_vv ...@@ -117,14 +118,17 @@ struct saa7146_vv
int video_minor; int video_minor;
int video_status;
struct saa7146_fh *video_fh;
/* video overlay */ /* video overlay */
struct v4l2_framebuffer ov_fb; struct v4l2_framebuffer ov_fb;
struct saa7146_format *ov_fmt; struct saa7146_format *ov_fmt;
struct saa7146_overlay *ov_data; struct saa7146_overlay *ov_data;
struct saa7146_fh *ov_suspend;
/* video capture */ /* video capture */
struct saa7146_dmaqueue video_q; struct saa7146_dmaqueue video_q;
struct saa7146_fh *streaming;
enum v4l2_field last_field; enum v4l2_field last_field;
/* common: fixme? shouldn't this be in saa7146_fh? /* common: fixme? shouldn't this be in saa7146_fh?
......
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