📄 stk-webcam.c
字号:
for (i = 0; i < MAX_ISO_BUFS; i++) { if (dev->isobufs[i].data == NULL) { kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL); if (kbuf == NULL) { STK_ERROR("Failed to allocate iso buffer %d\n", i); goto isobufs_out; } dev->isobufs[i].data = kbuf; } else STK_ERROR("isobuf data already allocated\n"); if (dev->isobufs[i].urb == NULL) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) { STK_ERROR("Failed to allocate URB %d\n", i); goto isobufs_out; } dev->isobufs[i].urb = urb; } else { STK_ERROR("Killing URB\n"); usb_kill_urb(dev->isobufs[i].urb); urb = dev->isobufs[i].urb; } urb->interval = 1; urb->dev = udev; urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep); urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = dev->isobufs[i].data; urb->transfer_buffer_length = ISO_BUFFER_SIZE; urb->complete = stk_isoc_handler; urb->context = dev; urb->start_frame = 0; urb->number_of_packets = ISO_FRAMES_PER_DESC; for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; } } set_memallocd(dev); return 0;isobufs_out: for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++) kfree(dev->isobufs[i].data); for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++) usb_free_urb(dev->isobufs[i].urb); kfree(dev->isobufs); dev->isobufs = NULL; return -ENOMEM;}static void stk_clean_iso(struct stk_camera *dev){ int i; if (dev == NULL || dev->isobufs == NULL) return; for (i = 0; i < MAX_ISO_BUFS; i++) { struct urb *urb; urb = dev->isobufs[i].urb; if (urb) { if (atomic_read(&dev->urbs_used) && is_present(dev)) usb_kill_urb(urb); usb_free_urb(urb); } kfree(dev->isobufs[i].data); } kfree(dev->isobufs); dev->isobufs = NULL; unset_memallocd(dev);}static int stk_setup_siobuf(struct stk_camera *dev, int index){ struct stk_sio_buffer *buf = dev->sio_bufs + index; INIT_LIST_HEAD(&buf->list); buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size); buf->buffer = vmalloc_user(buf->v4lbuf.length); if (buf->buffer == NULL) return -ENOMEM; buf->mapcount = 0; buf->dev = dev; buf->v4lbuf.index = index; buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf->v4lbuf.field = V4L2_FIELD_NONE; buf->v4lbuf.memory = V4L2_MEMORY_MMAP; buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; return 0;}static int stk_free_sio_buffers(struct stk_camera *dev){ int i; int nbufs; unsigned long flags; if (dev->n_sbufs == 0 || dev->sio_bufs == NULL) return 0; /* * If any buffers are mapped, we cannot free them at all. */ for (i = 0; i < dev->n_sbufs; i++) { if (dev->sio_bufs[i].mapcount > 0) return -EBUSY; } /* * OK, let's do it. */ spin_lock_irqsave(&dev->spinlock, flags); INIT_LIST_HEAD(&dev->sio_avail); INIT_LIST_HEAD(&dev->sio_full); nbufs = dev->n_sbufs; dev->n_sbufs = 0; spin_unlock_irqrestore(&dev->spinlock, flags); for (i = 0; i < nbufs; i++) { if (dev->sio_bufs[i].buffer != NULL) vfree(dev->sio_bufs[i].buffer); } kfree(dev->sio_bufs); dev->sio_bufs = NULL; return 0;}static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs){ int i; if (dev->sio_bufs != NULL) STK_ERROR("sio_bufs already allocated\n"); else { dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer), GFP_KERNEL); if (dev->sio_bufs == NULL) return -ENOMEM; for (i = 0; i < n_sbufs; i++) { if (stk_setup_siobuf(dev, i)) return (dev->n_sbufs > 1)? 0 : -ENOMEM; dev->n_sbufs = i+1; } } return 0;}static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs){ int err; err = stk_prepare_iso(dev); if (err) { stk_clean_iso(dev); return err; } err = stk_prepare_sio_buffers(dev, n_sbufs); if (err) { stk_free_sio_buffers(dev); return err; } return 0;}static void stk_free_buffers(struct stk_camera *dev){ stk_clean_iso(dev); stk_free_sio_buffers(dev);}/* -------------------------------------------- *//* v4l file operations */static int v4l_stk_open(struct inode *inode, struct file *fp){ struct stk_camera *dev; struct video_device *vdev; vdev = video_devdata(fp); dev = vdev_to_camera(vdev); lock_kernel(); if (dev == NULL || !is_present(dev)) { unlock_kernel(); return -ENXIO; } fp->private_data = dev; usb_autopm_get_interface(dev->interface); unlock_kernel(); return 0;}static int v4l_stk_release(struct inode *inode, struct file *fp){ struct stk_camera *dev = fp->private_data; if (dev->owner == fp) { stk_stop_stream(dev); stk_free_buffers(dev); dev->owner = NULL; } if(is_present(dev)) usb_autopm_put_interface(dev->interface); return 0;}static ssize_t v4l_stk_read(struct file *fp, char __user *buf, size_t count, loff_t *f_pos){ int i; int ret; unsigned long flags; struct stk_sio_buffer *sbuf; struct stk_camera *dev = fp->private_data; if (!is_present(dev)) return -EIO; if (dev->owner && dev->owner != fp) return -EBUSY; dev->owner = fp; if (!is_streaming(dev)) { if (stk_initialise(dev) || stk_allocate_buffers(dev, 3) || stk_start_stream(dev)) return -ENOMEM; spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < dev->n_sbufs; i++) { list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail); dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED; } spin_unlock_irqrestore(&dev->spinlock, flags); } if (*f_pos == 0) { if (fp->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; } if (count + *f_pos > dev->frame_size) count = dev->frame_size - *f_pos; spin_lock_irqsave(&dev->spinlock, flags); if (list_empty(&dev->sio_full)) { spin_unlock_irqrestore(&dev->spinlock, flags); STK_ERROR("BUG: No siobufs ready\n"); return 0; } sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); spin_unlock_irqrestore(&dev->spinlock, flags); if (copy_to_user(buf, sbuf->buffer + *f_pos, count)) return -EFAULT; *f_pos += count; if (*f_pos >= dev->frame_size) { *f_pos = 0; spin_lock_irqsave(&dev->spinlock, flags); list_move_tail(&sbuf->list, &dev->sio_avail); spin_unlock_irqrestore(&dev->spinlock, flags); } return count;}static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait){ struct stk_camera *dev = fp->private_data; poll_wait(fp, &dev->wait_frame, wait); if (!is_present(dev)) return POLLERR; if (!list_empty(&dev->sio_full)) return (POLLIN | POLLRDNORM); return 0;}static void stk_v4l_vm_open(struct vm_area_struct *vma){ struct stk_sio_buffer *sbuf = vma->vm_private_data; sbuf->mapcount++;}static void stk_v4l_vm_close(struct vm_area_struct *vma){ struct stk_sio_buffer *sbuf = vma->vm_private_data; sbuf->mapcount--; if (sbuf->mapcount == 0) sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;}static struct vm_operations_struct stk_v4l_vm_ops = { .open = stk_v4l_vm_open, .close = stk_v4l_vm_close};static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma){ unsigned int i; int ret; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; struct stk_camera *dev = fp->private_data; struct stk_sio_buffer *sbuf = NULL; if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) return -EINVAL; for (i = 0; i < dev->n_sbufs; i++) { if (dev->sio_bufs[i].v4lbuf.m.offset == offset) { sbuf = dev->sio_bufs + i; break; } } if (sbuf == NULL) return -EINVAL; ret = remap_vmalloc_range(vma, sbuf->buffer, 0); if (ret) return ret; vma->vm_flags |= VM_DONTEXPAND; vma->vm_private_data = sbuf; vma->vm_ops = &stk_v4l_vm_ops; sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; stk_v4l_vm_open(vma); return 0;}/* v4l ioctl handlers */static int stk_vidioc_querycap(struct file *filp, void *priv, struct v4l2_capability *cap){ strcpy(cap->driver, "stk"); strcpy(cap->card, "stk"); cap->version = DRIVER_VERSION_NUM; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; return 0;}static int stk_vidioc_enum_input(struct file *filp, void *priv, struct v4l2_input *input){ if (input->index != 0) return -EINVAL; strcpy(input->name, "Syntek USB Camera"); input->type = V4L2_INPUT_TYPE_CAMERA; return 0;}static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i){ *i = 0; return 0;}static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i){ if (i != 0) return -EINVAL; else return 0;}/* from vivi.c */static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a){ return 0;}/* List of all V4Lv2 controls supported by the driver */static struct v4l2_queryctrl stk_controls[] = { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", .minimum = 0, .maximum = 0xffff, .step = 0x0100, .default_value = 0x6000, }, /*TODO: get more controls to work */};static int stk_vidioc_queryctrl(struct file *filp, void *priv, struct v4l2_queryctrl *c){ int i; int nbr; nbr = ARRAY_SIZE(stk_controls); for (i = 0; i < nbr; i++) { if (stk_controls[i].id == c->id) { memcpy(c, &stk_controls[i], sizeof(struct v4l2_queryctrl)); return 0; } } return -EINVAL;}static int stk_vidioc_g_ctrl(struct file *filp, void *priv, struct v4l2_control *c){ struct stk_camera *dev = priv; switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = dev->vsettings.brightness; break; default: return -EINVAL; } return 0;}static int stk_vidioc_s_ctrl(struct file *filp, void *priv, struct v4l2_control *c){ struct stk_camera *dev = priv; switch (c->id) { case V4L2_CID_BRIGHTNESS: dev->vsettings.brightness = c->value; return stk_sensor_set_brightness(dev, c->value >> 8); default: return -EINVAL; } return 0;}static int stk_vidioc_enum_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_fmtdesc *fmtd){ fmtd->flags = 0; switch (fmtd->index) { case 0: fmtd->pixelformat = V4L2_PIX_FMT_RGB565; strcpy(fmtd->description, "r5g6b5"); break; case 1: fmtd->pixelformat = V4L2_PIX_FMT_RGB565X; strcpy(fmtd->description, "r5g6b5BE"); break; case 2: fmtd->pixelformat = V4L2_PIX_FMT_UYVY; strcpy(fmtd->description, "yuv4:2:2"); break; case 3: fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8; strcpy(fmtd->description, "Raw bayer"); break; case 4: fmtd->pixelformat = V4L2_PIX_FMT_YUYV; strcpy(fmtd->description, "yuv4:2:2"); break; default: return -EINVAL; } return 0;}static struct stk_size { unsigned w; unsigned h; enum stk_mode m;} stk_sizes[] = { { .w = 1280, .h = 1024, .m = MODE_SXGA, }, { .w = 640, .h = 480, .m = MODE_VGA, }, { .w = 352, .h = 288, .m = MODE_CIF, }, { .w = 320, .h = 240, .m = MODE_QVGA, }, { .w = 176, .h = 144, .m = MODE_QCIF, },};static int stk_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *f){ struct v4l2_pix_format *pix_format = &f->fmt.pix; struct stk_camera *dev = priv; int i; for (i = 0; i < ARRAY_SIZE(stk_sizes) && stk_sizes[i].m != dev->vsettings.mode; i++); if (i == ARRAY_SIZE(stk_sizes)) { STK_ERROR("ERROR: mode invalid\n"); return -EINVAL; } pix_format->width = stk_sizes[i].w; pix_format->height = stk_sizes[i].h; pix_format->field = V4L2_FIELD_NONE; pix_format->colorspace = V4L2_COLORSPACE_SRGB; pix_format->priv = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -