sn9c102_core.c
字号:
return 0; } case VIDIOC_G_FMT: { struct v4l2_format format; struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format); if (copy_from_user(&format, arg, sizeof(format))) return -EFAULT; if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; pfmt->bytesperline = (pfmt->width * pfmt->priv) / 8; pfmt->sizeimage = pfmt->height * pfmt->bytesperline; pfmt->field = V4L2_FIELD_NONE; memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); if (copy_to_user(arg, &format, sizeof(format))) return -EFAULT; return 0; } case VIDIOC_TRY_FMT: case VIDIOC_S_FMT: { struct sn9c102_sensor* s = cam->sensor; struct v4l2_format format; struct v4l2_pix_format* pix; struct v4l2_pix_format* pfmt = &(s->pix_format); struct v4l2_rect* bounds = &(s->cropcap.bounds); struct v4l2_rect rect; u8 scale; const enum sn9c102_stream_state stream = cam->stream; const u32 nbuffers = cam->nbuffers; u32 i; int err = 0; if (copy_from_user(&format, arg, sizeof(format))) return -EFAULT; pix = &(format.fmt.pix); if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; memcpy(&rect, &(s->_rect), sizeof(rect)); { /* calculate the scaling factor */ u32 a, b; a = rect.width * rect.height; b = pix->width * pix->height; scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 : ((a / b) > 4 ? 4 : (a / b)))) : 1; } rect.width = scale * pix->width; rect.height = scale * pix->height; if (rect.width < 16) rect.width = 16; if (rect.height < 16) rect.height = 16; if (rect.width > bounds->left + bounds->width - rect.left) rect.width = bounds->left+bounds->width - rect.left; if (rect.height > bounds->top + bounds->height - rect.top) rect.height = bounds->top + bounds->height - rect.top; rect.width &= ~15L; rect.height &= ~15L; pix->width = rect.width / scale; pix->height = rect.height / scale; pix->pixelformat = pfmt->pixelformat; pix->priv = pfmt->priv; /* bpp */ pix->colorspace = pfmt->colorspace; pix->bytesperline = (pix->width * pix->priv) / 8; pix->sizeimage = pix->height * pix->bytesperline; pix->field = V4L2_FIELD_NONE; if (cmd == VIDIOC_TRY_FMT) return 0; for (i = 0; i < cam->nbuffers; i++) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_FMT failed. " "Unmap the buffers first.") return -EINVAL; } if (cam->stream == STREAM_ON) { cam->stream = STREAM_INTERRUPT; err = wait_event_interruptible ( cam->wait_stream, (cam->stream == STREAM_OFF) || (cam->state & DEV_DISCONNECTED) ); if (err) { cam->state |= DEV_MISCONFIGURED; DBG(1, "The camera is misconfigured. To use " "it, close and open /dev/video%d " "again.", cam->v4ldev->minor) return err; } if (cam->state & DEV_DISCONNECTED) return -ENODEV; } if (copy_to_user(arg, &format, sizeof(format))) { cam->stream = stream; return -EFAULT; } sn9c102_release_buffers(cam); err = sn9c102_set_crop(cam, &rect); if (s->set_crop) err += s->set_crop(cam, &rect); err += sn9c102_set_scale(cam, scale); if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of hardware " "problems. To use the camera, close and open " "/dev/video%d again.", cam->v4ldev->minor) return err; } memcpy(pfmt, pix, sizeof(*pix)); memcpy(&(s->_rect), &rect, sizeof(rect)); if (nbuffers != sn9c102_request_buffers(cam, nbuffers)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of not enough " "memory. To use the camera, close and open " "/dev/video%d again.", cam->v4ldev->minor) return -ENOMEM; } cam->stream = stream; return 0; } case VIDIOC_REQBUFS: { struct v4l2_requestbuffers rb; u32 i; int err; if (copy_from_user(&rb, arg, sizeof(rb))) return -EFAULT; if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || rb.memory != V4L2_MEMORY_MMAP) return -EINVAL; if (cam->io == IO_READ) { DBG(3, "Close and open the device again to choose " "the mmap I/O method") return -EINVAL; } for (i = 0; i < cam->nbuffers; i++) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_REQBUFS failed. " "Previous buffers are still mapped.") return -EINVAL; } if (cam->stream == STREAM_ON) { cam->stream = STREAM_INTERRUPT; err = wait_event_interruptible ( cam->wait_stream, (cam->stream == STREAM_OFF) || (cam->state & DEV_DISCONNECTED) ); if (err) { cam->state |= DEV_MISCONFIGURED; DBG(1, "The camera is misconfigured. To use " "it, close and open /dev/video%d " "again.", cam->v4ldev->minor) return err; } if (cam->state & DEV_DISCONNECTED) return -ENODEV; } sn9c102_empty_framequeues(cam); sn9c102_release_buffers(cam); if (rb.count) rb.count = sn9c102_request_buffers(cam, rb.count); if (copy_to_user(arg, &rb, sizeof(rb))) { sn9c102_release_buffers(cam); cam->io = IO_NONE; return -EFAULT; } cam->io = rb.count ? IO_MMAP : IO_NONE; return 0; } case VIDIOC_QUERYBUF: { struct v4l2_buffer b; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || b.index >= cam->nbuffers || cam->io != IO_MMAP) return -EINVAL; memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); if (cam->frame[b.index].vma_use_count) b.flags |= V4L2_BUF_FLAG_MAPPED; if (cam->frame[b.index].state == F_DONE) b.flags |= V4L2_BUF_FLAG_DONE; else if (cam->frame[b.index].state != F_UNUSED) b.flags |= V4L2_BUF_FLAG_QUEUED; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; return 0; } case VIDIOC_QBUF: { struct v4l2_buffer b; unsigned long lock_flags; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || b.index >= cam->nbuffers || cam->io != IO_MMAP) return -EINVAL; if (cam->frame[b.index].state != F_UNUSED) return -EINVAL; cam->frame[b.index].state = F_QUEUED; spin_lock_irqsave(&cam->queue_lock, lock_flags); list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); spin_unlock_irqrestore(&cam->queue_lock, lock_flags); PDBGG("Frame #%lu queued", (unsigned long)b.index) return 0; } case VIDIOC_DQBUF: { struct v4l2_buffer b; struct sn9c102_frame_t *f; unsigned long lock_flags; int err = 0; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) return -EINVAL; if (list_empty(&cam->outqueue)) { if (cam->stream == STREAM_OFF) return -EINVAL; if (filp->f_flags & O_NONBLOCK) return -EAGAIN; err = wait_event_interruptible ( cam->wait_frame, (!list_empty(&cam->outqueue)) || (cam->state & DEV_DISCONNECTED) ); if (err) return err; if (cam->state & DEV_DISCONNECTED) return -ENODEV; } spin_lock_irqsave(&cam->queue_lock, lock_flags); f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); list_del(&cam->outqueue); spin_unlock_irqrestore(&cam->queue_lock, lock_flags); f->state = F_UNUSED; memcpy(&b, &f->buf, sizeof(b)); if (f->vma_use_count) b.flags |= V4L2_BUF_FLAG_MAPPED; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index) return 0; } case VIDIOC_STREAMON: { int type; if (copy_from_user(&type, arg, sizeof(type))) return -EFAULT; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) return -EINVAL; if (list_empty(&cam->inqueue)) return -EINVAL; cam->stream = STREAM_ON; DBG(3, "Stream on") return 0; } case VIDIOC_STREAMOFF: { int type, err; if (copy_from_user(&type, arg, sizeof(type))) return -EFAULT; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) return -EINVAL; if (cam->stream == STREAM_ON) { cam->stream = STREAM_INTERRUPT; err = wait_event_interruptible ( cam->wait_stream, (cam->stream == STREAM_OFF) || (cam->state & DEV_DISCONNECTED) ); if (err) { cam->state |= DEV_MISCONFIGURED; DBG(1, "The camera is misconfigured. To use " "it, close and open /dev/video%d " "again.", cam->v4ldev->minor) return err; } if (cam->state & DEV_DISCONNECTED) return -ENODEV; } sn9c102_empty_framequeues(cam); DBG(3, "Stream off") return 0; } case VIDIOC_G_STD: case VIDIOC_S_STD: case VIDIOC_QUERYSTD: case VIDIOC_ENUMSTD: case VIDIOC_QUERYMENU: case VIDIOC_G_PARM: case VIDIOC_S_PARM: return -EINVAL; default: return -EINVAL; }}static int sn9c102_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg){ struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); int err = 0; if (down_interruptible(&cam->fileop_sem)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present") up(&cam->fileop_sem); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it again.") up(&cam->fileop_sem); return -EIO; } err = sn9c102_v4l2_ioctl(inode, filp, cmd, (void __user *)arg); up(&cam->fileop_sem); return err;}static struct file_operations sn9c102_fops = { .owner = THIS_MODULE, .open = sn9c102_open, .release = sn9c102_release, .ioctl = sn9c102_ioctl, .read = sn9c102_read, .poll = sn9c102_poll, .mmap = sn9c102_mmap, .llseek = no_llseek,};/*****************************************************************************//* It exists a single interface only. We do not need to validate anything. */static intsn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id){ struct usb_device *udev = interface_to_usbdev(intf); struct sn9c102_device* cam; static unsigned int dev_nr = 0; unsigned int i, n; int err = 0, r; n = sizeof(sn9c102_id_table)/sizeof(sn9c102_id_table[0]); for (i = 0; i < n-1; i++) if (udev->descriptor.idVendor==sn9c102_id_table[i].idVendor && udev->descriptor.idProduct==sn9c102_id_table[i].idProduct) break; if (i == n-1) return -ENODEV; if (!(cam = kmalloc(sizeof(struct sn9c102_device), GFP_KERNEL))) return -ENOMEM; memset(cam, 0, sizeof(*cam)); cam->usbdev = udev; memcpy(&cam->dev, &udev->dev, sizeof(struct device)); if (!(cam->control_buffer = kmalloc(8, GFP_KERNEL))) { DBG(1, "kmalloc() failed") err = -ENOMEM; goto fail; } memset(cam->control_buffer, 0, 8); if (!(cam->v4ldev = video_device_alloc())) { DBG(1, "video_device_alloc() failed") err = -ENOMEM; goto fail; } init_MUTEX(&cam->dev_sem); r = sn9c102_read_reg(cam, 0x00); if (r < 0 || r != 0x10) { DBG(1, "Sorry, this is not a SN9C10[12] based camera " "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct) err = -ENODEV; goto fail; } DBG(2, "SN9C10[12] PC Camera Controller detected " "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor, sn9c102_id_table[i].idProduct) for (i = 0; sn9c102_sensor_table[i]; i++) { err = sn9c102_sensor_table[i](cam); if (!err) break; } if (!err && cam->sensor) { DBG(2, "%s image sensor detected", cam->sensor->name) DBG(3, "Support for %s maintained by %s", cam->sensor->name, cam->sensor->maintainer) } else { DBG(1, "No supported image sensor detected") err = -ENODEV; goto fail; } if (sn9c102_init(cam)) { DBG(1, "Initialization failed. I will retry on open().") cam->state |= DEV_MISCONFIGURED; } strcpy(cam->v4ldev->name, "SN9C10[12] PC Camera"); cam->v4ldev->owner = THIS_MODULE; cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->hardware = VID_HARDWARE_SN9C102; cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); down(&cam->dev_sem); err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, video_nr[dev_nr]); if (err) { DBG(1, "V4L2 device registration failed") if (err == -ENFILE && video_nr[dev_nr] == -1) DBG(1, "Free /dev/videoX node not found") video_nr[dev_nr] = -1; dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; up(&cam->dev_sem); goto fail; } DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor) sn9c102_create_sysfs(cam); usb_set_intfdata(intf, cam); up(&cam->dev_sem); return 0;fail: if (cam) { kfree(cam->control_buffer); if (cam->v4ldev) video_device_release(cam->v4ldev); kfree(cam); } return err;}static void sn9c102_usb_disconnect(struct usb_interface* intf){ struct sn9c102_device* cam = usb_get_intfdata(intf); if (!cam) return; down_write(&sn9c102_disconnect); down(&cam->dev_sem); DBG(2, "Disconnecting %s...", cam->v4ldev->name) wake_up_interruptible_all(&cam->open); if (cam->users) { DBG(2, "Device /dev/video%d is open! Deregistration and " "memory deallocation are deferred on close.", cam->v4ldev->minor) cam->state |= DEV_MISCONFIGURED; sn9c102_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; wake_up_interruptible(&cam->wait_frame); wake_up_interruptible(&cam->wait_stream); } else { cam->state |= DEV_DISCONNECTED; sn9c102_release_resources(cam); } up(&cam->dev_sem); if (!cam->users) kfree(cam); up_write(&sn9c102_disconnect);}static struct usb_driver sn9c102_usb_driver = { .owner = THIS_MODULE, .name = "sn9c102", .id_table = sn9c102_id_table, .probe = sn9c102_usb_probe, .disconnect = sn9c102_usb_disconnect,};/*****************************************************************************/static int __init sn9c102_module_init(void){ int err = 0; KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION) KDBG(3, SN9C102_MODULE_AUTHOR) if ((err = usb_register(&sn9c102_usb_driver))) KDBG(1, "usb_register() failed") return err;}static void __exit sn9c102_module_exit(void){ usb_deregister(&sn9c102_usb_driver);}module_init(sn9c102_module_init);module_exit(sn9c102_module_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -