📄 vicam.c
字号:
/* it's not the end of the world if * we fail to turn the camera off. */ set_camera_power(cam, 0); kfree(cam->raw_image); rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); kfree(cam->cntrlbuf); mutex_lock(&cam->cam_lock); cam->open_count--; open_count = cam->open_count; udev = cam->udev; mutex_unlock(&cam->cam_lock); if (!open_count && !udev) { kfree(cam); } return 0;}static void vicam_decode_color(const u8 *data, u8 *rgb){ /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB * Copyright (C) 2002 Monroe Williams (monroe@pobox.com) */ int i, prevY, nextY; prevY = 512; nextY = 512; data += VICAM_HEADER_SIZE; for( i = 0; i < 240; i++, data += 512 ) { const int y = ( i * 242 ) / 240; int j, prevX, nextX; int Y, Cr, Cb; if ( y == 242 - 1 ) { nextY = -512; } prevX = 1; nextX = 1; for ( j = 0; j < 320; j++, rgb += 3 ) { const int x = ( j * 512 ) / 320; const u8 * const src = &data[x]; if ( x == 512 - 1 ) { nextX = -1; } Cr = ( src[prevX] - src[0] ) + ( src[nextX] - src[0] ); Cr /= 2; Cb = ( src[prevY] - src[prevX + prevY] ) + ( src[prevY] - src[nextX + prevY] ) + ( src[nextY] - src[prevX + nextY] ) + ( src[nextY] - src[nextX + nextY] ); Cb /= 4; Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 ); if ( i & 1 ) { int Ct = Cr; Cr = Cb; Cb = Ct; } if ( ( x ^ i ) & 1 ) { Cr = -Cr; Cb = -Cb; } rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900, 0, 255 ); rgb[1] = clamp( ( ( Y - ( 392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000, 0, 255 ); rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300, 0, 255 ); prevX = -1; } prevY = -512; }}static voidread_frame(struct vicam_camera *cam, int framenum){ unsigned char *request = cam->cntrlbuf; int realShutter; int n; int actual_length; if (cam->needsDummyRead) { cam->needsDummyRead = 0; read_frame(cam, framenum); } memset(request, 0, 16); request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain request[1] = 0; // 512x242 capture request[2] = 0x90; // the function of these two bytes request[3] = 0x07; // is not yet understood if (cam->shutter_speed > 60) { // Short exposure realShutter = ((-15631900 / cam->shutter_speed) + 260533) / 1000; request[4] = realShutter & 0xFF; request[5] = (realShutter >> 8) & 0xFF; request[6] = 0x03; request[7] = 0x01; } else { // Long exposure realShutter = 15600 / cam->shutter_speed - 1; request[4] = 0; request[5] = 0; request[6] = realShutter & 0xFF; request[7] = realShutter >> 8; } // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0 request[8] = 0; // bytes 9-15 do not seem to affect exposure or image quality mutex_lock(&cam->cam_lock); if (!cam->udev) { goto done; } n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16); if (n < 0) { printk(KERN_ERR " Problem sending frame capture control message"); goto done; } n = usb_bulk_msg(cam->udev, usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), cam->raw_image, 512 * 242 + 128, &actual_length, 10000); if (n < 0) { printk(KERN_ERR "Problem during bulk read of frame data: %d\n", n); } done: mutex_unlock(&cam->cam_lock);}static ssize_tvicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos ){ struct vicam_camera *cam = file->private_data; DBG("read %d bytes.\n", (int) count); if (*ppos >= VICAM_MAX_FRAME_SIZE) { *ppos = 0; return 0; } if (*ppos == 0) { read_frame(cam, 0); vicam_decode_color(cam->raw_image, cam->framebuf + 0 * VICAM_MAX_FRAME_SIZE); } count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos); if (copy_to_user(buf, &cam->framebuf[*ppos], count)) { count = -EFAULT; } else { *ppos += count; } if (count == VICAM_MAX_FRAME_SIZE) { *ppos = 0; } return count;}static intvicam_mmap(struct file *file, struct vm_area_struct *vma){ // TODO: allocate the raw frame buffer if necessary unsigned long page, pos; unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; struct vicam_camera *cam = file->private_data; if (!cam) return -ENODEV; DBG("vicam_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 > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) return -EINVAL; */ pos = (unsigned long)cam->framebuf; while (size > 0) { page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } return 0;}static const struct file_operations vicam_fops = { .owner = THIS_MODULE, .open = vicam_open, .release = vicam_close, .read = vicam_read, .mmap = vicam_mmap, .ioctl = vicam_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek,};static struct video_device vicam_template = { .owner = THIS_MODULE, .name = "ViCam-based USB Camera", .type = VID_TYPE_CAPTURE, .fops = &vicam_fops, .minor = -1,};/* table of devices that work with this driver */static struct usb_device_id vicam_table[] = { {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)}, {} /* Terminating entry */};MODULE_DEVICE_TABLE(usb, vicam_table);static struct usb_driver vicam_driver = { .name = "vicam", .probe = vicam_probe, .disconnect = vicam_disconnect, .id_table = vicam_table};/** * vicam_probe * @intf: the interface * @id: the device id * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. */static intvicam_probe( struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *dev = interface_to_usbdev(intf); int bulkEndpoint = 0; const struct usb_host_interface *interface; const struct usb_endpoint_descriptor *endpoint; struct vicam_camera *cam; printk(KERN_INFO "ViCam based webcam connected\n"); interface = intf->cur_altsetting; DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints)); endpoint = &interface->endpoint[0].desc; 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 = kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "could not allocate kernel memory for vicam_camera struct\n"); return -ENOMEM; } cam->shutter_speed = 15; mutex_init(&cam->cam_lock); memcpy(&cam->vdev, &vicam_template, sizeof (vicam_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 -EIO; } printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); usb_set_intfdata (intf, cam); return 0;}static voidvicam_disconnect(struct usb_interface *intf){ int open_count; struct vicam_camera *cam = usb_get_intfdata (intf); usb_set_intfdata (intf, NULL); /* we must unregister the device before taking its * cam_lock. This is because the video open call * holds the same lock as video unregister. if we * unregister inside of the cam_lock and open also * uses the cam_lock, we get deadlock. */ video_unregister_device(&cam->vdev); /* stop the camera from being used */ mutex_lock(&cam->cam_lock); /* mark the camera as gone */ cam->udev = NULL; /* the only thing left to do is synchronize with * our close/release function on who should release * the camera memory. if there are any users using the * camera, it's their job. if there are no users, * it's ours. */ open_count = cam->open_count; mutex_unlock(&cam->cam_lock); if (!open_count) { kfree(cam); } printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");}/* */static int __initusb_vicam_init(void){ int retval; DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); retval = usb_register(&vicam_driver); if (retval) printk(KERN_WARNING "usb_register failed!\n"); return retval;}static void __exitusb_vicam_exit(void){ DBG(KERN_INFO "ViCam-based WebCam driver shutdown\n"); usb_deregister(&vicam_driver);}module_init(usb_vicam_init);module_exit(usb_vicam_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -