Loading drivers/media/video/meye.c +655 −710 Original line number Diff line number Diff line Loading @@ -42,15 +42,10 @@ #include <linux/meye.h> MODULE_AUTHOR("Stelian Pop <stelian@popies.net>"); MODULE_DESCRIPTION("v4l/v4l2 driver for the MotionEye camera"); MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera"); MODULE_LICENSE("GPL"); MODULE_VERSION(MEYE_DRIVER_VERSION); /* force usage of V4L1 API */ static int forcev4l1; /* = 0 */ module_param(forcev4l1, int, 0644); MODULE_PARM_DESC(forcev4l1, "force use of V4L1 instead of V4L2"); /* number of grab buffers */ static unsigned int gbuffers = 2; module_param(gbuffers, int, 0444); Loading Loading @@ -876,172 +871,32 @@ static int meye_release(struct inode *inode, struct file *file) return 0; } static int meye_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) static int meyeioc_g_params(struct meye_params *p) { switch (cmd) { case VIDIOCGCAP: { struct video_capability *b = arg; strcpy(b->name,meye.video_dev->name); b->type = VID_TYPE_CAPTURE; b->channels = 1; b->audios = 0; b->maxwidth = 640; b->maxheight = 480; b->minwidth = 320; b->minheight = 240; break; } case VIDIOCGCHAN: { struct video_channel *v = arg; v->flags = 0; v->tuners = 0; v->type = VIDEO_TYPE_CAMERA; if (v->channel != 0) return -EINVAL; strcpy(v->name,"Camera"); break; } case VIDIOCSCHAN: { struct video_channel *v = arg; if (v->channel != 0) return -EINVAL; break; } case VIDIOCGPICT: { struct video_picture *p = arg; *p = meye.picture; break; } case VIDIOCSPICT: { struct video_picture *p = arg; if (p->depth != 16) return -EINVAL; if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV) return -EINVAL; mutex_lock(&meye.lock); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, p->brightness >> 10); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, p->hue >> 10); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, p->colour >> 10); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, p->contrast >> 10); meye.picture = *p; mutex_unlock(&meye.lock); break; } case VIDIOCSYNC: { int *i = arg; int unused; if (*i < 0 || *i >= gbuffers) return -EINVAL; mutex_lock(&meye.lock); switch (meye.grab_buffer[*i].state) { case MEYE_BUF_UNUSED: mutex_unlock(&meye.lock); return -EINVAL; case MEYE_BUF_USING: if (file->f_flags & O_NONBLOCK) { mutex_unlock(&meye.lock); return -EAGAIN; } if (wait_event_interruptible(meye.proc_list, (meye.grab_buffer[*i].state != MEYE_BUF_USING))) { mutex_unlock(&meye.lock); return -EINTR; } /* fall through */ case MEYE_BUF_DONE: meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int)); } mutex_unlock(&meye.lock); break; } case VIDIOCMCAPTURE: { struct video_mmap *vm = arg; int restart = 0; if (vm->frame >= gbuffers || vm->frame < 0) return -EINVAL; if (vm->format != VIDEO_PALETTE_YUV422 && vm->format != VIDEO_PALETTE_YUYV) return -EINVAL; if (vm->height * vm->width * 2 > gbufsize) return -EINVAL; if (!meye.grab_fbuffer) return -EINVAL; if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED) return -EBUSY; mutex_lock(&meye.lock); if (vm->width == 640 && vm->height == 480) { if (meye.params.subsample) { meye.params.subsample = 0; restart = 1; } } else if (vm->width == 320 && vm->height == 240) { if (!meye.params.subsample) { meye.params.subsample = 1; restart = 1; } } else { mutex_unlock(&meye.lock); return -EINVAL; } if (restart || meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT) mchip_continuous_start(); meye.grab_buffer[vm->frame].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int)); mutex_unlock(&meye.lock); break; } case VIDIOCGMBUF: { struct video_mbuf *vm = arg; int i; memset(vm, 0 , sizeof(*vm)); vm->size = gbufsize * gbuffers; vm->frames = gbuffers; for (i = 0; i < gbuffers; i++) vm->offsets[i] = i * gbufsize; break; } case MEYEIOC_G_PARAMS: { struct meye_params *p = arg; *p = meye.params; break; return 0; } case MEYEIOC_S_PARAMS: { struct meye_params *jp = arg; static int meyeioc_s_params(struct meye_params *jp) { if (jp->subsample > 1) return -EINVAL; if (jp->quality > 10) return -EINVAL; if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63) return -EINVAL; if (jp->framerate > 31) return -EINVAL; mutex_lock(&meye.lock); if (meye.params.subsample != jp->subsample || meye.params.quality != jp->quality) mchip_hic_stop(); /* need restart */ meye.params = *jp; sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, meye.params.sharpness); Loading @@ -1050,34 +905,41 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, meye.params.picture); mutex_unlock(&meye.lock); break; } case MEYEIOC_QBUF_CAPT: { int *nb = arg; return 0; } static int meyeioc_qbuf_capt(int *nb) { if (!meye.grab_fbuffer) return -EINVAL; if (*nb >= gbuffers) return -EINVAL; if (*nb < 0) { /* stop capture */ mchip_hic_stop(); return 0; } if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED) return -EBUSY; mutex_lock(&meye.lock); if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) mchip_cont_compression_start(); meye.grab_buffer[*nb].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int)); mutex_unlock(&meye.lock); break; return 0; } case MEYEIOC_SYNC: { int *i = arg; static int meyeioc_sync(struct file *file, void *fh, int *i) { int unused; if (*i < 0 || *i >= gbuffers) Loading Loading @@ -1106,92 +968,99 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, } *i = meye.grab_buffer[*i].size; mutex_unlock(&meye.lock); break; return 0; } case MEYEIOC_STILLCAPT: { static int meyeioc_stillcapt(void) { if (!meye.grab_fbuffer) return -EINVAL; if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) return -EBUSY; mutex_lock(&meye.lock); meye.grab_buffer[0].state = MEYE_BUF_USING; mchip_take_picture(); mchip_get_picture( meye.grab_fbuffer, mchip_get_picture(meye.grab_fbuffer, mchip_hsize() * mchip_vsize() * 2); meye.grab_buffer[0].state = MEYE_BUF_DONE; mutex_unlock(&meye.lock); break; } case MEYEIOC_STILLJCAPT: { int *len = arg; return 0; } static int meyeioc_stilljcapt(int *len) { if (!meye.grab_fbuffer) return -EINVAL; if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) return -EBUSY; mutex_lock(&meye.lock); meye.grab_buffer[0].state = MEYE_BUF_USING; *len = -1; while (*len == -1) { mchip_take_picture(); *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); } meye.grab_buffer[0].state = MEYE_BUF_DONE; mutex_unlock(&meye.lock); break; return 0; } case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; if (forcev4l1) return -EINVAL; static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { memset(cap, 0, sizeof(*cap)); strcpy(cap->driver, "meye"); strcpy(cap->card, "meye"); sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev)); cap->version = (MEYE_DRIVER_MAJORVERSION << 8) + MEYE_DRIVER_MINORVERSION; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; break; } case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; return 0; } static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { if (i->index != 0) return -EINVAL; memset(i, 0, sizeof(*i)); i->index = 0; strcpy(i->name, "Camera"); i->type = V4L2_INPUT_TYPE_CAMERA; break; } case VIDIOC_G_INPUT: { int *i = arg; return 0; } static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) { *i = 0; break; return 0; } case VIDIOC_S_INPUT: { int *i = arg; if (*i != 0) static int vidioc_s_input(struct file *file, void *fh, unsigned int i) { if (i != 0) return -EINVAL; break; } case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *c = arg; return 0; } static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) { switch (c->id) { case V4L2_CID_BRIGHTNESS: Loading Loading @@ -1284,12 +1153,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, default: return -EINVAL; } break; } case VIDIOC_S_CTRL: { struct v4l2_control *c = arg; return 0; } static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) { mutex_lock(&meye.lock); switch (c->id) { case V4L2_CID_BRIGHTNESS: Loading Loading @@ -1339,12 +1208,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; } mutex_unlock(&meye.lock); break; } case VIDIOC_G_CTRL: { struct v4l2_control *c = arg; return 0; } static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) { mutex_lock(&meye.lock); switch (c->id) { case V4L2_CID_BRIGHTNESS: Loading Loading @@ -1380,16 +1249,19 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; } mutex_unlock(&meye.lock); break; } case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; return 0; } static int vidioc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) { if (f->index > 1) return -EINVAL; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (f->index == 0) { /* standard YUV 422 capture */ memset(f, 0, sizeof(*f)); Loading @@ -1407,21 +1279,26 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, strcpy(f->description, "MJPEG"); f->pixelformat = V4L2_PIX_FMT_MJPEG; } break; } case VIDIOC_TRY_FMT: { struct v4l2_format *f = arg; return 0; } static int vidioc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) return -EINVAL; if (f->fmt.pix.field != V4L2_FIELD_ANY && f->fmt.pix.field != V4L2_FIELD_NONE) return -EINVAL; f->fmt.pix.field = V4L2_FIELD_NONE; if (f->fmt.pix.width <= 320) { f->fmt.pix.width = 320; f->fmt.pix.height = 240; Loading @@ -1429,21 +1306,24 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.width = 640; f->fmt.pix.height = 480; } f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = 0; f->fmt.pix.priv = 0; break; } case VIDIOC_G_FMT: { struct v4l2_format *f = arg; return 0; } static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; switch (meye.mchip_mode) { case MCHIP_HIC_MODE_CONT_OUT: default: Loading @@ -1453,6 +1333,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; break; } f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix.width = mchip_hsize(); f->fmt.pix.height = mchip_vsize(); Loading @@ -1461,22 +1342,26 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.bytesperline; f->fmt.pix.colorspace = 0; f->fmt.pix.priv = 0; break; } case VIDIOC_S_FMT: { struct v4l2_format *f = arg; return 0; } static int vidioc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) return -EINVAL; if (f->fmt.pix.field != V4L2_FIELD_ANY && f->fmt.pix.field != V4L2_FIELD_NONE) return -EINVAL; f->fmt.pix.field = V4L2_FIELD_NONE; mutex_lock(&meye.lock); if (f->fmt.pix.width <= 320) { f->fmt.pix.width = 320; f->fmt.pix.height = 240; Loading @@ -1486,6 +1371,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.height = 480; meye.params.subsample = 0; } switch (f->fmt.pix.pixelformat) { case V4L2_PIX_FMT_YUYV: meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; Loading @@ -1494,6 +1380,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; break; } mutex_unlock(&meye.lock); f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * Loading @@ -1501,21 +1388,25 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.colorspace = 0; f->fmt.pix.priv = 0; break; return 0; } case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *req = arg; static int vidioc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) { int i; if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (req->memory != V4L2_MEMORY_MMAP) return -EINVAL; if (meye.grab_fbuffer && req->count == gbuffers) { /* already allocated, no modifications */ break; return 0; } mutex_lock(&meye.lock); if (meye.grab_fbuffer) { for (i = 0; i < gbuffers; i++) Loading @@ -1526,93 +1417,114 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, rvfree(meye.grab_fbuffer, gbuffers * gbufsize); meye.grab_fbuffer = NULL; } gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS)); req->count = gbuffers; meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize); if (!meye.grab_fbuffer) { printk(KERN_ERR "meye: v4l framebuffer allocation" " failed\n"); mutex_unlock(&meye.lock); return -ENOMEM; } for (i = 0; i < gbuffers; i++) meye.vma_use_count[i] = 0; mutex_unlock(&meye.lock); break; return 0; } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) { int index = buf->index; if (index < 0 || index >= gbuffers) return -EINVAL; memset(buf, 0, sizeof(*buf)); buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf->index = index; buf->bytesused = meye.grab_buffer[index].size; buf->flags = V4L2_BUF_FLAG_MAPPED; if (meye.grab_buffer[index].state == MEYE_BUF_USING) buf->flags |= V4L2_BUF_FLAG_QUEUED; if (meye.grab_buffer[index].state == MEYE_BUF_DONE) buf->flags |= V4L2_BUF_FLAG_DONE; buf->field = V4L2_FIELD_NONE; buf->timestamp = meye.grab_buffer[index].timestamp; buf->sequence = meye.grab_buffer[index].sequence; buf->memory = V4L2_MEMORY_MMAP; buf->m.offset = index * gbufsize; buf->length = gbufsize; break; } case VIDIOC_QBUF: { struct v4l2_buffer *buf = arg; return 0; } static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; if (buf->index < 0 || buf->index >= gbuffers) return -EINVAL; if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED) return -EINVAL; mutex_lock(&meye.lock); buf->flags |= V4L2_BUF_FLAG_QUEUED; buf->flags &= ~V4L2_BUF_FLAG_DONE; meye.grab_buffer[buf->index].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int)); mutex_unlock(&meye.lock); break; return 0; } case VIDIOC_DQBUF: { struct v4l2_buffer *buf = arg; static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { int reqnr; if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; mutex_lock(&meye.lock); if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { mutex_unlock(&meye.lock); return -EAGAIN; } if (wait_event_interruptible(meye.proc_list, kfifo_len(meye.doneq) != 0) < 0) { mutex_unlock(&meye.lock); return -EINTR; } if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr, sizeof(int))) { mutex_unlock(&meye.lock); return -EBUSY; } if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) { mutex_unlock(&meye.lock); return -EINVAL; } buf->index = reqnr; buf->bytesused = meye.grab_buffer[reqnr].size; buf->flags = V4L2_BUF_FLAG_MAPPED; Loading @@ -1624,11 +1536,14 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, buf->length = gbufsize; meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED; mutex_unlock(&meye.lock); break; return 0; } case VIDIOC_STREAMON: { static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) { mutex_lock(&meye.lock); switch (meye.mchip_mode) { case MCHIP_HIC_MODE_CONT_OUT: mchip_continuous_start(); Loading @@ -1640,39 +1555,51 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&meye.lock); return -EINVAL; } mutex_unlock(&meye.lock); break; } case VIDIOC_STREAMOFF: { int i; return 0; } static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) { mutex_lock(&meye.lock); mchip_hic_stop(); kfifo_reset(meye.grabq); kfifo_reset(meye.doneq); for (i = 0; i < MEYE_MAX_BUFNBRS; i++) meye.grab_buffer[i].state = MEYE_BUF_UNUSED; mutex_unlock(&meye.lock); break; return 0; } /* * XXX what about private snapshot ioctls ? * Do they need to be converted to V4L2 ? */ static int vidioc_default(struct file *file, void *fh, int cmd, void *arg) { switch (cmd) { case MEYEIOC_G_PARAMS: return meyeioc_g_params((struct meye_params *) arg); default: return -ENOIOCTLCMD; } case MEYEIOC_S_PARAMS: return meyeioc_s_params((struct meye_params *) arg); return 0; case MEYEIOC_QBUF_CAPT: return meyeioc_qbuf_capt((int *) arg); case MEYEIOC_SYNC: return meyeioc_sync(file, fh, (int *) arg); case MEYEIOC_STILLCAPT: return meyeioc_stillcapt(); case MEYEIOC_STILLJCAPT: return meyeioc_stilljcapt((int *) arg); default: return -EINVAL; } static int meye_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { return video_usercopy(inode, file, cmd, arg, meye_do_ioctl); } static unsigned int meye_poll(struct file *file, poll_table *wait) Loading Loading @@ -1760,7 +1687,7 @@ static const struct file_operations meye_fops = { .open = meye_open, .release = meye_release, .mmap = meye_mmap, .ioctl = meye_ioctl, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, #endif Loading @@ -1775,6 +1702,24 @@ static struct video_device meye_template = { .fops = &meye_fops, .release = video_device_release, .minor = -1, .vidioc_querycap = vidioc_querycap, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, .vidioc_try_fmt_cap = vidioc_try_fmt_cap, .vidioc_g_fmt_cap = vidioc_g_fmt_cap, .vidioc_s_fmt_cap = vidioc_s_fmt_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_default = vidioc_default, }; #ifdef CONFIG_PM Loading Loading
drivers/media/video/meye.c +655 −710 Original line number Diff line number Diff line Loading @@ -42,15 +42,10 @@ #include <linux/meye.h> MODULE_AUTHOR("Stelian Pop <stelian@popies.net>"); MODULE_DESCRIPTION("v4l/v4l2 driver for the MotionEye camera"); MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera"); MODULE_LICENSE("GPL"); MODULE_VERSION(MEYE_DRIVER_VERSION); /* force usage of V4L1 API */ static int forcev4l1; /* = 0 */ module_param(forcev4l1, int, 0644); MODULE_PARM_DESC(forcev4l1, "force use of V4L1 instead of V4L2"); /* number of grab buffers */ static unsigned int gbuffers = 2; module_param(gbuffers, int, 0444); Loading Loading @@ -876,172 +871,32 @@ static int meye_release(struct inode *inode, struct file *file) return 0; } static int meye_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) static int meyeioc_g_params(struct meye_params *p) { switch (cmd) { case VIDIOCGCAP: { struct video_capability *b = arg; strcpy(b->name,meye.video_dev->name); b->type = VID_TYPE_CAPTURE; b->channels = 1; b->audios = 0; b->maxwidth = 640; b->maxheight = 480; b->minwidth = 320; b->minheight = 240; break; } case VIDIOCGCHAN: { struct video_channel *v = arg; v->flags = 0; v->tuners = 0; v->type = VIDEO_TYPE_CAMERA; if (v->channel != 0) return -EINVAL; strcpy(v->name,"Camera"); break; } case VIDIOCSCHAN: { struct video_channel *v = arg; if (v->channel != 0) return -EINVAL; break; } case VIDIOCGPICT: { struct video_picture *p = arg; *p = meye.picture; break; } case VIDIOCSPICT: { struct video_picture *p = arg; if (p->depth != 16) return -EINVAL; if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV) return -EINVAL; mutex_lock(&meye.lock); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, p->brightness >> 10); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, p->hue >> 10); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, p->colour >> 10); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, p->contrast >> 10); meye.picture = *p; mutex_unlock(&meye.lock); break; } case VIDIOCSYNC: { int *i = arg; int unused; if (*i < 0 || *i >= gbuffers) return -EINVAL; mutex_lock(&meye.lock); switch (meye.grab_buffer[*i].state) { case MEYE_BUF_UNUSED: mutex_unlock(&meye.lock); return -EINVAL; case MEYE_BUF_USING: if (file->f_flags & O_NONBLOCK) { mutex_unlock(&meye.lock); return -EAGAIN; } if (wait_event_interruptible(meye.proc_list, (meye.grab_buffer[*i].state != MEYE_BUF_USING))) { mutex_unlock(&meye.lock); return -EINTR; } /* fall through */ case MEYE_BUF_DONE: meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int)); } mutex_unlock(&meye.lock); break; } case VIDIOCMCAPTURE: { struct video_mmap *vm = arg; int restart = 0; if (vm->frame >= gbuffers || vm->frame < 0) return -EINVAL; if (vm->format != VIDEO_PALETTE_YUV422 && vm->format != VIDEO_PALETTE_YUYV) return -EINVAL; if (vm->height * vm->width * 2 > gbufsize) return -EINVAL; if (!meye.grab_fbuffer) return -EINVAL; if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED) return -EBUSY; mutex_lock(&meye.lock); if (vm->width == 640 && vm->height == 480) { if (meye.params.subsample) { meye.params.subsample = 0; restart = 1; } } else if (vm->width == 320 && vm->height == 240) { if (!meye.params.subsample) { meye.params.subsample = 1; restart = 1; } } else { mutex_unlock(&meye.lock); return -EINVAL; } if (restart || meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT) mchip_continuous_start(); meye.grab_buffer[vm->frame].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int)); mutex_unlock(&meye.lock); break; } case VIDIOCGMBUF: { struct video_mbuf *vm = arg; int i; memset(vm, 0 , sizeof(*vm)); vm->size = gbufsize * gbuffers; vm->frames = gbuffers; for (i = 0; i < gbuffers; i++) vm->offsets[i] = i * gbufsize; break; } case MEYEIOC_G_PARAMS: { struct meye_params *p = arg; *p = meye.params; break; return 0; } case MEYEIOC_S_PARAMS: { struct meye_params *jp = arg; static int meyeioc_s_params(struct meye_params *jp) { if (jp->subsample > 1) return -EINVAL; if (jp->quality > 10) return -EINVAL; if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63) return -EINVAL; if (jp->framerate > 31) return -EINVAL; mutex_lock(&meye.lock); if (meye.params.subsample != jp->subsample || meye.params.quality != jp->quality) mchip_hic_stop(); /* need restart */ meye.params = *jp; sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, meye.params.sharpness); Loading @@ -1050,34 +905,41 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, meye.params.picture); mutex_unlock(&meye.lock); break; } case MEYEIOC_QBUF_CAPT: { int *nb = arg; return 0; } static int meyeioc_qbuf_capt(int *nb) { if (!meye.grab_fbuffer) return -EINVAL; if (*nb >= gbuffers) return -EINVAL; if (*nb < 0) { /* stop capture */ mchip_hic_stop(); return 0; } if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED) return -EBUSY; mutex_lock(&meye.lock); if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) mchip_cont_compression_start(); meye.grab_buffer[*nb].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int)); mutex_unlock(&meye.lock); break; return 0; } case MEYEIOC_SYNC: { int *i = arg; static int meyeioc_sync(struct file *file, void *fh, int *i) { int unused; if (*i < 0 || *i >= gbuffers) Loading Loading @@ -1106,92 +968,99 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, } *i = meye.grab_buffer[*i].size; mutex_unlock(&meye.lock); break; return 0; } case MEYEIOC_STILLCAPT: { static int meyeioc_stillcapt(void) { if (!meye.grab_fbuffer) return -EINVAL; if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) return -EBUSY; mutex_lock(&meye.lock); meye.grab_buffer[0].state = MEYE_BUF_USING; mchip_take_picture(); mchip_get_picture( meye.grab_fbuffer, mchip_get_picture(meye.grab_fbuffer, mchip_hsize() * mchip_vsize() * 2); meye.grab_buffer[0].state = MEYE_BUF_DONE; mutex_unlock(&meye.lock); break; } case MEYEIOC_STILLJCAPT: { int *len = arg; return 0; } static int meyeioc_stilljcapt(int *len) { if (!meye.grab_fbuffer) return -EINVAL; if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) return -EBUSY; mutex_lock(&meye.lock); meye.grab_buffer[0].state = MEYE_BUF_USING; *len = -1; while (*len == -1) { mchip_take_picture(); *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); } meye.grab_buffer[0].state = MEYE_BUF_DONE; mutex_unlock(&meye.lock); break; return 0; } case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; if (forcev4l1) return -EINVAL; static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { memset(cap, 0, sizeof(*cap)); strcpy(cap->driver, "meye"); strcpy(cap->card, "meye"); sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev)); cap->version = (MEYE_DRIVER_MAJORVERSION << 8) + MEYE_DRIVER_MINORVERSION; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; break; } case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; return 0; } static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { if (i->index != 0) return -EINVAL; memset(i, 0, sizeof(*i)); i->index = 0; strcpy(i->name, "Camera"); i->type = V4L2_INPUT_TYPE_CAMERA; break; } case VIDIOC_G_INPUT: { int *i = arg; return 0; } static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) { *i = 0; break; return 0; } case VIDIOC_S_INPUT: { int *i = arg; if (*i != 0) static int vidioc_s_input(struct file *file, void *fh, unsigned int i) { if (i != 0) return -EINVAL; break; } case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *c = arg; return 0; } static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) { switch (c->id) { case V4L2_CID_BRIGHTNESS: Loading Loading @@ -1284,12 +1153,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, default: return -EINVAL; } break; } case VIDIOC_S_CTRL: { struct v4l2_control *c = arg; return 0; } static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) { mutex_lock(&meye.lock); switch (c->id) { case V4L2_CID_BRIGHTNESS: Loading Loading @@ -1339,12 +1208,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; } mutex_unlock(&meye.lock); break; } case VIDIOC_G_CTRL: { struct v4l2_control *c = arg; return 0; } static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) { mutex_lock(&meye.lock); switch (c->id) { case V4L2_CID_BRIGHTNESS: Loading Loading @@ -1380,16 +1249,19 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; } mutex_unlock(&meye.lock); break; } case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; return 0; } static int vidioc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) { if (f->index > 1) return -EINVAL; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (f->index == 0) { /* standard YUV 422 capture */ memset(f, 0, sizeof(*f)); Loading @@ -1407,21 +1279,26 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, strcpy(f->description, "MJPEG"); f->pixelformat = V4L2_PIX_FMT_MJPEG; } break; } case VIDIOC_TRY_FMT: { struct v4l2_format *f = arg; return 0; } static int vidioc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) return -EINVAL; if (f->fmt.pix.field != V4L2_FIELD_ANY && f->fmt.pix.field != V4L2_FIELD_NONE) return -EINVAL; f->fmt.pix.field = V4L2_FIELD_NONE; if (f->fmt.pix.width <= 320) { f->fmt.pix.width = 320; f->fmt.pix.height = 240; Loading @@ -1429,21 +1306,24 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.width = 640; f->fmt.pix.height = 480; } f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = 0; f->fmt.pix.priv = 0; break; } case VIDIOC_G_FMT: { struct v4l2_format *f = arg; return 0; } static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; switch (meye.mchip_mode) { case MCHIP_HIC_MODE_CONT_OUT: default: Loading @@ -1453,6 +1333,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; break; } f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix.width = mchip_hsize(); f->fmt.pix.height = mchip_vsize(); Loading @@ -1461,22 +1342,26 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.bytesperline; f->fmt.pix.colorspace = 0; f->fmt.pix.priv = 0; break; } case VIDIOC_S_FMT: { struct v4l2_format *f = arg; return 0; } static int vidioc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) return -EINVAL; if (f->fmt.pix.field != V4L2_FIELD_ANY && f->fmt.pix.field != V4L2_FIELD_NONE) return -EINVAL; f->fmt.pix.field = V4L2_FIELD_NONE; mutex_lock(&meye.lock); if (f->fmt.pix.width <= 320) { f->fmt.pix.width = 320; f->fmt.pix.height = 240; Loading @@ -1486,6 +1371,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.height = 480; meye.params.subsample = 0; } switch (f->fmt.pix.pixelformat) { case V4L2_PIX_FMT_YUYV: meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; Loading @@ -1494,6 +1380,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; break; } mutex_unlock(&meye.lock); f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * Loading @@ -1501,21 +1388,25 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.colorspace = 0; f->fmt.pix.priv = 0; break; return 0; } case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *req = arg; static int vidioc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) { int i; if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (req->memory != V4L2_MEMORY_MMAP) return -EINVAL; if (meye.grab_fbuffer && req->count == gbuffers) { /* already allocated, no modifications */ break; return 0; } mutex_lock(&meye.lock); if (meye.grab_fbuffer) { for (i = 0; i < gbuffers; i++) Loading @@ -1526,93 +1417,114 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, rvfree(meye.grab_fbuffer, gbuffers * gbufsize); meye.grab_fbuffer = NULL; } gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS)); req->count = gbuffers; meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize); if (!meye.grab_fbuffer) { printk(KERN_ERR "meye: v4l framebuffer allocation" " failed\n"); mutex_unlock(&meye.lock); return -ENOMEM; } for (i = 0; i < gbuffers; i++) meye.vma_use_count[i] = 0; mutex_unlock(&meye.lock); break; return 0; } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) { int index = buf->index; if (index < 0 || index >= gbuffers) return -EINVAL; memset(buf, 0, sizeof(*buf)); buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf->index = index; buf->bytesused = meye.grab_buffer[index].size; buf->flags = V4L2_BUF_FLAG_MAPPED; if (meye.grab_buffer[index].state == MEYE_BUF_USING) buf->flags |= V4L2_BUF_FLAG_QUEUED; if (meye.grab_buffer[index].state == MEYE_BUF_DONE) buf->flags |= V4L2_BUF_FLAG_DONE; buf->field = V4L2_FIELD_NONE; buf->timestamp = meye.grab_buffer[index].timestamp; buf->sequence = meye.grab_buffer[index].sequence; buf->memory = V4L2_MEMORY_MMAP; buf->m.offset = index * gbufsize; buf->length = gbufsize; break; } case VIDIOC_QBUF: { struct v4l2_buffer *buf = arg; return 0; } static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; if (buf->index < 0 || buf->index >= gbuffers) return -EINVAL; if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED) return -EINVAL; mutex_lock(&meye.lock); buf->flags |= V4L2_BUF_FLAG_QUEUED; buf->flags &= ~V4L2_BUF_FLAG_DONE; meye.grab_buffer[buf->index].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int)); mutex_unlock(&meye.lock); break; return 0; } case VIDIOC_DQBUF: { struct v4l2_buffer *buf = arg; static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { int reqnr; if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; mutex_lock(&meye.lock); if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { mutex_unlock(&meye.lock); return -EAGAIN; } if (wait_event_interruptible(meye.proc_list, kfifo_len(meye.doneq) != 0) < 0) { mutex_unlock(&meye.lock); return -EINTR; } if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr, sizeof(int))) { mutex_unlock(&meye.lock); return -EBUSY; } if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) { mutex_unlock(&meye.lock); return -EINVAL; } buf->index = reqnr; buf->bytesused = meye.grab_buffer[reqnr].size; buf->flags = V4L2_BUF_FLAG_MAPPED; Loading @@ -1624,11 +1536,14 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, buf->length = gbufsize; meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED; mutex_unlock(&meye.lock); break; return 0; } case VIDIOC_STREAMON: { static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) { mutex_lock(&meye.lock); switch (meye.mchip_mode) { case MCHIP_HIC_MODE_CONT_OUT: mchip_continuous_start(); Loading @@ -1640,39 +1555,51 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&meye.lock); return -EINVAL; } mutex_unlock(&meye.lock); break; } case VIDIOC_STREAMOFF: { int i; return 0; } static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) { mutex_lock(&meye.lock); mchip_hic_stop(); kfifo_reset(meye.grabq); kfifo_reset(meye.doneq); for (i = 0; i < MEYE_MAX_BUFNBRS; i++) meye.grab_buffer[i].state = MEYE_BUF_UNUSED; mutex_unlock(&meye.lock); break; return 0; } /* * XXX what about private snapshot ioctls ? * Do they need to be converted to V4L2 ? */ static int vidioc_default(struct file *file, void *fh, int cmd, void *arg) { switch (cmd) { case MEYEIOC_G_PARAMS: return meyeioc_g_params((struct meye_params *) arg); default: return -ENOIOCTLCMD; } case MEYEIOC_S_PARAMS: return meyeioc_s_params((struct meye_params *) arg); return 0; case MEYEIOC_QBUF_CAPT: return meyeioc_qbuf_capt((int *) arg); case MEYEIOC_SYNC: return meyeioc_sync(file, fh, (int *) arg); case MEYEIOC_STILLCAPT: return meyeioc_stillcapt(); case MEYEIOC_STILLJCAPT: return meyeioc_stilljcapt((int *) arg); default: return -EINVAL; } static int meye_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { return video_usercopy(inode, file, cmd, arg, meye_do_ioctl); } static unsigned int meye_poll(struct file *file, poll_table *wait) Loading Loading @@ -1760,7 +1687,7 @@ static const struct file_operations meye_fops = { .open = meye_open, .release = meye_release, .mmap = meye_mmap, .ioctl = meye_ioctl, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, #endif Loading @@ -1775,6 +1702,24 @@ static struct video_device meye_template = { .fops = &meye_fops, .release = video_device_release, .minor = -1, .vidioc_querycap = vidioc_querycap, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, .vidioc_try_fmt_cap = vidioc_try_fmt_cap, .vidioc_g_fmt_cap = vidioc_g_fmt_cap, .vidioc_s_fmt_cap = vidioc_s_fmt_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_default = vidioc_default, }; #ifdef CONFIG_PM Loading