📄 vicam.c
字号:
n = usb_bulk_msg(cam->udev, usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), cam->raw_image, 512 * 242 + 128, &actual_length, 500); if (n < 0) { printk(KERN_ERR "Problem during bulk read of frame data: %d\n", n); } vicam_decode_color(cam->raw_image, cam->framebuf + framenum * VICAM_MAX_FRAME_SIZE ); cam->framebuf_size = 320 * 240 * VICAM_BYTES_PER_PIXEL; cam->framebuf_read_start = 0; return;}static longvicam_read(struct video_device *dev, char *buf, unsigned long count, int noblock){ struct vicam_camera *cam = dev->priv; 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; } } } down_interruptible(&cam->busy_lock); if (cam->needsDummyRead) { read_frame(cam, 0); cam->needsDummyRead = 0; } // read_frame twice because the camera doesn't seem to take the shutter speed for the first one. 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 intvicam_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 vicam_camera *cam = dev->priv; 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; */ /* make this _really_ smp-safe */ if (down_interruptible(&cam->busy_lock)) return -EINTR; if (!cam->framebuf) { /* we do lazy allocation */ cam->framebuf = usbvideo_rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_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;}#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry *vicam_proc_root = NULL;static intvicam_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ char *out = page; int len; struct vicam_camera *cam = (struct vicam_camera *) data; out += sprintf(out, "Vicam-based WebCam Linux Driver.\n"); out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n"); out += sprintf(out, "vicam stats:\n"); out += sprintf(out, " Shutter Speed: 1/%d\n", cam->shutter_speed); out += sprintf(out, " Gain: %d\n", cam->gain); len = out - page; len -= off; if (len < count) { *eof = 1; if (len <= 0) return 0; } else len = count; *start = page + off; return len;}static intvicam_write_proc(struct file *file, const char *buffer, unsigned long count, void *data){ char *in; char *start; struct vicam_camera *cam = (struct vicam_camera *) data; in = kmalloc(count + 1, GFP_KERNEL); if (!in) return -ENOMEM; in[count] = 0; // I'm not sure buffer is gauranteed to be null terminated // so I do this to make sure I have a null in there. strncpy(in, buffer, count); start = strstr(in, "gain="); if (start && (start == in || *(start - 1) == ' ' || *(start - 1) == ',')) cam->gain = simple_strtoul(start + 5, NULL, 10); start = strstr(in, "shutter="); if (start && (start == in || *(start - 1) == ' ' || *(start - 1) == ',')) cam->shutter_speed = simple_strtoul(start + 8, NULL, 10); kfree(in); return count;}voidvicam_create_proc_root(void){ vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0); if (vicam_proc_root) vicam_proc_root->owner = THIS_MODULE; else printk(KERN_ERR "could not create /proc entry for vicam!");}voidvicam_destroy_proc_root(void){ if (vicam_proc_root) remove_proc_entry("video/vicam", 0);}voidvicam_create_proc_entry(void *ptr){ struct vicam_camera *cam = (struct vicam_camera *) ptr; char name[7]; struct proc_dir_entry *ent; DBG(KERN_INFO "vicam: creating proc entry\n"); if (!vicam_proc_root || !cam) { printk(KERN_INFO "vicam: could not create proc entry, %s pointer is null.\n", (!cam ? "camera" : "root")); return; } sprintf(name, "video%d", cam->vdev.minor); ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, vicam_proc_root); if (!ent) return; ent->data = cam; ent->read_proc = vicam_read_proc; ent->write_proc = vicam_write_proc; ent->size = 512; cam->proc_entry = ent;}voidvicam_destroy_proc_entry(void *ptr){ struct vicam_camera *cam = (struct vicam_camera *) ptr; char name[7]; if (!cam || !cam->proc_entry) return; sprintf(name, "video%d", cam->vdev.minor); remove_proc_entry(name, vicam_proc_root); cam->proc_entry = NULL;}#endifintvicam_video_init(struct video_device *vdev){ // This would normally create the proc entry for this camera#ifdef CONFIG_PROC_FS vicam_create_proc_entry(vdev->priv);#endif return 0;}static longvicam_write(struct video_device *v, const char *buf, unsigned long count, int nonblock){ return -EINVAL;}static struct video_device vicam_template = { owner:THIS_MODULE, name:"ViCam-based USB Camera", type:VID_TYPE_CAPTURE, hardware:VID_HARDWARE_VICAM, open:vicam_open, close:vicam_close, read:vicam_read, write:vicam_write, ioctl:vicam_ioctl, mmap:vicam_mmap, initialize:vicam_video_init, 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)}, {} /* 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 * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. */static void *vicam_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 vicam_camera *cam; /* See if the device offered us matches what we can accept */ if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { return NULL; } printk(KERN_INFO "ViCam 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 vicam_camera), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "could not allocate kernel memory for vicam_camera struct\n"); return NULL; } memset(cam, 0, sizeof (struct vicam_camera)); cam->shutter_speed = 15; init_MUTEX(&cam->busy_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 NULL; } printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); return cam;}static voidvicam_disconnect(struct usb_device *dev, void *ptr){ struct vicam_camera *cam = ptr; video_unregister_device(&cam->vdev);#ifdef CONFIG_PROC_FS vicam_destroy_proc_entry(cam);#endif if (cam->raw_image) kfree(cam->raw_image); if (cam->framebuf) usbvideo_rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); kfree(cam); printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");}/* */static int __initusb_vicam_init(void){ DBG(KERN_INFO "ViCam-based WebCam driver startup\n");#ifdef CONFIG_PROC_FS vicam_create_proc_root();#endif if (usb_register(&vicam_driver) != 0) printk(KERN_WARNING "usb_register failed!\n"); return 0;}static void __exitusb_vicam_exit(void){ DBG(KERN_INFO "ViCam-based WebCam driver shutdown\n"); usb_deregister(&vicam_driver);#ifdef CONFIG_PROC_FS vicam_destroy_proc_root();#endif}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 + -