📄 sqcam.c
字号:
DBG("open\n"); if (!cam) { printk(KERN_ERR "sqcam video_device improperly initialized"); } intr = down_interruptible(&cam->busy_lock); if (intr) return -EINTR; if (cam->is_opened) { printk(KERN_INFO "sqcam_open called on already opened camera"); up(&cam->busy_lock); return -EBUSY; } if (!cam->raw_image) { cam->raw_image = kmalloc(SQCAM_MAX_RAW_SIZE, GFP_KERNEL); if (!cam->raw_image) { up(&cam->busy_lock); return -ENOMEM; } } if (!cam->framebuf) { cam->framebuf = usbvideo_rvmalloc(SQCAM_MAX_FRAME_SIZE * SQCAM_FRAMES); if (!cam->framebuf) { kfree(cam->raw_image); up(&cam->busy_lock); return -ENOMEM; } } if (!cam->is_initialized) { initialize_camera(cam); cam->is_initialized = 1; } n = send_control_msg(1, cam->udev, 0x0c, 0xc0, 0, NULL, 0); siz = 0x61; // 0x60 -> 160x120, 0x61 -> 320x240 if (n >= 0) n = send_control_msg(1, cam->udev, 0x0c, 0x06, siz, NULL, 0); if (n >= 0) n = send_control_msg(0, cam->udev, 0x0c, 0x07, 0, NULL, 0); cam->is_opened = 1; up(&cam->busy_lock); return 0;}static voidsqcam_close(struct video_device *dev){ struct sqcam_camera *cam = (struct sqcam_camera *) dev->priv; DBG("close\n"); if (cam->is_removed) { sqcam_purge(cam); } else { reset_camera(cam); cam->is_opened = 0; }}#define DATA_HEADER_SIZE 64void sqcam_decode_bayer(char *data, char *rgb){ int j; unsigned char b; unsigned char *src; unsigned char *dst; src = data + DATA_HEADER_SIZE; dst = rgb; /* Reverse the data, else the pic is upside down. */ for (j = 0; j < 320*240 / 2; j++) { b = src[j]; src[j] = src[320*240 - 1 - j]; src[320*240 - 1 - j] = b; } gp_bayer_decode(src, 320, 240, dst, 3);}static voidread_frame(struct sqcam_camera *cam, int framenum){ unsigned char siz; int n, read; int actual_length; read = 320 * 240 + 64; // read 'read' bytes in SQCAM_MAX_READ_SIZE chunks do { siz = 0x50; n = send_control_msg(1, cam->udev, 0x0c, 0x03, (read > SQCAM_MAX_READ_SIZE) ? SQCAM_MAX_READ_SIZE : read, &siz, 1); if (n < 0) { printk(KERN_ERR " Problem sending frame capture control message"); return; } n = usb_bulk_msg(cam->udev, usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), cam->raw_image + (320*240+64 - read), (read > SQCAM_MAX_READ_SIZE) ? SQCAM_MAX_READ_SIZE : read, &actual_length, 500); read -= actual_length; DBG("blk msg:: size: %d\n", actual_length); if (n < 0) { printk(KERN_ERR "Problem during bulk read of frame data: %d\n", n); read = 0; } } while (read); sqcam_decode_bayer(cam->raw_image, cam->framebuf + framenum * SQCAM_MAX_FRAME_SIZE ); cam->framebuf_size = 320 * 240 * SQCAM_BYTES_PER_PIXEL; cam->framebuf_read_start = 0; return;}static longsqcam_read(struct video_device *dev, char *buf, unsigned long count, int noblock){ struct sqcam_camera *cam = dev->priv; int intr; DBG("read %d bytes.\n", (int) count); if (!buf) return -EINVAL; if (!count) return -EINVAL; // This is some code that will hopefully allow us to do shell copies // from the /dev/videoX to a file and have it actually work. if (cam->framebuf_size != 0) { if (cam->framebuf_read_start == cam->framebuf_size) { cam->framebuf_size = cam->framebuf_read_start = 0; return 0; } else { if (cam->framebuf_read_start + count <= cam->framebuf_size) { // count does not exceed available bytes copy_to_user(buf, (cam->framebuf) + cam->framebuf_read_start, count); cam->framebuf_read_start += count; return count; } else { count = cam->framebuf_size - cam->framebuf_read_start; copy_to_user(buf, (cam->framebuf) + cam->framebuf_read_start, count); cam->framebuf_read_start = cam->framebuf_size; return count; } } } intr = down_interruptible(&cam->busy_lock); if (intr) return -EINTR; read_frame(cam, 0); if (count > cam->framebuf_size) count = cam->framebuf_size; copy_to_user(buf, cam->framebuf, count); if (count != cam->framebuf_size) cam->framebuf_read_start = count; else cam->framebuf_size = 0; up(&cam->busy_lock); return count;}static intsqcam_mmap(struct video_device *dev, const char *adr, unsigned long size){ // TODO: allocate the raw frame buffer if necessary unsigned long start = (unsigned long) adr; unsigned long page, pos; struct sqcam_camera *cam = dev->priv; if (!cam) return -ENODEV; DBG("sqcam_mmap: %ld\n", size); /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes * to the size the application requested for mmap and it was screwing apps up. if (size > SQCAM_FRAMES*SQCAM_MAX_FRAME_SIZE) return -EINVAL; */ /* make this _really_ smp-safe */ if (down_interruptible(&cam->busy_lock)) return -EINTR; if (!cam->framebuf) { /* we do lazy allocation */ cam->framebuf = usbvideo_rvmalloc(SQCAM_MAX_FRAME_SIZE * SQCAM_FRAMES); if (!cam->framebuf) { up(&cam->busy_lock); return -ENOMEM; } } pos = (unsigned long) (cam->framebuf); while (size > 0) { page = usbvideo_kvirt_to_pa(pos); if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { up(&cam->busy_lock); return -EAGAIN; } start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } up(&cam->busy_lock); return 0;}intsqcam_video_init(struct video_device *vdev){ return 0;}static longsqcam_write(struct video_device *v, const char *buf, unsigned long count, int nonblock){ return -EINVAL;}static struct video_device sqcam_template = { owner:THIS_MODULE, name:"SQcam-based USB Camera", type:VID_TYPE_CAPTURE, hardware:VID_HARDWARE_SE401, /* need an own value */ open:sqcam_open, close:sqcam_close, read:sqcam_read, write:sqcam_write, ioctl:sqcam_ioctl, mmap:sqcam_mmap, initialize:sqcam_video_init, minor:-1,};/* table of devices that work with this driver */static struct usb_device_id sqcam_table[] = { {USB_DEVICE(USB_SQCAM_VENDOR_ID, USB_SQCAM_PRODUCT_ID)}, {} /* Terminating entry */};MODULE_DEVICE_TABLE(usb, sqcam_table);static struct usb_driver sqcam_driver = { name:"sqcam", probe:sqcam_probe, disconnect:sqcam_disconnect, id_table:sqcam_table};/** * sqcam_probe * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. */static void *sqcam_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){ int nas, bulkEndpoint = 0; const struct usb_interface_descriptor *interface; const struct usb_endpoint_descriptor *endpoint; struct sqcam_camera *cam; /* See if the device offered us matches what we can accept */ if ((dev->descriptor.idVendor != USB_SQCAM_VENDOR_ID) || (dev->descriptor.idProduct != USB_SQCAM_PRODUCT_ID)) { return NULL; } printk(KERN_INFO "SQcam based webcam connected\n"); nas = dev->actconfig->interface[ifnum].num_altsetting; if (nas != 1) { printk(KERN_WARNING "Expected only one alternate setting for this camera!\n"); return NULL; } interface = &dev->actconfig->interface[ifnum].altsetting[0]; DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", ifnum, (unsigned) (interface->bNumEndpoints)); endpoint = &interface->endpoint[0]; if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x02)) { /* we found a bulk in endpoint */ bulkEndpoint = endpoint->bEndpointAddress; } else { printk(KERN_ERR "No bulk in endpoint was found ?! (this is bad)\n"); } if ((cam = kmalloc(sizeof (struct sqcam_camera), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "could not allocate kernel memory for sqcam_camera struct\n"); return NULL; } memset(cam, 0, sizeof (struct sqcam_camera)); init_MUTEX(&cam->busy_lock); memcpy(&cam->vdev, &sqcam_template, sizeof (sqcam_template)); cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only cam->udev = dev; cam->bulkEndpoint = bulkEndpoint; if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { kfree(cam); printk(KERN_WARNING "video_register_device failed\n"); return NULL; } printk(KERN_INFO "SQcam webcam driver now controlling video device %d\n",cam->vdev.minor); return cam;}static voidsqcam_purge(struct sqcam_camera *cam){ video_unregister_device(&cam->vdev); if (cam->raw_image) kfree(cam->raw_image); if (cam->framebuf) usbvideo_rvfree(cam->framebuf, SQCAM_MAX_FRAME_SIZE * SQCAM_FRAMES); kfree(cam); printk(KERN_DEBUG "SQcam-based WebCam disconnected\n");}static voidsqcam_disconnect(struct usb_device *dev, void *ptr){ struct sqcam_camera *cam = ptr; if (cam->is_opened) { cam->is_removed = 1; } else { sqcam_purge(cam); }}/* */static int __initusb_sqcam_init(void){ DBG(KERN_INFO "SQcam-based WebCam driver startup\n"); if (usb_register(&sqcam_driver) != 0) printk(KERN_WARNING "usb_register failed!\n"); return 0;}static void __exitusb_sqcam_exit(void){ DBG(KERN_INFO "SQcam-based WebCam driver shutdown\n"); usb_deregister(&sqcam_driver);}module_init(usb_sqcam_init);module_exit(usb_sqcam_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");/* bayer.c * * Copyright
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -