📄 se401.c
字号:
if (!se401->dev) return -EIO; switch (cmd) { case VIDIOCGCAP: { struct video_capability b; strcpy(b.name, se401->camera_name); b.type = VID_TYPE_CAPTURE; b.channels = 1; b.audios = 0; b.maxwidth = se401->width[se401->sizes-1]; b.maxheight = se401->height[se401->sizes-1]; b.minwidth = se401->width[0]; b.minheight = se401->height[0]; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; return 0; } case VIDIOCGCHAN: { struct video_channel v; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; if (v.channel != 0) return -EINVAL; v.flags = 0; v.tuners = 0; v.type = VIDEO_TYPE_CAMERA; strcpy(v.name, "Camera"); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; return 0; } case VIDIOCSCHAN: { int v; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; if (v != 0) return -EINVAL; return 0; } case VIDIOCGPICT: { struct video_picture p; se401_get_pict(se401, &p); if (copy_to_user(arg, &p, sizeof(p))) return -EFAULT; return 0; } case VIDIOCSPICT: { struct video_picture p; if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; if (se401_set_pict(se401, &p)) return -EINVAL; return 0; } case VIDIOCSWIN: { struct video_window vw; if (copy_from_user(&vw, arg, sizeof(vw))) return -EFAULT; if (vw.flags) return -EINVAL; if (vw.clipcount) return -EINVAL; if (se401_set_size(se401, vw.width, vw.height)) return -EINVAL; return 0; } case VIDIOCGWIN: { struct video_window vw; vw.x = 0; /* FIXME */ vw.y = 0; vw.chromakey = 0; vw.flags = 0; vw.clipcount = 0; vw.width = se401->cwidth; vw.height = se401->cheight; if (copy_to_user(arg, &vw, sizeof(vw))) return -EFAULT; return 0; } case VIDIOCGMBUF: { struct video_mbuf vm; int i; memset(&vm, 0, sizeof(vm)); vm.size = SE401_NUMFRAMES * se401->maxframesize; vm.frames = SE401_NUMFRAMES; for (i=0; i<SE401_NUMFRAMES; i++) vm.offsets[i] = se401->maxframesize * i; if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) return -EFAULT; return 0; } case VIDIOCMCAPTURE: { struct video_mmap vm; if (copy_from_user(&vm, arg, sizeof(vm))) return -EFAULT; if (vm.format != VIDEO_PALETTE_RGB24) return -EINVAL; if (vm.frame >= SE401_NUMFRAMES) return -EINVAL; if (se401->frame[vm.frame].grabstate != FRAME_UNUSED) return -EBUSY; /* Is this according to the v4l spec??? */ if (se401_set_size(se401, vm.width, vm.height)) return -EINVAL; se401->frame[vm.frame].grabstate=FRAME_READY; if (!se401->streaming) se401_start_stream(se401); /* Set the picture properties */ if (se401->framecount==0) se401_send_pict(se401); /* Calibrate the reset level after a few frames. */ if (se401->framecount%20==1) se401_auto_resetlevel(se401); return 0; } case VIDIOCSYNC: { int frame, ret=0; if (copy_from_user((void *)&frame, arg, sizeof(int))) return -EFAULT; if(frame <0 || frame >= SE401_NUMFRAMES) return -EINVAL; ret=se401_newframe(se401, frame); se401->frame[frame].grabstate=FRAME_UNUSED; return ret; } case VIDIOCGFBUF: { struct video_buffer vb; memset(&vb, 0, sizeof(vb)); vb.base = NULL; /* frame buffer not supported, not used */ if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) return -EFAULT; return 0; } case VIDIOCKEY: return 0; case VIDIOCCAPTURE: return -EINVAL; case VIDIOCSFBUF: return -EINVAL; case VIDIOCGTUNER: case VIDIOCSTUNER: return -EINVAL; case VIDIOCGFREQ: case VIDIOCSFREQ: return -EINVAL; case VIDIOCGAUDIO: case VIDIOCSAUDIO: return -EINVAL; default: return -ENOIOCTLCMD; } /* end switch */ return 0;}static long se401_read(struct video_device *dev, char *buf, unsigned long count, int noblock){ int realcount=count, ret=0; struct usb_se401 *se401 = (struct usb_se401 *)dev; if (se401->dev == NULL) return -EIO; if (realcount > se401->cwidth*se401->cheight*3) realcount=se401->cwidth*se401->cheight*3; /* Shouldn't happen: */ if (se401->frame[0].grabstate==FRAME_GRABBING) return -EBUSY; se401->frame[0].grabstate=FRAME_READY; se401->frame[1].grabstate=FRAME_UNUSED; se401->curframe=0; if (!se401->streaming) se401_start_stream(se401); /* Set the picture properties */ if (se401->framecount==0) se401_send_pict(se401); /* Calibrate the reset level after a few frames. */ if (se401->framecount%20==1) se401_auto_resetlevel(se401); ret=se401_newframe(se401, 0); se401->frame[0].grabstate=FRAME_UNUSED; if (ret) return ret; if (copy_to_user(buf, se401->frame[0].data, realcount)) return -EFAULT; return realcount;}static int se401_mmap(struct video_device *dev, const char *adr, unsigned long size){ struct usb_se401 *se401 = (struct usb_se401 *)dev; unsigned long start = (unsigned long)adr; unsigned long page, pos; down(&se401->lock); if (se401->dev == NULL) { up(&se401->lock); return -EIO; } if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { up(&se401->lock); return -EINVAL; } pos = (unsigned long)se401->fbuf; while (size > 0) { page = kvirt_to_pa(pos); if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { up(&se401->lock); return -EAGAIN; } start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } up(&se401->lock); return 0;}static struct video_device se401_template = { name: "se401 USB camera", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_SE401, open: se401_open, close: se401_close, read: se401_read, write: se401_write, ioctl: se401_ioctl, mmap: se401_mmap, initialize: se401_init_done,};/***************************/static int se401_init(struct usb_se401 *se401){ int i=0, rc; unsigned char cp[0x40]; char temp[200]; /* led on */ se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); /* get camera descriptor */ rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp)); if (cp[1]!=0x41) { err("Wrong descriptor type"); return 1; } sprintf (temp, "ExtraFeatures: %d", cp[3]); se401->sizes=cp[4]+cp[5]*256; se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); for (i=0; i<se401->sizes; i++) { se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256; se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256; } sprintf (temp, "%s Sizes:", temp); for (i=0; i<se401->sizes; i++) { sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]); } info("%s", temp); se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3; rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp)); se401->cwidth=cp[0]+cp[1]*256; rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp)); se401->cheight=cp[0]+cp[1]*256; if (!cp[2] && SE401_FORMAT_BAYER) { err("Bayer format not supported!"); return 1; } /* set output mode (BAYER) */ se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0); rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp)); se401->brightness=cp[0]+cp[1]*256; /* some default values */ se401->resetlevel=0x2d; se401->rgain=0x20; se401->ggain=0x20; se401->bgain=0x20; se401_set_exposure(se401, 20000); se401->palette=VIDEO_PALETTE_RGB24; se401->enhance=1; se401->dropped=0; se401->error=0; se401->framecount=0; se401->readcount=0; /* Start interrupt transfers for snapshot button */ se401->inturb=usb_alloc_urb(0); if (!se401->inturb) { info("Allocation of inturb failed"); return 1; } FILL_INT_URB(se401->inturb, se401->dev, usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT), &se401->button, sizeof(se401->button), se401_button_irq, se401, HZ/10 ); if (usb_submit_urb(se401->inturb)) { info("int urb burned down"); return 1; } /* Flash the led */ se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); return 0;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)static void* se401_probe(struct usb_device *dev, unsigned int ifnum)#elsestatic void* __devinit se401_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)#endif{ struct usb_interface_descriptor *interface; struct usb_se401 *se401; char *camera_name=NULL; /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) return NULL; interface = &dev->actconfig->interface[ifnum].altsetting[0]; /* Is it an se401? */ if (dev->descriptor.idVendor == 0x03e8 && dev->descriptor.idProduct == 0x0004) { camera_name="Endpoints/Aox SE401"; } else if (dev->descriptor.idVendor == 0x0471 && dev->descriptor.idProduct == 0x030b) { camera_name="Philips PCVC665K"; } else if (dev->descriptor.idVendor == 0x047d && dev->descriptor.idProduct == 0x5001) { camera_name="Kensington VideoCAM 67014"; } else if (dev->descriptor.idVendor == 0x047d && dev->descriptor.idProduct == 0x5002) { camera_name="Kensington VideoCAM 6701(5/7)"; } else if (dev->descriptor.idVendor == 0x047d && dev->descriptor.idProduct == 0x5003) { camera_name="Kensington VideoCAM 67016"; } else return NULL; /* Checking vendor/product should be enough, but what the hell */ if (interface->bInterfaceClass != 0x00) return NULL; if (interface->bInterfaceSubClass != 0x00) return NULL; /* We found one */ info("SE401 camera found: %s", camera_name); if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) { err("couldn't kmalloc se401 struct"); return NULL; } memset(se401, 0, sizeof(*se401)); se401->dev = dev; se401->iface = interface->bInterfaceNumber; se401->camera_name = camera_name; info("firmware version: %02x", dev->descriptor.bcdDevice & 255); if (se401_init(se401)) { kfree(se401); return NULL; } memcpy(&se401->vdev, &se401_template, sizeof(se401_template)); memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name)); init_waitqueue_head(&se401->wq); init_MUTEX(&se401->lock); wmb(); if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { kfree(se401); err("video_register_device failed"); return NULL; } info("registered new video device: video%d", se401->vdev.minor); return se401;}static void se401_disconnect(struct usb_device *dev, void *ptr){ struct usb_se401 *se401 = (struct usb_se401 *) ptr; lock_kernel(); /* We don't want people trying to open up the device */ if (!se401->user){ video_unregister_device(&se401->vdev); usb_se401_remove_disconnected(se401); } else { se401->removed = 1; } unlock_kernel();}static inline void usb_se401_remove_disconnected (struct usb_se401 *se401){ int i; se401->dev = NULL; se401->frame[0].grabstate = FRAME_ERROR; se401->frame[1].grabstate = FRAME_ERROR; se401->streaming = 0; wake_up_interruptible(&se401->wq); for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) { se401->urb[i]->next = NULL; usb_unlink_urb(se401->urb[i]); usb_free_urb(se401->urb[i]); se401->urb[i] = NULL; kfree(se401->sbuf[i].data); } for (i=0; i<SE401_NUMSCRATCH; i++) if (se401->scratch[i].data) { kfree(se401->scratch[i].data); } if (se401->inturb) { usb_unlink_urb(se401->inturb); usb_free_urb(se401->inturb); } info("%s disconnected", se401->camera_name);#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) destroy_proc_se401_cam(se401);#endif /* Free the memory */ kfree(se401->width); kfree(se401->height); kfree(se401);}static struct usb_driver se401_driver = { name: "se401",#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0) id_table: device_table,#endif probe: se401_probe, disconnect: se401_disconnect};/**************************************************************************** * * Module routines * ***************************************************************************/static int __init usb_se401_init(void){#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) proc_se401_create();#endif info("SE401 usb camera driver version %s registering", version); if (flickerless) if (flickerless!=50 && flickerless!=60) { info("Invallid flickerless value, use 0, 50 or 60."); return -1; } if (usb_register(&se401_driver) < 0) return -1; return 0;}static void __exit usb_se401_exit(void){ usb_deregister(&se401_driver); info("SE401 driver deregistered");#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) proc_se401_destroy();#endif}module_init(usb_se401_init);module_exit(usb_se401_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -