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. 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 = -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); } else { err = video_end(fh, file); } return err; }
int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; if (fh->resources & bit) { DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n", bit, vv->resources); return 1; } if (vv->resources & bit) { DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n", vv->resources, bit); return 0; } fh->resources |= bit; vv->resources |= bit; DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources); return 1; }
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard) { struct mxb *mxb = (struct mxb *)dev->ext_priv; if (V4L2_STD_PAL_I == standard->id) { v4l2_std_id std = V4L2_STD_PAL_I; DEB_D("VIDIOC_S_STD: setting mxb for PAL_I\n"); saa7146_write(dev, GPIO_CTRL, 0x00404050); saa7111a_call(mxb, core, s_gpio, 0); tuner_call(mxb, core, s_std, std); } else { v4l2_std_id std = V4L2_STD_PAL_BG; DEB_D("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM\n"); saa7146_write(dev, GPIO_CTRL, 0x00404050); saa7111a_call(mxb, core, s_gpio, 1); tuner_call(mxb, core, s_std, std); } return 0; }
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard) { struct mxb *mxb = (struct mxb *)dev->ext_priv; if (V4L2_STD_PAL_I == standard->id) { v4l2_std_id std = V4L2_STD_PAL_I; DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n")); /* set the 7146 gpio register -- I don't know what this does exactly */ saa7146_write(dev, GPIO_CTRL, 0x00404050); /* unset the 7111 gpio register -- I don't know what this does exactly */ saa7111a_call(mxb, core, s_gpio, 0); tuner_call(mxb, core, s_std, std); } else { v4l2_std_id std = V4L2_STD_PAL_BG; DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n")); /* set the 7146 gpio register -- I don't know what this does exactly */ saa7146_write(dev, GPIO_CTRL, 0x00404050); /* set the 7111 gpio register -- I don't know what this does exactly */ saa7111a_call(mxb, core, s_gpio, 1); tuner_call(mxb, core, s_std, std); } return 0; }
int saa7146_stop_preview(struct saa7146_fh *fh) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); /* check if streaming capture is running */ if (IS_CAPTURE_ACTIVE(fh) != 0) { DEB_D(("streaming capture is active.\n")); return -EBUSY; } /* check if overlay is running at all */ if ((vv->video_status & STATUS_OVERLAY) == 0) { DEB_D(("no active overlay.\n")); return 0; } 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_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); return 0; }
int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; if (fh->resources & bit) { DEB_D(("already allocated! want: 0x%02x, cur:0x%02x\n",bit,vv->resources)); /* have it already allocated */ return 1; } /* is it free? */ mutex_lock(&dev->lock); if (vv->resources & bit) { DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit)); /* no, someone else uses it */ mutex_unlock(&dev->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; vv->resources |= bit; DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources)); mutex_unlock(&dev->lock); return 1; }
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 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 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")); return -EBUSY; } if ((vv->video_status & STATUS_OVERLAY) != 0) { 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; } } mutex_lock(&dev->lock); 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) dev->ext_vv_data->std_callback(dev, vv->standard); found = 1; } mutex_unlock(&dev->lock); if (vv->ov_suspend != NULL) { saa7146_start_preview(vv->ov_suspend); vv->ov_suspend = NULL; } 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)); return 0; }
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; if (V4L2_TUNER_ANALOG_TV != f->type) return -EINVAL; if (mxb->cur_input) { DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); return -EINVAL; } mxb->cur_freq = *f; DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); /* tune in desired frequency */ tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq); /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ spin_lock(&dev->slock); vv->vbi_fieldcount = 0; spin_unlock(&dev->slock); return 0; }
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; if (V4L2_TUNER_ANALOG_TV != f->type) return -EINVAL; if (mxb->cur_input) { DEB_D("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input); return -EINVAL; } mxb->cur_freq = *f; DEB_EE("VIDIOC_S_FREQUENCY: freq:0x%08x\n", mxb->cur_freq.frequency); tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq); spin_lock(&dev->slock); vv->vbi_fieldcount = 0; spin_unlock(&dev->slock); return 0; }
static int video_begin(struct saa7146_fh *fh) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; struct saa7146_format *fmt = NULL; unsigned int resource; int ret = 0, err = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); if ((vv->video_status & STATUS_CAPTURE) != 0) { if (vv->video_fh == fh) { DEB_S(("already capturing.\n")); return 0; } DEB_S(("already capturing in another open.\n")); 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); /* we need to have a valid format set here */ BUG_ON(NULL == fmt); if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; } else { resource = RESOURCE_DMA1_HPS; } ret = saa7146_res_get(fh, resource); if (0 == ret) { DEB_S(("cannot get capture resource %d\n",resource)); if (vv->ov_suspend != NULL) { saa7146_start_preview(vv->ov_suspend); vv->ov_suspend = NULL; } return -EBUSY; } /* clear out beginning of streaming bit (rps register 0)*/ saa7146_write(dev, MC2, MASK_27 ); /* enable rps0 irqs */ SAA7146_IER_ENABLE(dev, MASK_27); vv->video_fh = fh; vv->video_status = STATUS_CAPTURE; return 0; }
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; DEB_D(("VIDIOCGMBUF \n")); q = &fh->video_q; err = videobuf_mmap_setup(q, gbuffers, gbufsize, V4L2_MEMORY_MMAP); if (err < 0) return err; gbuffers = err; 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; }
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); /* check if we have overlay information */ if (vv->ov.fh == NULL) { DEB_D("no overlay data available. try S_FMT first.\n"); return -EAGAIN; } /* check if streaming capture is running */ if (IS_CAPTURE_ACTIVE(fh) != 0) { DEB_D("streaming capture is active\n"); return -EBUSY; } /* check if overlay is running */ if (IS_OVERLAY_ACTIVE(fh) != 0) { if (vv->video_fh == fh) { DEB_D("overlay is already active\n"); return 0; } DEB_D("overlay is already active in another open\n"); return -EBUSY; } if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { DEB_D("cannot get necessary overlay resources\n"); return -EBUSY; } fmt.fmt.win = vv->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; } vv->ov.win = fmt.fmt.win; DEB_D("%dx%d+%d+%d %s field=%s\n", vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]); if (0 != (ret = saa7146_enable_overlay(fh))) { DEB_D("enabling overlay failed: %d\n", ret); saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); return ret; } vv->video_status = STATUS_OVERLAY; vv->video_fh = fh; return 0; }
static long vidioc_default(struct file *file, void *fh, bool valid_prio, 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; if (i < 0 || i >= MXB_AUDIOS) { DEB_D("invalid argument to MXB_S_AUDIO_CD: i:%d\n", i); return -EINVAL; } DEB_EE("MXB_S_AUDIO_CD: i:%d\n", i); tea6420_route_cd(mxb, i); return 0; } case MXB_S_AUDIO_LINE: { int i = *(int *)arg; if (i < 0 || i >= MXB_AUDIOS) { DEB_D("invalid argument to MXB_S_AUDIO_LINE: i:%d\n", i); return -EINVAL; } DEB_EE("MXB_S_AUDIO_LINE: i:%d\n", i); tea6420_route_line(mxb, i); return 0; } default: /* DEB2(pr_err("does not handle this ioctl\n")); */ return -ENOIOCTLCMD; } return 0; }
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)) return -EPERM; /* check args */ fmt = saa7146_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 (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) { if (vv->video_fh != fh) { DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); return -EBUSY; } } mutex_lock(&dev->lock); /* ok, accept it */ vv->ov_fb = *fb; vv->ov_fmt = fmt; if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) { vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8; DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline)); } mutex_unlock(&dev->lock); return 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 err = saa7146_stop_preview(fh); return err; }
int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf) { assert_spin_locked(&dev->slock); DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf)); BUG_ON(!q); if (NULL == q->curr) { q->curr = buf; DEB_D(("immediately activating buffer %p\n", buf)); buf->activate(dev,buf,NULL); } else { list_add_tail(&buf->vb.queue,&q->queue); buf->vb.state = VIDEOBUF_QUEUED; DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); } return 0; }
void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; BUG_ON((fh->resources & bits) != bits); fh->resources &= ~bits; vv->resources &= ~bits; DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources); }
static int get_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; u32 value = 0; 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)); break; case V4L2_CID_HFLIP: c->value = vv->hflip; DEB_D(("V4L2_CID_HFLIP: %d\n",c->value)); break; default: return -EINVAL; } return 0; }
static int mxb_probe(struct saa7146_dev *dev) { struct mxb *mxb = NULL; mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL); if (mxb == NULL) { DEB_D(("not enough kernel memory.\n")); return -ENOMEM; } snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num); saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); if (i2c_add_adapter(&mxb->i2c_adapter) < 0) { DEB_S(("cannot register i2c-device. skipping.\n")); kfree(mxb); return -EFAULT; } mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "saa7115", "saa7111", I2C_SAA7111A); mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tea6420", "tea6420", I2C_TEA6420_1); mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tea6420", "tea6420", I2C_TEA6420_2); mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tea6415c", "tea6415c", I2C_TEA6415C); mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tda9840", "tda9840", I2C_TDA9840); mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tuner", "tuner", I2C_TUNER); if (v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "saa5246a", "saa5246a", I2C_SAA5246A)) { printk(KERN_INFO "mxb: found teletext decoder\n"); } /* check if all devices are present */ if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) { printk("mxb: did not find all i2c devices. aborting\n"); i2c_del_adapter(&mxb->i2c_adapter); kfree(mxb); return -ENODEV; } /* all devices are present, probe was successful */ /* we store the pointer in our private data field */ dev->ext_priv = mxb; return 0; }
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)); return -EINVAL; } mxb->cur_mode = t->audmode; return call_all(dev, tuner, s_tuner, t); }
struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc) { int i, j = NUM_FORMATS; for (i = 0; i < j; i++) { if (formats[i].pixelformat == fourcc) { return formats+i; } } DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc)); return NULL; }
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; down(&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)) { up(&dev->lock); return -EFAULT; } /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ fh->ov.fh = fh; up(&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; } }
void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; if ((fh->resources & bits) != bits) BUG(); down(&dev->lock); fh->resources &= ~bits; vv->resources &= ~bits; DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources)); up(&dev->lock); }
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 = MAXCONTROLS - 1; i >= 0; i--) { if (mxb_controls[i].id == qc->id) { *qc = mxb_controls[i]; DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); return 0; } } return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); }
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 > MXB_INPUTS) { DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); 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; }
static int mxb_probe(struct saa7146_dev *dev) { struct mxb *mxb = NULL; mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL); if (mxb == NULL) { DEB_D("not enough kernel memory\n"); return -ENOMEM; } snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num); saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); if (i2c_add_adapter(&mxb->i2c_adapter) < 0) { DEB_S("cannot register i2c-device. skipping.\n"); kfree(mxb); return -EFAULT; } mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "saa7111", I2C_SAA7111A, NULL); mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tea6420", I2C_TEA6420_1, NULL); mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tea6420", I2C_TEA6420_2, NULL); mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tea6415c", I2C_TEA6415C, NULL); mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tda9840", I2C_TDA9840, NULL); mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, "tuner", I2C_TUNER, NULL); if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) { pr_err("did not find all i2c devices. aborting\n"); i2c_del_adapter(&mxb->i2c_adapter); kfree(mxb); return -ENODEV; } dev->ext_priv = mxb; return 0; }
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 (err) return err; 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; }
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", mxb->cur_input)); return -EINVAL; } *f = mxb->cur_freq; DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); return 0; }