Commit b960074f authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (10271): saa7146: convert to video_ioctl2.

The conversion to video_ioctl2 is the first phase to converting this driver
to the latest v4l2 framework.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent c9b8b04b
......@@ -308,14 +308,6 @@ static int fops_release(struct file *file)
return 0;
}
static long fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
/*
DEB_EE(("file:%p, cmd:%d, arg:%li\n", file, cmd, arg));
*/
return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl);
}
static int fops_mmap(struct file *file, struct vm_area_struct * vma)
{
struct saa7146_fh *fh = file->private_data;
......@@ -425,7 +417,7 @@ static const struct v4l2_file_operations video_fops =
.write = fops_write,
.poll = fops_poll,
.mmap = fops_mmap,
.ioctl = fops_ioctl,
.ioctl = video_ioctl2,
};
static void vv_callback(struct saa7146_dev *dev, unsigned long status)
......@@ -452,19 +444,16 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
}
}
static struct video_device device_template =
{
.fops = &video_fops,
.minor = -1,
};
int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
{
struct saa7146_vv *vv = kzalloc (sizeof(struct saa7146_vv),GFP_KERNEL);
if( NULL == vv ) {
struct saa7146_vv *vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
if (vv == NULL) {
ERR(("out of memory. aborting.\n"));
return -1;
}
ext_vv->ops = saa7146_video_ioctl_ops;
ext_vv->core_ops = &saa7146_video_ioctl_ops;
DEB_EE(("dev:%p\n",dev));
......@@ -521,6 +510,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
{
struct saa7146_vv *vv = dev->vv_data;
struct video_device *vfd;
int err;
DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
......@@ -529,16 +519,18 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
if (vfd == NULL)
return -ENOMEM;
memcpy(vfd, &device_template, sizeof(struct video_device));
strlcpy(vfd->name, name, sizeof(vfd->name));
vfd->fops = &video_fops;
vfd->ioctl_ops = dev->ext_vv_data ? &dev->ext_vv_data->ops :
&saa7146_video_ioctl_ops;
vfd->release = video_device_release;
strlcpy(vfd->name, name, sizeof(vfd->name));
video_set_drvdata(vfd, dev);
// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
if (video_register_device(vfd, type, -1) < 0) {
err = video_register_device(vfd, type, -1);
if (err < 0) {
ERR(("cannot register v4l2 device. skipping.\n"));
video_device_release(vfd);
return -1;
return err;
}
if( VFL_TYPE_GRABBER == type ) {
......
......@@ -97,172 +97,13 @@ struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc)
return NULL;
}
static int g_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
{
struct saa7146_dev *dev = fh->dev;
DEB_EE(("dev:%p, fh:%p\n",dev,fh));
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
f->fmt.pix = fh->video_fmt;
return 0;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
f->fmt.win = fh->ov.win;
return 0;
case V4L2_BUF_TYPE_VBI_CAPTURE:
{
f->fmt.vbi = fh->vbi_fmt;
return 0;
}
default:
DEB_D(("invalid format type '%d'.\n",f->type));
return -EINVAL;
}
}
static int try_win(struct saa7146_dev *dev, struct v4l2_window *win)
{
struct saa7146_vv *vv = dev->vv_data;
enum v4l2_field field;
int maxw, maxh;
DEB_EE(("dev:%p\n",dev));
if (NULL == vv->ov_fb.base) {
DEB_D(("no fb base set.\n"));
return -EINVAL;
}
if (NULL == vv->ov_fmt) {
DEB_D(("no fb fmt set.\n"));
return -EINVAL;
}
if (win->w.width < 48 || win->w.height < 32) {
DEB_D(("min width/height. (%d,%d)\n",win->w.width,win->w.height));
return -EINVAL;
}
if (win->clipcount > 16) {
DEB_D(("clipcount too big.\n"));
return -EINVAL;
}
field = win->field;
maxw = vv->standard->h_max_out;
maxh = vv->standard->v_max_out;
if (V4L2_FIELD_ANY == field) {
field = (win->w.height > maxh/2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
}
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_ALTERNATE:
maxh = maxh / 2;
break;
case V4L2_FIELD_INTERLACED:
break;
default: {
DEB_D(("no known field mode '%d'.\n",field));
return -EINVAL;
}
}
win->field = field;
if (win->w.width > maxw)
win->w.width = maxw;
if (win->w.height > maxh)
win->w.height = maxh;
return 0;
}
static int try_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
int err;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
{
struct saa7146_format *fmt;
enum v4l2_field field;
int maxw, maxh;
int calc_bpl;
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
fmt = format_by_fourcc(dev,f->fmt.pix.pixelformat);
if (NULL == fmt) {
return -EINVAL;
}
field = f->fmt.pix.field;
maxw = vv->standard->h_max_out;
maxh = vv->standard->v_max_out;
if (V4L2_FIELD_ANY == field) {
field = (f->fmt.pix.height > maxh/2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
}
switch (field) {
case V4L2_FIELD_ALTERNATE: {
vv->last_field = V4L2_FIELD_TOP;
maxh = maxh / 2;
break;
}
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
vv->last_field = V4L2_FIELD_INTERLACED;
maxh = maxh / 2;
break;
case V4L2_FIELD_INTERLACED:
vv->last_field = V4L2_FIELD_INTERLACED;
break;
default: {
DEB_D(("no known field mode '%d'.\n",field));
return -EINVAL;
}
}
f->fmt.pix.field = field;
if (f->fmt.pix.width > maxw)
f->fmt.pix.width = maxw;
if (f->fmt.pix.height > maxh)
f->fmt.pix.height = maxh;
calc_bpl = (f->fmt.pix.width * fmt->depth)/8;
if (f->fmt.pix.bytesperline < calc_bpl)
f->fmt.pix.bytesperline = calc_bpl;
if (f->fmt.pix.bytesperline > (2*PAGE_SIZE * fmt->depth)/8) /* arbitrary constraint */
f->fmt.pix.bytesperline = calc_bpl;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",f->fmt.pix.width,f->fmt.pix.height,f->fmt.pix.bytesperline,f->fmt.pix.sizeimage));
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));
err = try_win(dev,&f->fmt.win);
if (0 != err) {
return err;
}
return 0;
default:
DEB_EE(("unknown format type '%d'\n",f->type));
return -EINVAL;
}
}
static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f);
int saa7146_start_preview(struct saa7146_fh *fh)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
struct v4l2_format fmt;
int ret = 0, err = 0;
DEB_EE(("dev:%p, fh:%p\n",dev,fh));
......@@ -294,12 +135,13 @@ int saa7146_start_preview(struct saa7146_fh *fh)
return -EBUSY;
}
err = try_win(dev,&fh->ov.win);
fmt.fmt.win = fh->ov.win;
err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
if (0 != err) {
saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
return -EBUSY;
}
fh->ov.win = fmt.fmt.win;
vv->ov_data = &fh->ov;
DEB_D(("%dx%d+%d+%d %s field=%s\n",
......@@ -355,58 +197,6 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
}
EXPORT_SYMBOL_GPL(saa7146_stop_preview);
static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
int err;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_EE(("streaming capture is active\n"));
return -EBUSY;
}
err = try_fmt(fh,f);
if (0 != err)
return err;
fh->video_fmt = f->fmt.pix;
DEB_EE(("set to pixelformat '%4.4s'\n",(char *)&fh->video_fmt.pixelformat));
return 0;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));
err = try_win(dev,&f->fmt.win);
if (0 != err)
return err;
mutex_lock(&dev->lock);
fh->ov.win = f->fmt.win;
fh->ov.nclips = f->fmt.win.clipcount;
if (fh->ov.nclips > 16)
fh->ov.nclips = 16;
if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) {
mutex_unlock(&dev->lock);
return -EFAULT;
}
/* fh->ov.fh is used to indicate that we have valid overlay informations, too */
fh->ov.fh = fh;
mutex_unlock(&dev->lock);
/* check if our current overlay is active */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh);
saa7146_start_preview(fh);
}
return 0;
default:
DEB_D(("unknown format type '%d'\n",f->type));
return -EINVAL;
}
}
/********************************************************************************/
/* device controls */
......@@ -463,184 +253,58 @@ static struct v4l2_queryctrl* ctrl_by_id(int id)
return NULL;
}
static int get_control(struct saa7146_fh *fh, struct v4l2_control *c)
/********************************************************************************/
/* common pagetable functions */
static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
struct pci_dev *pci = dev->pci;
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
struct scatterlist *list = dma->sglist;
int length = dma->sglen;
struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
const struct v4l2_queryctrl* ctrl;
u32 value = 0;
DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
ctrl = ctrl_by_id(c->id);
if (NULL == ctrl)
return -EINVAL;
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
value = saa7146_read(dev, BCS_CTRL);
c->value = 0xff & (value >> 24);
DEB_D(("V4L2_CID_BRIGHTNESS: %d\n",c->value));
break;
case V4L2_CID_CONTRAST:
value = saa7146_read(dev, BCS_CTRL);
c->value = 0x7f & (value >> 16);
DEB_D(("V4L2_CID_CONTRAST: %d\n",c->value));
break;
case V4L2_CID_SATURATION:
value = saa7146_read(dev, BCS_CTRL);
c->value = 0x7f & (value >> 0);
DEB_D(("V4L2_CID_SATURATION: %d\n",c->value));
break;
case V4L2_CID_VFLIP:
c->value = vv->vflip;
DEB_D(("V4L2_CID_VFLIP: %d\n",c->value));
if( 0 != IS_PLANAR(sfmt->trans)) {
struct saa7146_pgtable *pt1 = &buf->pt[0];
struct saa7146_pgtable *pt2 = &buf->pt[1];
struct saa7146_pgtable *pt3 = &buf->pt[2];
__le32 *ptr1, *ptr2, *ptr3;
__le32 fill;
int size = buf->fmt->width*buf->fmt->height;
int i,p,m1,m2,m3,o1,o2;
switch( sfmt->depth ) {
case 12: {
/* create some offsets inside the page table */
m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;
m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
o1 = size%PAGE_SIZE;
o2 = (size+(size/4))%PAGE_SIZE;
DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
break;
case V4L2_CID_HFLIP:
c->value = vv->hflip;
DEB_D(("V4L2_CID_HFLIP: %d\n",c->value));
}
case 16: {
/* create some offsets inside the page table */
m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
o1 = size%PAGE_SIZE;
o2 = (size+(size/2))%PAGE_SIZE;
DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
break;
default:
return -EINVAL;
}
return 0;
}
static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
const struct v4l2_queryctrl* ctrl;
ctrl = ctrl_by_id(c->id);
if (NULL == ctrl) {
DEB_D(("unknown control %d\n",c->id));
return -EINVAL;
default: {
return -1;
}
}
mutex_lock(&dev->lock);
switch (ctrl->type) {
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_INTEGER:
if (c->value < ctrl->minimum)
c->value = ctrl->minimum;
if (c->value > ctrl->maximum)
c->value = ctrl->maximum;
break;
default:
/* nothing */;
};
switch (c->id) {
case V4L2_CID_BRIGHTNESS: {
u32 value = saa7146_read(dev, BCS_CTRL);
value &= 0x00ffffff;
value |= (c->value << 24);
saa7146_write(dev, BCS_CTRL, value);
saa7146_write(dev, MC2, MASK_22 | MASK_06 );
break;
}
case V4L2_CID_CONTRAST: {
u32 value = saa7146_read(dev, BCS_CTRL);
value &= 0xff00ffff;
value |= (c->value << 16);
saa7146_write(dev, BCS_CTRL, value);
saa7146_write(dev, MC2, MASK_22 | MASK_06 );
break;
}
case V4L2_CID_SATURATION: {
u32 value = saa7146_read(dev, BCS_CTRL);
value &= 0xffffff00;
value |= (c->value << 0);
saa7146_write(dev, BCS_CTRL, value);
saa7146_write(dev, MC2, MASK_22 | MASK_06 );
break;
}
case V4L2_CID_HFLIP:
/* fixme: we can support changing VFLIP and HFLIP here... */
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
mutex_unlock(&dev->lock);
return -EINVAL;
}
vv->hflip = c->value;
break;
case V4L2_CID_VFLIP:
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
mutex_unlock(&dev->lock);
return -EINVAL;
}
vv->vflip = c->value;
break;
default: {
mutex_unlock(&dev->lock);
return -EINVAL;
}
}
mutex_unlock(&dev->lock);
if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh);
saa7146_start_preview(fh);
}
return 0;
}
/********************************************************************************/
/* common pagetable functions */
static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
{
struct pci_dev *pci = dev->pci;
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
struct scatterlist *list = dma->sglist;
int length = dma->sglen;
struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
if( 0 != IS_PLANAR(sfmt->trans)) {
struct saa7146_pgtable *pt1 = &buf->pt[0];
struct saa7146_pgtable *pt2 = &buf->pt[1];
struct saa7146_pgtable *pt3 = &buf->pt[2];
__le32 *ptr1, *ptr2, *ptr3;
__le32 fill;
int size = buf->fmt->width*buf->fmt->height;
int i,p,m1,m2,m3,o1,o2;
switch( sfmt->depth ) {
case 12: {
/* create some offsets inside the page table */
m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;
m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
o1 = size%PAGE_SIZE;
o2 = (size+(size/4))%PAGE_SIZE;
DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
break;
}
case 16: {
/* create some offsets inside the page table */
m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
o1 = size%PAGE_SIZE;
o2 = (size+(size/2))%PAGE_SIZE;
DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
break;
}
default: {
return -1;
}
}
ptr1 = pt1->cpu;
ptr2 = pt2->cpu;
ptr3 = pt3->cpu;
ptr1 = pt1->cpu;
ptr2 = pt2->cpu;
ptr3 = pt3->cpu;
/* walk all pages, copy all page addresses to ptr1 */
for (i = 0; i < length; i++, list++) {
......@@ -829,72 +493,13 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
return 0;
}
/*
* This function is _not_ called directly, but from
* video_generic_ioctl (and maybe others). userspace
* copying is done already, arg is a kernel pointer.
*/
long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
long err = 0;
int result = 0, ee = 0;
struct saa7146_use_ops *ops;
struct videobuf_queue *q;
/* check if extension handles the command */
for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) {
if( cmd == dev->ext_vv_data->ioctls[ee].cmd )
break;
}
if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) {
DEB_D(("extension handles ioctl exclusive.\n"));
result = dev->ext_vv_data->ioctl(fh, cmd, arg);
return result;
}
if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) {
DEB_D(("extension handles ioctl before.\n"));
result = dev->ext_vv_data->ioctl(fh, cmd, arg);
if( -EAGAIN != result ) {
return result;
}
}
/* fixme: add handle "after" case (is it still needed?) */
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
ops = &saa7146_video_uops;
q = &fh->video_q;
break;
}
case V4L2_BUF_TYPE_VBI_CAPTURE: {
ops = &saa7146_vbi_uops;
q = &fh->vbi_q;
break;
}
default:
BUG();
return 0;
}
switch (cmd) {
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
memset(cap,0,sizeof(*cap));
DEB_EE(("VIDIOC_QUERYCAP\n"));
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
strcpy((char *)cap->driver, "saa7146 v4l2");
strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->version = SAA7146_VERSION_CODE;
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
......@@ -903,38 +508,38 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
V4L2_CAP_STREAMING;
cap->capabilities |= dev->ext_vv_data->capabilities;
return 0;
}
case VIDIOC_G_FBUF:
{
struct v4l2_framebuffer *fb = arg;
}
DEB_EE(("VIDIOC_G_FBUF\n"));
static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
*fb = vv->ov_fb;
fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
return 0;
}
case VIDIOC_S_FBUF:
{
struct v4l2_framebuffer *fb = arg;
}
static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_format *fmt;
DEB_EE(("VIDIOC_S_FBUF\n"));
if(!capable(CAP_SYS_ADMIN) &&
!capable(CAP_SYS_RAWIO))
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
return -EPERM;
/* check args */
fmt = format_by_fourcc(dev,fb->fmt.pixelformat);
if (NULL == fmt) {
fmt = format_by_fourcc(dev, fb->fmt.pixelformat);
if (NULL == fmt)
return -EINVAL;
}
/* 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));
}
if (fmt->flags & FORMAT_IS_PLANAR)
DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",
(char *)&fmt->pixelformat));
/* check if overlay is running */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
......@@ -951,38 +556,30 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
vv->ov_fmt = fmt;
if (0 == 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;
mutex_unlock(&dev->lock);
return 0;
}
case VIDIOC_ENUM_FMT:
{
struct v4l2_fmtdesc *f = arg;
}
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{
if (f->index >= NUM_FORMATS)
return -EINVAL;
strlcpy((char *)f->description, formats[f->index].name,
sizeof(f->description));
f->pixelformat = formats[f->index].pixelformat;
f->flags = 0;
memset(f->reserved, 0, sizeof(f->reserved));
break;
default:
return -EINVAL;
}
DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index));
return 0;
}
case VIDIOC_QUERYCTRL:
{
}
static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt_vid_cap(file, fh, f);
}
static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
{
const struct v4l2_queryctrl *ctrl;
struct v4l2_queryctrl *c = arg;
if ((c->id < V4L2_CID_BASE ||
c->id >= V4L2_CID_LASTP1) &&
......@@ -991,88 +588,378 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return -EINVAL;
ctrl = ctrl_by_id(c->id);
if( NULL == ctrl ) {
if (ctrl == NULL)
return -EINVAL;
/*
c->flags = V4L2_CTRL_FLAG_DISABLED;
return 0;
*/
}
DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n",c->id));
DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id));
*c = *ctrl;
return 0;
}
case VIDIOC_G_CTRL: {
DEB_EE(("VIDIOC_G_CTRL\n"));
return get_control(fh,arg);
}
case VIDIOC_S_CTRL:
{
DEB_EE(("VIDIOC_S_CTRL\n"));
err = set_control(fh,arg);
return err;
}
case VIDIOC_G_PARM:
{
struct v4l2_streamparm *parm = arg;
if( parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ) {
}
static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
const struct v4l2_queryctrl *ctrl;
u32 value = 0;
ctrl = ctrl_by_id(c->id);
if (NULL == ctrl)
return -EINVAL;
}
memset(&parm->parm.capture,0,sizeof(struct v4l2_captureparm));
parm->parm.capture.readbuffers = 1;
// fixme: only for PAL!
parm->parm.capture.timeperframe.numerator = 1;
parm->parm.capture.timeperframe.denominator = 25;
return 0;
}
case VIDIOC_G_FMT:
{
struct v4l2_format *f = arg;
DEB_EE(("VIDIOC_G_FMT\n"));
return g_fmt(fh,f);
}
case VIDIOC_S_FMT:
{
struct v4l2_format *f = arg;
DEB_EE(("VIDIOC_S_FMT\n"));
return s_fmt(fh,f);
}
case VIDIOC_TRY_FMT:
{
struct v4l2_format *f = arg;
DEB_EE(("VIDIOC_TRY_FMT\n"));
return try_fmt(fh,f);
}
case VIDIOC_G_STD:
{
v4l2_std_id *id = arg;
DEB_EE(("VIDIOC_G_STD\n"));
*id = vv->standard->id;
return 0;
}
/* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
PAL / NTSC / SECAM. if your hardware does not (or does more)
-- override this function in your extension */
case VIDIOC_ENUMSTD:
{
struct v4l2_standard *e = arg;
if (e->index < 0 )
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
value = saa7146_read(dev, BCS_CTRL);
c->value = 0xff & (value >> 24);
DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value));
break;
case V4L2_CID_CONTRAST:
value = saa7146_read(dev, BCS_CTRL);
c->value = 0x7f & (value >> 16);
DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value));
break;
case V4L2_CID_SATURATION:
value = saa7146_read(dev, BCS_CTRL);
c->value = 0x7f & (value >> 0);
DEB_D(("V4L2_CID_SATURATION: %d\n", c->value));
break;
case V4L2_CID_VFLIP:
c->value = vv->vflip;
DEB_D(("V4L2_CID_VFLIP: %d\n", c->value));
break;
case V4L2_CID_HFLIP:
c->value = vv->hflip;
DEB_D(("V4L2_CID_HFLIP: %d\n", c->value));
break;
default:
return -EINVAL;
if( e->index < dev->ext_vv_data->num_stds ) {
DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index));
v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
return 0;
}
return 0;
}
static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
const struct v4l2_queryctrl *ctrl;
ctrl = ctrl_by_id(c->id);
if (NULL == ctrl) {
DEB_D(("unknown control %d\n", c->id));
return -EINVAL;
}
case VIDIOC_S_STD:
{
v4l2_std_id *id = arg;
int found = 0;
int i;
DEB_EE(("VIDIOC_S_STD\n"));
mutex_lock(&dev->lock);
switch (ctrl->type) {
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_INTEGER:
if (c->value < ctrl->minimum)
c->value = ctrl->minimum;
if (c->value > ctrl->maximum)
c->value = ctrl->maximum;
break;
default:
/* nothing */;
}
switch (c->id) {
case V4L2_CID_BRIGHTNESS: {
u32 value = saa7146_read(dev, BCS_CTRL);
value &= 0x00ffffff;
value |= (c->value << 24);
saa7146_write(dev, BCS_CTRL, value);
saa7146_write(dev, MC2, MASK_22 | MASK_06);
break;
}
case V4L2_CID_CONTRAST: {
u32 value = saa7146_read(dev, BCS_CTRL);
value &= 0xff00ffff;
value |= (c->value << 16);
saa7146_write(dev, BCS_CTRL, value);
saa7146_write(dev, MC2, MASK_22 | MASK_06);
break;
}
case V4L2_CID_SATURATION: {
u32 value = saa7146_read(dev, BCS_CTRL);
value &= 0xffffff00;
value |= (c->value << 0);
saa7146_write(dev, BCS_CTRL, value);
saa7146_write(dev, MC2, MASK_22 | MASK_06);
break;
}
case V4L2_CID_HFLIP:
/* fixme: we can support changing VFLIP and HFLIP here... */
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
mutex_unlock(&dev->lock);
return -EINVAL;
}
vv->hflip = c->value;
break;
case V4L2_CID_VFLIP:
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
mutex_unlock(&dev->lock);
return -EINVAL;
}
vv->vflip = c->value;
break;
default:
mutex_unlock(&dev->lock);
return -EINVAL;
}
mutex_unlock(&dev->lock);
if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh);
saa7146_start_preview(fh);
}
return 0;
}
static int vidioc_g_parm(struct file *file, void *fh,
struct v4l2_streamparm *parm)
{
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
parm->parm.capture.readbuffers = 1;
/* fixme: only for PAL! */
parm->parm.capture.timeperframe.numerator = 1;
parm->parm.capture.timeperframe.denominator = 25;
return 0;
}
static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt;
return 0;
}
static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
{
f->fmt.win = ((struct saa7146_fh *)fh)->ov.win;
return 0;
}
static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
{
f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt;
return 0;
}
static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_format *fmt;
enum v4l2_field field;
int maxw, maxh;
int calc_bpl;
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
field = f->fmt.pix.field;
maxw = vv->standard->h_max_out;
maxh = vv->standard->v_max_out;
if (V4L2_FIELD_ANY == field) {
field = (f->fmt.pix.height > maxh / 2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
}
switch (field) {
case V4L2_FIELD_ALTERNATE:
vv->last_field = V4L2_FIELD_TOP;
maxh = maxh / 2;
break;
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
vv->last_field = V4L2_FIELD_INTERLACED;
maxh = maxh / 2;
break;
case V4L2_FIELD_INTERLACED:
vv->last_field = V4L2_FIELD_INTERLACED;
break;
default:
DEB_D(("no known field mode '%d'.\n", field));
return -EINVAL;
}
f->fmt.pix.field = field;
if (f->fmt.pix.width > maxw)
f->fmt.pix.width = maxw;
if (f->fmt.pix.height > maxh)
f->fmt.pix.height = maxh;
calc_bpl = (f->fmt.pix.width * fmt->depth) / 8;
if (f->fmt.pix.bytesperline < calc_bpl)
f->fmt.pix.bytesperline = calc_bpl;
if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */
f->fmt.pix.bytesperline = calc_bpl;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width,
f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage));
return 0;
}
static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
struct v4l2_window *win = &f->fmt.win;
enum v4l2_field field;
int maxw, maxh;
DEB_EE(("dev:%p\n", dev));
if (NULL == vv->ov_fb.base) {
DEB_D(("no fb base set.\n"));
return -EINVAL;
}
if (NULL == vv->ov_fmt) {
DEB_D(("no fb fmt set.\n"));
return -EINVAL;
}
if (win->w.width < 48 || win->w.height < 32) {
DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height));
return -EINVAL;
}
if (win->clipcount > 16) {
DEB_D(("clipcount too big.\n"));
return -EINVAL;
}
field = win->field;
maxw = vv->standard->h_max_out;
maxh = vv->standard->v_max_out;
if (V4L2_FIELD_ANY == field) {
field = (win->w.height > maxh / 2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
}
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_ALTERNATE:
maxh = maxh / 2;
break;
case V4L2_FIELD_INTERLACED:
break;
default:
DEB_D(("no known field mode '%d'.\n", field));
return -EINVAL;
}
win->field = field;
if (win->w.width > maxw)
win->w.width = maxw;
if (win->w.height > maxh)
win->w.height = maxh;
return 0;
}
static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f)
{
struct saa7146_fh *fh = __fh;
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
int err;
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_EE(("streaming capture is active\n"));
return -EBUSY;
}
err = vidioc_try_fmt_vid_cap(file, fh, f);
if (0 != err)
return err;
fh->video_fmt = f->fmt.pix;
DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat));
return 0;
}
static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f)
{
struct saa7146_fh *fh = __fh;
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
int err;
DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh));
err = vidioc_try_fmt_vid_overlay(file, fh, f);
if (0 != err)
return err;
mutex_lock(&dev->lock);
fh->ov.win = f->fmt.win;
fh->ov.nclips = f->fmt.win.clipcount;
if (fh->ov.nclips > 16)
fh->ov.nclips = 16;
if (copy_from_user(fh->ov.clips, f->fmt.win.clips,
sizeof(struct v4l2_clip) * fh->ov.nclips)) {
mutex_unlock(&dev->lock);
return -EFAULT;
}
/* fh->ov.fh is used to indicate that we have valid overlay informations, too */
fh->ov.fh = fh;
mutex_unlock(&dev->lock);
/* check if our current overlay is active */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh);
saa7146_start_preview(fh);
}
return 0;
}
static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
*norm = vv->standard->id;
return 0;
}
/* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
PAL / NTSC / SECAM. if your hardware does not (or does more)
-- override this function in your extension */
/*
case VIDIOC_ENUMSTD:
{
struct v4l2_standard *e = arg;
if (e->index < 0 )
return -EINVAL;
if( e->index < dev->ext_vv_data->num_stds ) {
DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index));
v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
return 0;
}
return -EINVAL;
}
*/
static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
int found = 0;
int err, i;
DEB_EE(("VIDIOC_S_STD\n"));
if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
DEB_D(("cannot change video standard while streaming capture is active\n"));
......@@ -1090,12 +977,12 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
mutex_lock(&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)
break;
if (i != dev->ext_vv_data->num_stds) {
vv->standard = &dev->ext_vv_data->stds[i];
if( NULL != dev->ext_vv_data->std_callback )
if (NULL != dev->ext_vv_data->std_callback)
dev->ext_vv_data->std_callback(dev, vv->standard);
found = 1;
}
......@@ -1107,65 +994,96 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
vv->ov_suspend = NULL;
}
if( 0 == found ) {
if (!found) {
DEB_EE(("VIDIOC_S_STD: standard not found.\n"));
return -EINVAL;
}
DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n",vv->standard->name));
DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name));
return 0;
}
case VIDIOC_OVERLAY:
{
int on = *(int *)arg;
}
DEB_D(("VIDIOC_OVERLAY on:%d\n",on));
if (on != 0) {
static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
{
int err;
DEB_D(("VIDIOC_OVERLAY on:%d\n", on));
if (on)
err = saa7146_start_preview(fh);
} else {
else
err = saa7146_stop_preview(fh);
}
return err;
}
case VIDIOC_REQBUFS: {
struct v4l2_requestbuffers *req = arg;
DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type));
return videobuf_reqbufs(q,req);
}
case VIDIOC_QUERYBUF: {
struct v4l2_buffer *buf = arg;
DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset));
return videobuf_querybuf(q,buf);
}
case VIDIOC_QBUF: {
struct v4l2_buffer *buf = arg;
int ret = 0;
ret = videobuf_qbuf(q,buf);
DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index));
return ret;
}
case VIDIOC_DQBUF: {
struct v4l2_buffer *buf = arg;
int ret = 0;
ret = videobuf_dqbuf(q,buf,file->f_flags & O_NONBLOCK);
DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index));
return ret;
}
case VIDIOC_STREAMON: {
int *type = arg;
DEB_D(("VIDIOC_STREAMON, type:%d\n",*type));
}
static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b)
{
struct saa7146_fh *fh = __fh;
if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return videobuf_reqbufs(&fh->video_q, b);
if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE)
return videobuf_reqbufs(&fh->vbi_q, b);
return -EINVAL;
}
static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
{
struct saa7146_fh *fh = __fh;
if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return videobuf_querybuf(&fh->video_q, buf);
if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
return videobuf_querybuf(&fh->vbi_q, buf);
return -EINVAL;
}
static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
{
struct saa7146_fh *fh = __fh;
if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return videobuf_qbuf(&fh->video_q, buf);
if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
return videobuf_qbuf(&fh->vbi_q, buf);
return -EINVAL;
}
static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
{
struct saa7146_fh *fh = __fh;
if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK);
if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK);
return -EINVAL;
}
static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
{
struct saa7146_fh *fh = __fh;
int err;
DEB_D(("VIDIOC_STREAMON, type:%d\n", type));
err = video_begin(fh);
if( 0 != err) {
return err;
}
err = videobuf_streamon(q);
if (err)
return err;
}
case VIDIOC_STREAMOFF: {
int *type = arg;
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return videobuf_streamon(&fh->video_q);
if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
return videobuf_streamon(&fh->vbi_q);
return -EINVAL;
}
DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type));
static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
{
struct saa7146_fh *fh = __fh;
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
int err;
DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type));
/* ugly: we need to copy some checks from video_end(),
because videobuf_streamoff() relies on the capture running.
......@@ -1180,7 +1098,11 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return -EBUSY;
}
err = videobuf_streamoff(q);
err = -EINVAL;
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
err = videobuf_streamoff(&fh->video_q);
else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
err = videobuf_streamoff(&fh->vbi_q);
if (0 != err) {
DEB_D(("warning: videobuf_streamoff() failed.\n"));
video_end(fh, file);
......@@ -1188,40 +1110,68 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
err = video_end(fh, file);
}
return err;
}
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
int i;
static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf)
{
struct saa7146_fh *fh = __fh;
struct videobuf_queue *q = &fh->video_q;
int err, i;
/* fixme: number of capture buffers and sizes for v4l apps */
int gbuffers = 2;
int gbufsize = 768*576*4;
int gbufsize = 768 * 576 * 4;
DEB_D(("VIDIOCGMBUF \n"));
q = &fh->video_q;
err = videobuf_mmap_setup(q,gbuffers,gbufsize,
err = videobuf_mmap_setup(q, gbuffers, gbufsize,
V4L2_MEMORY_MMAP);
if (err < 0)
return err;
gbuffers = err;
memset(mbuf,0,sizeof(*mbuf));
memset(mbuf, 0, sizeof(*mbuf));
mbuf->frames = gbuffers;
mbuf->size = gbuffers * gbufsize;
for (i = 0; i < gbuffers; i++)
mbuf->offsets[i] = i * gbufsize;
return 0;
}
#endif
default:
return v4l_compat_translate_ioctl(file, cmd, arg,
saa7146_video_do_ioctl);
}
return 0;
}
#endif
const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
.vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
.vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_overlay = vidioc_overlay,
.vidioc_g_fbuf = vidioc_g_fbuf,
.vidioc_s_fbuf = vidioc_s_fbuf,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_g_parm = vidioc_g_parm,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
#endif
};
/*********************************************************************************/
/* buffer handling functions */
......
......@@ -316,16 +316,10 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
return 0;
}
static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
{
struct saa7146_dev *dev = fh->dev;
struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
dprintk(4, "saa7146_dev: %p\n", dev);
switch (cmd) {
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *t = arg;
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
u16 stereo_det;
s8 stereo;
......@@ -346,7 +340,7 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
t->signal = 0xffff;
t->afc = 0;
// FIXME: standard / stereo detection is still broken
/* FIXME: standard / stereo detection is still broken */
msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
......@@ -356,20 +350,20 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
/* stereo */
t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
t->audmode = V4L2_TUNER_MODE_STEREO;
}
else if (stereo < -0x10) {
} else if (stereo < -0x10) {
/* bilingual */
t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
t->audmode = V4L2_TUNER_MODE_LANG1;
}
else /* mono */
} else /* mono */
t->rxsubchans = V4L2_TUNER_SUB_MONO;
return 0;
}
case VIDIOC_S_TUNER:
{
struct v4l2_tuner *t = arg;
}
static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
u16 fm_matrix, src;
dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
......@@ -379,27 +373,27 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
switch (t->audmode) {
case V4L2_TUNER_MODE_STEREO:
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
fm_matrix = 0x3001; // stereo
fm_matrix = 0x3001; /* stereo */
src = 0x0020;
break;
case V4L2_TUNER_MODE_LANG1_LANG2:
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
fm_matrix = 0x3000; // bilingual
fm_matrix = 0x3000; /* bilingual */
src = 0x0020;
break;
case V4L2_TUNER_MODE_LANG1:
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
fm_matrix = 0x3000; // mono
fm_matrix = 0x3000; /* mono */
src = 0x0000;
break;
case V4L2_TUNER_MODE_LANG2:
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
fm_matrix = 0x3000; // mono
fm_matrix = 0x3000; /* mono */
src = 0x0010;
break;
default: /* case V4L2_TUNER_MODE_MONO: */
dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
fm_matrix = 0x3000; // mono
fm_matrix = 0x3000; /* mono */
src = 0x0030;
break;
}
......@@ -408,10 +402,12 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
return 0;
}
case VIDIOC_G_FREQUENCY:
{
struct v4l2_frequency *f = arg;
}
static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
......@@ -422,10 +418,12 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
f->type = V4L2_TUNER_ANALOG_TV;
f->frequency = av7110->current_freq;
return 0;
}
case VIDIOC_S_FREQUENCY:
{
struct v4l2_frequency *f = arg;
}
static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
......@@ -435,26 +433,27 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
if (V4L2_TUNER_ANALOG_TV != f->type)
return -EINVAL;
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); // fast mute
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
/* tune in desired frequency */
if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820)
ves1820_set_tv_freq(dev, f->frequency);
} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297)
stv0297_set_tv_freq(dev, f->frequency);
}
av7110->current_freq = f->frequency;
msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); // start stereo detection
msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */
msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */
return 0;
}
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
}
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
......@@ -469,17 +468,22 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
return 0;
}
case VIDIOC_G_INPUT:
{
int *input = (int *)arg;
}
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
*input = av7110->current_input;
dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
return 0;
}
case VIDIOC_S_INPUT:
{
int input = *(int *)arg;
}
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
......@@ -491,79 +495,82 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
av7110->current_input = input;
return av7110_dvb_c_switch(fh);
}
case VIDIOC_G_AUDIO:
{
struct v4l2_audio *a = arg;
}
static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
if (a->index != 0)
return -EINVAL;
memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
break;
}
case VIDIOC_S_AUDIO:
{
struct v4l2_audio *a = arg;
return 0;
}
static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
break;
}
case VIDIOC_G_SLICED_VBI_CAP:
{
struct v4l2_sliced_vbi_cap *cap = arg;
return 0;
}
static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
struct v4l2_sliced_vbi_cap *cap)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
memset(cap, 0, sizeof *cap);
memset(cap, 0, sizeof(*cap));
if (FW_VERSION(av7110->arm_app) >= 0x2623) {
cap->service_set = V4L2_SLICED_WSS_625;
cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
}
break;
}
case VIDIOC_G_FMT:
{
struct v4l2_format *f = arg;
return 0;
}
static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
struct v4l2_format *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
dprintk(2, "VIDIOC_G_FMT:\n");
if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
FW_VERSION(av7110->arm_app) < 0x2623)
return -EAGAIN; /* handled by core driver */
if (FW_VERSION(av7110->arm_app) < 0x2623)
return -EINVAL;
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
if (av7110->wssMode) {
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
}
break;
f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
}
case VIDIOC_S_FMT:
{
struct v4l2_format *f = arg;
return 0;
}
static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
struct v4l2_format *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
dprintk(2, "VIDIOC_S_FMT\n");
if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
FW_VERSION(av7110->arm_app) < 0x2623)
return -EAGAIN; /* handled by core driver */
if (FW_VERSION(av7110->arm_app) < 0x2623)
return -EINVAL;
if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
/* WSS controlled by firmware */
av7110->wssMode = 0;
av7110->wssData = 0;
return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
SetWSSConfig, 1, 0);
} else {
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
/* WSS controlled by userspace */
av7110->wssMode = 1;
av7110->wssData = 0;
}
break;
}
default:
printk("no such ioctl\n");
return -ENOIOCTLCMD;
}
return 0;
}
......@@ -609,22 +616,6 @@ static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size
* INITIALIZATION
****************************************************************************/
static struct saa7146_extension_ioctls ioctls[] = {
{ VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
{ VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
{ VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
{ VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
{ VIDIOC_G_FMT, SAA7146_BEFORE },
{ VIDIOC_S_FMT, SAA7146_BEFORE },
{ 0, 0 }
};
static u8 saa7113_init_regs[] = {
0x02, 0xd0,
0x03, 0x23,
......@@ -788,20 +779,34 @@ int av7110_init_analog_module(struct av7110 *av7110)
int av7110_init_v4l(struct av7110 *av7110)
{
struct saa7146_dev* dev = av7110->dev;
struct saa7146_ext_vv *vv_data;
int ret;
/* special case DVB-C: these cards have an analog tuner
plus need some special handling, so we have separate
saa7146_ext_vv data for these... */
if (av7110->analog_tuner_flags)
ret = saa7146_vv_init(dev, &av7110_vv_data_c);
vv_data = &av7110_vv_data_c;
else
ret = saa7146_vv_init(dev, &av7110_vv_data_st);
vv_data = &av7110_vv_data_st;
ret = saa7146_vv_init(dev, vv_data);
if (ret) {
ERR(("cannot init capture device. skipping.\n"));
return -ENODEV;
}
vv_data->ops.vidioc_enum_input = vidioc_enum_input;
vv_data->ops.vidioc_g_input = vidioc_g_input;
vv_data->ops.vidioc_s_input = vidioc_s_input;
vv_data->ops.vidioc_g_tuner = vidioc_g_tuner;
vv_data->ops.vidioc_s_tuner = vidioc_s_tuner;
vv_data->ops.vidioc_g_frequency = vidioc_g_frequency;
vv_data->ops.vidioc_s_frequency = vidioc_s_frequency;
vv_data->ops.vidioc_g_audio = vidioc_g_audio;
vv_data->ops.vidioc_s_audio = vidioc_s_audio;
vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
ERR(("cannot register capture device. skipping.\n"));
......@@ -900,9 +905,6 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
.num_stds = ARRAY_SIZE(standard),
.std_callback = &std_callback,
.ioctls = &ioctls[0],
.ioctl = av7110_ioctl,
.vbi_fops.open = av7110_vbi_reset,
.vbi_fops.release = av7110_vbi_reset,
.vbi_fops.write = av7110_vbi_write,
......@@ -918,9 +920,6 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
.num_stds = ARRAY_SIZE(standard),
.std_callback = &std_callback,
.ioctls = &ioctls[0],
.ioctl = av7110_ioctl,
.vbi_fops.open = av7110_vbi_reset,
.vbi_fops.release = av7110_vbi_reset,
.vbi_fops.write = av7110_vbi_write,
......
......@@ -1404,6 +1404,41 @@ static int budget_av_detach(struct saa7146_dev *dev)
return err;
}
#define KNC1_INPUTS 2
static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
{0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
{1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
};
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
if (i->index < 0 || i->index >= KNC1_INPUTS)
return -EINVAL;
memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
return 0;
}
static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
*i = budget_av->cur_input;
dprintk(1, "VIDIOC_G_INPUT %d.\n", *i);
return 0;
}
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
return saa7113_setinput(budget_av, input);
}
static struct saa7146_ext_vv vv_data;
static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
......@@ -1442,6 +1477,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
ERR(("cannot init vv subsystem.\n"));
return err;
}
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
vv_data.ops.vidioc_g_input = vidioc_g_input;
vv_data.ops.vidioc_s_input = vidioc_s_input;
if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
/* fixme: proper cleanup here */
......@@ -1480,54 +1518,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
return 0;
}
#define KNC1_INPUTS 2
static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
{0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
{1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
};
static struct saa7146_extension_ioctls ioctls[] = {
{VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE},
{VIDIOC_G_INPUT, SAA7146_EXCLUSIVE},
{VIDIOC_S_INPUT, SAA7146_EXCLUSIVE},
{0, 0}
};
static long av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
switch (cmd) {
case VIDIOC_ENUMINPUT:{
struct v4l2_input *i = arg;
dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
if (i->index < 0 || i->index >= KNC1_INPUTS) {
return -EINVAL;
}
memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
return 0;
}
case VIDIOC_G_INPUT:{
int *input = (int *) arg;
*input = budget_av->cur_input;
dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
return 0;
}
case VIDIOC_S_INPUT:{
int input = *(int *) arg;
dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
return saa7113_setinput(budget_av, input);
}
default:
return -ENOIOCTLCMD;
}
return 0;
}
static struct saa7146_standard standard[] = {
{.name = "PAL",.id = V4L2_STD_PAL,
.v_offset = 0x17,.v_field = 288,
......@@ -1546,8 +1536,6 @@ static struct saa7146_ext_vv vv_data = {
.flags = 0,
.stds = &standard[0],
.num_stds = ARRAY_SIZE(standard),
.ioctls = &ioctls[0],
.ioctl = av_ioctl,
};
static struct saa7146_extension budget_extension;
......
......@@ -56,17 +56,6 @@ struct hexium_data
u8 byte;
};
static struct saa7146_extension_ioctls ioctls[] = {
{ VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_QUERYCTRL, SAA7146_BEFORE },
{ VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_S_STD, SAA7146_AFTER },
{ VIDIOC_G_CTRL, SAA7146_BEFORE },
{ VIDIOC_S_CTRL, SAA7146_BEFORE },
{ 0, 0 }
};
#define HEXIUM_CONTROLS 1
static struct v4l2_queryctrl hexium_controls[] = {
{ V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
......@@ -231,132 +220,51 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
return 0;
}
static struct saa7146_ext_vv vv_data;
/* this function only gets called when the probing was successful */
static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
struct hexium *hexium = (struct hexium *) dev->ext_priv;
DEB_EE((".\n"));
hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
if (NULL == hexium) {
printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
return -ENOMEM;
}
dev->ext_priv = hexium;
/* enable i2c-port pins */
saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
hexium->i2c_adapter = (struct i2c_adapter) {
.class = I2C_CLASS_TV_ANALOG,
.name = "hexium gemini",
};
saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
DEB_S(("cannot register i2c-device. skipping.\n"));
kfree(hexium);
return -EFAULT;
}
/* set HWControl GPIO number 2 */
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
saa7146_write(dev, DD1_INIT, 0x07000700);
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
/* the rest */
hexium->cur_input = 0;
hexium_init_done(dev);
hexium_set_standard(hexium, hexium_pal);
hexium->cur_std = V4L2_STD_PAL;
hexium_set_input(hexium, 0);
hexium->cur_input = 0;
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
saa7146_vv_init(dev, &vv_data);
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
return -1;
}
if (i->index < 0 || i->index >= HEXIUM_INPUTS)
return -EINVAL;
printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
hexium_num++;
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
return 0;
}
static int hexium_detach(struct saa7146_dev *dev)
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
DEB_EE(("dev:%p\n", dev));
saa7146_unregister_device(&hexium->video_dev, dev);
saa7146_vv_release(dev);
hexium_num--;
*input = hexium->cur_input;
i2c_del_adapter(&hexium->i2c_adapter);
kfree(hexium);
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
return 0;
}
static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
/*
struct saa7146_vv *vv = dev->vv_data;
*/
switch (cmd) {
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
return -EINVAL;
}
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
return 0;
}
case VIDIOC_G_INPUT:
{
int *input = (int *) arg;
*input = hexium->cur_input;
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
return 0;
}
case VIDIOC_S_INPUT:
{
int input = *(int *) arg;
DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
if (input < 0 || input >= HEXIUM_INPUTS) {
if (input < 0 || input >= HEXIUM_INPUTS)
return -EINVAL;
}
hexium->cur_input = input;
hexium_set_input(hexium, input);
return 0;
}
/* the saa7146 provides some controls (brightness, contrast, saturation)
}
/* the saa7146 provides some controls (brightness, contrast, saturation)
which gets registered *after* this function. because of this we have
to return with a value != 0 even if the function succeded.. */
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
int i;
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
......@@ -366,54 +274,47 @@ static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0;
}
}
return -EAGAIN;
}
case VIDIOC_G_CTRL:
{
struct v4l2_control *vc = arg;
return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
}
static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
int i;
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
if (hexium_controls[i].id == vc->id) {
if (hexium_controls[i].id == vc->id)
break;
}
}
if (i < 0) {
return -EAGAIN;
}
if (i < 0)
return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
switch (vc->id) {
case V4L2_CID_PRIVATE_BASE:{
if (vc->id == V4L2_CID_PRIVATE_BASE) {
vc->value = hexium->cur_bw;
DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
return 0;
}
}
return -EINVAL;
}
}
case VIDIOC_S_CTRL:
{
struct v4l2_control *vc = arg;
static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
int i = 0;
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
if (hexium_controls[i].id == vc->id) {
if (hexium_controls[i].id == vc->id)
break;
}
}
if (i < 0) {
return -EAGAIN;
}
if (i < 0)
return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
switch (vc->id) {
case V4L2_CID_PRIVATE_BASE:{
if (vc->id == V4L2_CID_PRIVATE_BASE)
hexium->cur_bw = vc->value;
break;
}
}
DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
......@@ -437,19 +338,92 @@ static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
hexium_set_standard(hexium, hexium_ntsc_bw);
return 0;
}
if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std)
/* fixme: is there no bw secam mode? */
return -EINVAL;
}
return -EINVAL;
}
static struct saa7146_ext_vv vv_data;
/* this function only gets called when the probing was successful */
static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
{
struct hexium *hexium = (struct hexium *) dev->ext_priv;
DEB_EE((".\n"));
hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
if (NULL == hexium) {
printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
return -ENOMEM;
}
default:
/*
DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
*/
return -ENOIOCTLCMD;
dev->ext_priv = hexium;
/* enable i2c-port pins */
saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
hexium->i2c_adapter = (struct i2c_adapter) {
.class = I2C_CLASS_TV_ANALOG,
.name = "hexium gemini",
};
saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
DEB_S(("cannot register i2c-device. skipping.\n"));
kfree(hexium);
return -EFAULT;
}
/* set HWControl GPIO number 2 */
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
saa7146_write(dev, DD1_INIT, 0x07000700);
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
/* the rest */
hexium->cur_input = 0;
hexium_init_done(dev);
hexium_set_standard(hexium, hexium_pal);
hexium->cur_std = V4L2_STD_PAL;
hexium_set_input(hexium, 0);
hexium->cur_input = 0;
saa7146_vv_init(dev, &vv_data);
vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
vv_data.ops.vidioc_g_input = vidioc_g_input;
vv_data.ops.vidioc_s_input = vidioc_s_input;
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
return -1;
}
printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
hexium_num++;
return 0;
}
static int hexium_detach(struct saa7146_dev *dev)
{
struct hexium *hexium = (struct hexium *) dev->ext_priv;
DEB_EE(("dev:%p\n", dev));
saa7146_unregister_device(&hexium->video_dev, dev);
saa7146_vv_release(dev);
hexium_num--;
i2c_del_adapter(&hexium->i2c_adapter);
kfree(hexium);
return 0;
}
......@@ -514,8 +488,6 @@ static struct saa7146_ext_vv vv_data = {
.stds = &hexium_standards[0],
.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
.std_callback = &std_callback,
.ioctls = &ioctls[0],
.ioctl = hexium_ioctl,
};
static struct saa7146_extension hexium_extension = {
......
......@@ -57,14 +57,6 @@ struct hexium_data
u8 byte;
};
static struct saa7146_extension_ioctls ioctls[] = {
{ VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_S_STD, SAA7146_AFTER },
{ 0, 0 }
};
struct hexium
{
int type;
......@@ -329,6 +321,44 @@ static int hexium_set_input(struct hexium *hexium, int input)
return 0;
}
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
if (i->index < 0 || i->index >= HEXIUM_INPUTS)
return -EINVAL;
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
return 0;
}
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
*input = hexium->cur_input;
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
return 0;
}
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
if (input < 0 || input >= HEXIUM_INPUTS)
return -EINVAL;
hexium->cur_input = input;
hexium_set_input(hexium, input);
return 0;
}
static struct saa7146_ext_vv vv_data;
/* this function only gets called when the probing was successful */
......@@ -339,6 +369,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
DEB_EE((".\n"));
saa7146_vv_init(dev, &vv_data);
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
vv_data.ops.vidioc_g_input = vidioc_g_input;
vv_data.ops.vidioc_s_input = vidioc_s_input;
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
return -1;
......@@ -370,58 +403,6 @@ static int hexium_detach(struct saa7146_dev *dev)
return 0;
}
static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
/*
struct saa7146_vv *vv = dev->vv_data;
*/
switch (cmd) {
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
return -EINVAL;
}
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
return 0;
}
case VIDIOC_G_INPUT:
{
int *input = (int *) arg;
*input = hexium->cur_input;
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
return 0;
}
case VIDIOC_S_INPUT:
{
int input = *(int *) arg;
if (input < 0 || input >= HEXIUM_INPUTS) {
return -EINVAL;
}
hexium->cur_input = input;
hexium_set_input(hexium, input);
return 0;
}
default:
/*
DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
*/
return -ENOIOCTLCMD;
}
return 0;
}
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
{
return 0;
......@@ -479,8 +460,6 @@ static struct saa7146_ext_vv vv_data = {
.stds = &hexium_standards[0],
.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
.std_callback = &std_callback,
.ioctls = &ioctls[0],
.ioctl = hexium_ioctl,
};
static struct saa7146_extension extension = {
......
......@@ -110,26 +110,6 @@ static struct v4l2_queryctrl mxb_controls[] = {
{ V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
};
static struct saa7146_extension_ioctls ioctls[] = {
{ VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
{ VIDIOC_QUERYCTRL, SAA7146_BEFORE },
{ VIDIOC_G_CTRL, SAA7146_BEFORE },
{ VIDIOC_S_CTRL, SAA7146_BEFORE },
{ VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
{ VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
{ VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
{ VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_DBG_G_REGISTER, SAA7146_EXCLUSIVE },
{ VIDIOC_DBG_S_REGISTER, SAA7146_EXCLUSIVE },
{ MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
{ MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
{ 0, 0 }
};
struct mxb
{
struct video_device *video_dev;
......@@ -424,94 +404,9 @@ void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
}
*/
static struct saa7146_ext_vv vv_data;
/* this function only gets called when the probing was successful */
static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
{
struct mxb *mxb = (struct mxb *)dev->ext_priv;
DEB_EE(("dev:%p\n", dev));
/* checking for i2c-devices can be omitted here, because we
already did this in "mxb_vl42_probe" */
saa7146_vv_init(dev, &vv_data);
if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
ERR(("cannot register capture v4l2 device. skipping.\n"));
return -1;
}
/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
if (MXB_BOARD_CAN_DO_VBI(dev)) {
if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
ERR(("cannot register vbi v4l2 device. skipping.\n"));
}
}
i2c_use_client(mxb->tea6420_1);
i2c_use_client(mxb->tea6420_2);
i2c_use_client(mxb->tea6415c);
i2c_use_client(mxb->tda9840);
i2c_use_client(mxb->saa7111a);
i2c_use_client(mxb->tuner);
printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
mxb_num++;
mxb_init_done(dev);
return 0;
}
static int mxb_detach(struct saa7146_dev *dev)
{
struct mxb *mxb = (struct mxb *)dev->ext_priv;
DEB_EE(("dev:%p\n", dev));
i2c_release_client(mxb->tea6420_1);
i2c_release_client(mxb->tea6420_2);
i2c_release_client(mxb->tea6415c);
i2c_release_client(mxb->tda9840);
i2c_release_client(mxb->saa7111a);
i2c_release_client(mxb->tuner);
saa7146_unregister_device(&mxb->video_dev,dev);
if (MXB_BOARD_CAN_DO_VBI(dev))
saa7146_unregister_device(&mxb->vbi_dev, dev);
saa7146_vv_release(dev);
mxb_num--;
i2c_del_adapter(&mxb->i2c_adapter);
kfree(mxb);
return 0;
}
static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
{
struct saa7146_dev *dev = fh->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
struct saa7146_vv *vv = dev->vv_data;
switch(cmd) {
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
if (i->index < 0 || i->index >= MXB_INPUTS)
return -EINVAL;
memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
return 0;
}
/* the saa7146 provides some controls (brightness, contrast, saturation)
which gets registered *after* this function. because of this we have
to return with a value != 0 even if the function succeded.. */
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
int i;
for (i = MAXCONTROLS - 1; i >= 0; i--) {
......@@ -521,11 +416,13 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0;
}
}
return -EAGAIN;
}
case VIDIOC_G_CTRL:
{
struct v4l2_control *vc = arg;
return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
}
static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
int i;
for (i = MAXCONTROLS - 1; i >= 0; i--) {
......@@ -534,7 +431,7 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
}
if (i < 0)
return -EAGAIN;
return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
if (vc->id == V4L2_CID_AUDIO_MUTE) {
vc->value = mxb->cur_mute;
......@@ -544,11 +441,12 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
return 0;
}
}
case VIDIOC_S_CTRL:
{
struct v4l2_control *vc = arg;
static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
int i = 0;
for (i = MAXCONTROLS - 1; i >= 0; i--) {
......@@ -557,7 +455,7 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
}
if (i < 0)
return -EAGAIN;
return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
if (vc->id == V4L2_CID_AUDIO_MUTE) {
mxb->cur_mute = vc->value;
......@@ -576,18 +474,31 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
}
return 0;
}
case VIDIOC_G_INPUT:
{
int *input = (int *)arg;
*input = mxb->cur_input;
}
DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
if (i->index < 0 || i->index >= MXB_INPUTS)
return -EINVAL;
memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
return 0;
}
case VIDIOC_S_INPUT:
{
int input = *(int *)arg;
}
static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
*i = mxb->cur_input;
DEB_EE(("VIDIOC_G_INPUT %d.\n", *i));
return 0;
}
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
struct tea6415c_multiplex vm;
struct v4l2_routing route;
int i = 0;
......@@ -652,10 +563,10 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
route.input = i;
route.output = 0;
if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n");
/* switch the audio-source only if necessary */
if( 0 == mxb->cur_mute ) {
if (0 == mxb->cur_mute) {
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
&TEA6420_line[video_audio_connect[input]][0]);
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
......@@ -663,10 +574,12 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
}
return 0;
}
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *t = arg;
}
static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
if (t->index) {
DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
......@@ -676,31 +589,35 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
memset(t, 0, sizeof(*t));
i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
i2c_clients_command(&mxb->i2c_adapter, VIDIOC_G_TUNER, t);
strlcpy(t->name, "TV Tuner", sizeof(t->name));
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
t->audmode = mxb->cur_mode;
return 0;
}
case VIDIOC_S_TUNER:
{
struct v4l2_tuner *t = arg;
}
static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
if (t->index) {
DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index));
return -EINVAL;
}
mxb->cur_mode = t->audmode;
i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
i2c_clients_command(&mxb->i2c_adapter, VIDIOC_S_TUNER, t);
return 0;
}
case VIDIOC_G_FREQUENCY:
{
struct v4l2_frequency *f = arg;
}
static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
if (mxb->cur_input) {
DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
......@@ -712,10 +629,13 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
return 0;
}
case VIDIOC_S_FREQUENCY:
{
struct v4l2_frequency *f = arg;
}
static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
struct saa7146_vv *vv = dev->vv_data;
if (f->tuner)
return -EINVAL;
......@@ -740,65 +660,86 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
spin_unlock(&dev->slock);
return 0;
}
case MXB_S_AUDIO_CD:
{
int i = *(int*)arg;
}
if (i < 0 || i >= MXB_AUDIOS) {
DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
if (a->index < 0 || a->index > MXB_INPUTS) {
DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
return -EINVAL;
}
DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
return 0;
}
static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
return 0;
}
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_G_REGISTER, reg);
return 0;
}
case MXB_S_AUDIO_LINE:
}
static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_S_REGISTER, reg);
return 0;
}
#endif
static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
switch (cmd) {
case MXB_S_AUDIO_CD:
{
int i = *(int*)arg;
int i = *(int *)arg;
if (i < 0 || i >= MXB_AUDIOS) {
DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i));
return -EINVAL;
}
DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i));
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[i][0]);
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[i][1]);
return 0;
}
case VIDIOC_G_AUDIO:
case MXB_S_AUDIO_LINE:
{
struct v4l2_audio *a = arg;
int i = *(int *)arg;
if (a->index < 0 || a->index > MXB_INPUTS) {
DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
if (i < 0 || i >= MXB_AUDIOS) {
DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i));
return -EINVAL;
}
DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
return 0;
}
case VIDIOC_S_AUDIO:
{
struct v4l2_audio *a = arg;
DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i));
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[i][0]);
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[i][1]);
DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
return 0;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
case VIDIOC_DBG_S_REGISTER:
case VIDIOC_DBG_G_REGISTER:
i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
return 0;
#endif
default:
/*
DEB2(printk("does not handle this ioctl.\n"));
......@@ -808,6 +749,88 @@ static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0;
}
static struct saa7146_ext_vv vv_data;
/* this function only gets called when the probing was successful */
static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
{
struct mxb *mxb = (struct mxb *)dev->ext_priv;
DEB_EE(("dev:%p\n", dev));
/* checking for i2c-devices can be omitted here, because we
already did this in "mxb_vl42_probe" */
saa7146_vv_init(dev, &vv_data);
vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
vv_data.ops.vidioc_g_input = vidioc_g_input;
vv_data.ops.vidioc_s_input = vidioc_s_input;
vv_data.ops.vidioc_g_tuner = vidioc_g_tuner;
vv_data.ops.vidioc_s_tuner = vidioc_s_tuner;
vv_data.ops.vidioc_g_frequency = vidioc_g_frequency;
vv_data.ops.vidioc_s_frequency = vidioc_s_frequency;
vv_data.ops.vidioc_g_audio = vidioc_g_audio;
vv_data.ops.vidioc_s_audio = vidioc_s_audio;
#ifdef CONFIG_VIDEO_ADV_DEBUG
vv_data.ops.vidioc_g_register = vidioc_g_register;
vv_data.ops.vidioc_s_register = vidioc_s_register;
#endif
vv_data.ops.vidioc_default = vidioc_default;
if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
ERR(("cannot register capture v4l2 device. skipping.\n"));
return -1;
}
/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
if (MXB_BOARD_CAN_DO_VBI(dev)) {
if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
ERR(("cannot register vbi v4l2 device. skipping.\n"));
}
}
i2c_use_client(mxb->tea6420_1);
i2c_use_client(mxb->tea6420_2);
i2c_use_client(mxb->tea6415c);
i2c_use_client(mxb->tda9840);
i2c_use_client(mxb->saa7111a);
i2c_use_client(mxb->tuner);
printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
mxb_num++;
mxb_init_done(dev);
return 0;
}
static int mxb_detach(struct saa7146_dev *dev)
{
struct mxb *mxb = (struct mxb *)dev->ext_priv;
DEB_EE(("dev:%p\n", dev));
i2c_release_client(mxb->tea6420_1);
i2c_release_client(mxb->tea6420_2);
i2c_release_client(mxb->tea6415c);
i2c_release_client(mxb->tda9840);
i2c_release_client(mxb->saa7111a);
i2c_release_client(mxb->tuner);
saa7146_unregister_device(&mxb->video_dev,dev);
if (MXB_BOARD_CAN_DO_VBI(dev))
saa7146_unregister_device(&mxb->vbi_dev, dev);
saa7146_vv_release(dev);
mxb_num--;
i2c_del_adapter(&mxb->i2c_adapter);
kfree(mxb);
return 0;
}
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
{
struct mxb *mxb = (struct mxb *)dev->ext_priv;
......@@ -885,8 +908,6 @@ static struct saa7146_ext_vv vv_data = {
.stds = &standard[0],
.num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
.std_callback = &std_callback,
.ioctls = &ioctls[0],
.ioctl = mxb_ioctl,
};
static struct saa7146_extension extension = {
......
......@@ -150,16 +150,6 @@ struct saa7146_vv
unsigned int resources; /* resource management for device */
};
#define SAA7146_EXCLUSIVE 0x1
#define SAA7146_BEFORE 0x2
#define SAA7146_AFTER 0x4
struct saa7146_extension_ioctls
{
unsigned int cmd;
int flags;
};
/* flags */
#define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */
......@@ -176,8 +166,10 @@ struct saa7146_ext_vv
int num_stds;
int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
struct saa7146_extension_ioctls *ioctls;
long (*ioctl)(struct saa7146_fh *, unsigned int cmd, void *arg);
/* the extension can override this */
struct v4l2_ioctl_ops ops;
/* pointer to the saa7146 core ops */
const struct v4l2_ioctl_ops *core_ops;
struct v4l2_file_operations vbi_fops;
};
......@@ -213,6 +205,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sy
void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
/* from saa7146_video.c */
extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
extern struct saa7146_use_ops saa7146_video_uops;
int saa7146_start_preview(struct saa7146_fh *fh);
int saa7146_stop_preview(struct saa7146_fh *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