📄 stk-webcam.c
字号:
pix_format->pixelformat = dev->vsettings.palette; if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) pix_format->bytesperline = pix_format->width; else pix_format->bytesperline = 2 * pix_format->width; pix_format->sizeimage = pix_format->bytesperline * pix_format->height; return 0;}static int stk_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmtd){ int i; switch (fmtd->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_SBGGR8: break; default: return -EINVAL; } for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) { if (fmtd->fmt.pix.width > stk_sizes[i].w) break; } if (i == ARRAY_SIZE(stk_sizes) || (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w) < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) { fmtd->fmt.pix.height = stk_sizes[i-1].h; fmtd->fmt.pix.width = stk_sizes[i-1].w; fmtd->fmt.pix.priv = i - 1; } else { fmtd->fmt.pix.height = stk_sizes[i].h; fmtd->fmt.pix.width = stk_sizes[i].w; fmtd->fmt.pix.priv = i; } fmtd->fmt.pix.field = V4L2_FIELD_NONE; fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8) fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width; else fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width; fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline * fmtd->fmt.pix.height; return 0;}static int stk_setup_format(struct stk_camera *dev){ int i = 0; int depth; if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) depth = 1; else depth = 2; while (stk_sizes[i].m != dev->vsettings.mode && i < ARRAY_SIZE(stk_sizes)) i++; if (i == ARRAY_SIZE(stk_sizes)) { STK_ERROR("Something is broken in %s\n", __func__); return -EFAULT; } /* This registers controls some timings, not sure of what. */ stk_camera_write_reg(dev, 0x001b, 0x0e); if (dev->vsettings.mode == MODE_SXGA) stk_camera_write_reg(dev, 0x001c, 0x0e); else stk_camera_write_reg(dev, 0x001c, 0x46); /* * Registers 0x0115 0x0114 are the size of each line (bytes), * regs 0x0117 0x0116 are the heigth of the image. */ stk_camera_write_reg(dev, 0x0115, ((stk_sizes[i].w * depth) >> 8) & 0xff); stk_camera_write_reg(dev, 0x0114, (stk_sizes[i].w * depth) & 0xff); stk_camera_write_reg(dev, 0x0117, (stk_sizes[i].h >> 8) & 0xff); stk_camera_write_reg(dev, 0x0116, stk_sizes[i].h & 0xff); return stk_sensor_configure(dev);}static int stk_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmtd){ int ret; struct stk_camera *dev = priv; if (dev == NULL) return -ENODEV; if (!is_present(dev)) return -ENODEV; if (is_streaming(dev)) return -EBUSY; if (dev->owner && dev->owner != filp) return -EBUSY; ret = stk_vidioc_try_fmt_vid_cap(filp, priv, fmtd); if (ret) return ret; dev->owner = filp; dev->vsettings.palette = fmtd->fmt.pix.pixelformat; stk_free_buffers(dev); dev->frame_size = fmtd->fmt.pix.sizeimage; dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m; stk_initialise(dev); return stk_setup_format(dev);}static int stk_vidioc_reqbufs(struct file *filp, void *priv, struct v4l2_requestbuffers *rb){ struct stk_camera *dev = priv; if (dev == NULL) return -ENODEV; if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (rb->memory != V4L2_MEMORY_MMAP) return -EINVAL; if (is_streaming(dev) || (dev->owner && dev->owner != filp)) return -EBUSY; dev->owner = filp; /*FIXME If they ask for zero, we must stop streaming and free */ if (rb->count < 3) rb->count = 3; /* Arbitrary limit */ else if (rb->count > 5) rb->count = 5; stk_allocate_buffers(dev, rb->count); rb->count = dev->n_sbufs; return 0;}static int stk_vidioc_querybuf(struct file *filp, void *priv, struct v4l2_buffer *buf){ int index; struct stk_camera *dev = priv; struct stk_sio_buffer *sbuf; if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; index = buf->index; if (index < 0 || index >= dev->n_sbufs) return -EINVAL; sbuf = dev->sio_bufs + buf->index; *buf = sbuf->v4lbuf; return 0;}static int stk_vidioc_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf){ struct stk_camera *dev = priv; struct stk_sio_buffer *sbuf; unsigned long flags; if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; if (buf->index < 0 || buf->index >= dev->n_sbufs) return -EINVAL; sbuf = dev->sio_bufs + buf->index; if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) return 0; sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; spin_lock_irqsave(&dev->spinlock, flags); list_add_tail(&sbuf->list, &dev->sio_avail); *buf = sbuf->v4lbuf; spin_unlock_irqrestore(&dev->spinlock, flags); return 0;}static int stk_vidioc_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf){ struct stk_camera *dev = priv; struct stk_sio_buffer *sbuf; unsigned long flags; int ret; if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || !is_streaming(dev)) return -EINVAL; if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) return -EWOULDBLOCK; ret = wait_event_interruptible(dev->wait_frame, !list_empty(&dev->sio_full) || !is_present(dev)); if (ret) return ret; if (!is_present(dev)) return -EIO; spin_lock_irqsave(&dev->spinlock, flags); sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); list_del_init(&sbuf->list); spin_unlock_irqrestore(&dev->spinlock, flags); sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; sbuf->v4lbuf.sequence = ++dev->sequence; do_gettimeofday(&sbuf->v4lbuf.timestamp); *buf = sbuf->v4lbuf; return 0;}static int stk_vidioc_streamon(struct file *filp, void *priv, enum v4l2_buf_type type){ struct stk_camera *dev = priv; if (is_streaming(dev)) return 0; if (dev->sio_bufs == NULL) return -EINVAL; dev->sequence = 0; return stk_start_stream(dev);}static int stk_vidioc_streamoff(struct file *filp, void *priv, enum v4l2_buf_type type){ struct stk_camera *dev = priv; unsigned long flags; int i; stk_stop_stream(dev); spin_lock_irqsave(&dev->spinlock, flags); INIT_LIST_HEAD(&dev->sio_avail); INIT_LIST_HEAD(&dev->sio_full); for (i = 0; i < dev->n_sbufs; i++) { INIT_LIST_HEAD(&dev->sio_bufs[i].list); dev->sio_bufs[i].v4lbuf.flags = 0; } spin_unlock_irqrestore(&dev->spinlock, flags); return 0;}static int stk_vidioc_g_parm(struct file *filp, void *priv, struct v4l2_streamparm *sp){ if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; sp->parm.capture.capability = 0; sp->parm.capture.capturemode = 0; /*FIXME This is not correct */ sp->parm.capture.timeperframe.numerator = 1; sp->parm.capture.timeperframe.denominator = 30; sp->parm.capture.readbuffers = 2; sp->parm.capture.extendedmode = 0; return 0;}static struct file_operations v4l_stk_fops = { .owner = THIS_MODULE, .open = v4l_stk_open, .release = v4l_stk_release, .read = v4l_stk_read, .poll = v4l_stk_poll, .mmap = v4l_stk_mmap, .ioctl = video_ioctl2,#ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32,#endif .llseek = no_llseek};static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { .vidioc_querycap = stk_vidioc_querycap, .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = stk_vidioc_s_fmt_vid_cap, .vidioc_g_fmt_vid_cap = stk_vidioc_g_fmt_vid_cap, .vidioc_enum_input = stk_vidioc_enum_input, .vidioc_s_input = stk_vidioc_s_input, .vidioc_g_input = stk_vidioc_g_input, .vidioc_s_std = stk_vidioc_s_std, .vidioc_reqbufs = stk_vidioc_reqbufs, .vidioc_querybuf = stk_vidioc_querybuf, .vidioc_qbuf = stk_vidioc_qbuf, .vidioc_dqbuf = stk_vidioc_dqbuf, .vidioc_streamon = stk_vidioc_streamon, .vidioc_streamoff = stk_vidioc_streamoff, .vidioc_queryctrl = stk_vidioc_queryctrl, .vidioc_g_ctrl = stk_vidioc_g_ctrl, .vidioc_s_ctrl = stk_vidioc_s_ctrl, .vidioc_g_parm = stk_vidioc_g_parm,};static void stk_v4l_dev_release(struct video_device *vd){ struct stk_camera *dev = vdev_to_camera(vd); if (dev->sio_bufs != NULL || dev->isobufs != NULL) STK_ERROR("We are leaking memory\n"); usb_put_intf(dev->interface); kfree(dev);}static struct video_device stk_v4l_data = { .name = "stkwebcam", .minor = -1, .tvnorms = V4L2_STD_UNKNOWN, .current_norm = V4L2_STD_UNKNOWN, .fops = &v4l_stk_fops, .ioctl_ops = &v4l_stk_ioctl_ops, .release = stk_v4l_dev_release,};static int stk_register_video_device(struct stk_camera *dev){ int err; dev->vdev = stk_v4l_data; dev->vdev.debug = debug; dev->vdev.parent = &dev->interface->dev; err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) STK_ERROR("v4l registration failed\n"); else STK_INFO("Syntek USB2.0 Camera is now controlling video device" " /dev/video%d\n", dev->vdev.num); return err;}/* USB Stuff */static int stk_camera_probe(struct usb_interface *interface, const struct usb_device_id *id){ int i; int err = 0; struct stk_camera *dev = NULL; struct usb_device *udev = interface_to_usbdev(interface); struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL); if (dev == NULL) { STK_ERROR("Out of memory !\n"); return -ENOMEM; } spin_lock_init(&dev->spinlock); init_waitqueue_head(&dev->wait_frame); dev->udev = udev; dev->interface = interface; usb_get_intf(interface); dev->vsettings.vflip = vflip; dev->vsettings.hflip = hflip; dev->n_sbufs = 0; set_present(dev); /* Set up the endpoint information * use only the first isoc-in endpoint * for the current alternate setting */ iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if (!dev->isoc_ep && ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) { /* we found an isoc in endpoint */ dev->isoc_ep = (endpoint->bEndpointAddress & 0xF); break; } } if (!dev->isoc_ep) { STK_ERROR("Could not find isoc-in endpoint"); err = -ENODEV; goto error; } dev->vsettings.brightness = 0x7fff; dev->vsettings.palette = V4L2_PIX_FMT_RGB565; dev->vsettings.mode = MODE_VGA; dev->frame_size = 640 * 480 * 2; INIT_LIST_HEAD(&dev->sio_avail); INIT_LIST_HEAD(&dev->sio_full); usb_set_intfdata(interface, dev); err = stk_register_video_device(dev); if (err) { goto error; } stk_create_sysfs_files(&dev->vdev); usb_autopm_enable(dev->interface); return 0;error: kfree(dev); return err;}static void stk_camera_disconnect(struct usb_interface *interface){ struct stk_camera *dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); unset_present(dev); wake_up_interruptible(&dev->wait_frame); stk_remove_sysfs_files(&dev->vdev); STK_INFO("Syntek USB2.0 Camera release resources " "video device /dev/video%d\n", dev->vdev.num); video_unregister_device(&dev->vdev);}#ifdef CONFIG_PMstatic int stk_camera_suspend(struct usb_interface *intf, pm_message_t message){ struct stk_camera *dev = usb_get_intfdata(intf); if (is_streaming(dev)) { stk_stop_stream(dev); /* yes, this is ugly */ set_streaming(dev); } return 0;}static int stk_camera_resume(struct usb_interface *intf){ struct stk_camera *dev = usb_get_intfdata(intf); if (!is_initialised(dev)) return 0; unset_initialised(dev); stk_initialise(dev); stk_setup_format(dev); if (is_streaming(dev)) stk_start_stream(dev); return 0;}#endifstatic struct usb_driver stk_camera_driver = { .name = "stkwebcam", .probe = stk_camera_probe, .disconnect = stk_camera_disconnect, .id_table = stkwebcam_table,#ifdef CONFIG_PM .suspend = stk_camera_suspend, .resume = stk_camera_resume,#endif};static int __init stk_camera_init(void){ int result; result = usb_register(&stk_camera_driver); if (result) STK_ERROR("usb_register failed ! Error number %d\n", result); return result;}static void __exit stk_camera_exit(void){ usb_deregister(&stk_camera_driver);}module_init(stk_camera_init);module_exit(stk_camera_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -