📄 se401.c
字号:
b->minwidth = se401->width[0]; b->minheight = se401->height[0]; return 0; } case VIDIOCGCHAN: { struct video_channel *v = arg; if (v->channel != 0) return -EINVAL; v->flags = 0; v->tuners = 0; v->type = VIDEO_TYPE_CAMERA; strcpy(v->name, "Camera"); return 0; } case VIDIOCSCHAN: { struct video_channel *v = arg; if (v->channel != 0) return -EINVAL; return 0; } case VIDIOCGPICT: { struct video_picture *p = arg; se401_get_pict(se401, p); return 0; } case VIDIOCSPICT: { struct video_picture *p = arg; if (se401_set_pict(se401, p)) return -EINVAL; return 0; } case VIDIOCSWIN: { struct video_window *vw = arg; 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 = arg; vw->x = 0; /* FIXME */ vw->y = 0; vw->chromakey = 0; vw->flags = 0; vw->clipcount = 0; vw->width = se401->cwidth; vw->height = se401->cheight; return 0; } case VIDIOCGMBUF: { struct video_mbuf *vm = arg; 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; return 0; } case VIDIOCMCAPTURE: { struct video_mmap *vm = arg; 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 = arg; int ret=0; 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 = arg; memset(vb, 0, sizeof(*vb)); 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 int se401_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, se401_do_ioctl);}static ssize_t se401_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ int realcount=count, ret=0; struct video_device *dev = file->private_data; 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 file *file, struct vm_area_struct *vma){ struct video_device *dev = file->private_data; struct usb_se401 *se401 = (struct usb_se401 *)dev; unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; 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 = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, 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 file_operations se401_fops = { .owner = THIS_MODULE, .open = se401_open, .release = se401_close, .read = se401_read, .mmap = se401_mmap, .ioctl = se401_ioctl, .llseek = no_llseek,};static struct video_device se401_template = { .owner = THIS_MODULE, .name = "se401 USB camera", .type = VID_TYPE_CAPTURE, .hardware = VID_HARDWARE_SE401, .fops = &se401_fops,};/***************************/static int se401_init(struct usb_se401 *se401, int button){ 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); if (!se401->width) return 1; se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); if (!se401->height) { kfree(se401->width); return 1; } 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 */ if (button) { se401->inturb=usb_alloc_urb(0, GFP_KERNEL); if (!se401->inturb) { info("Allocation of inturb failed"); return 1; } usb_fill_int_urb(se401->inturb, se401->dev, usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT), &se401->button, sizeof(se401->button), se401_button_irq, se401, 8 ); if (usb_submit_urb(se401->inturb, GFP_KERNEL)) { info("int urb burned down"); return 1; } } else se401->inturb=NULL; /* 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;}static int se401_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *dev = interface_to_usbdev(intf); struct usb_interface_descriptor *interface; struct usb_se401 *se401; char *camera_name=NULL; int button=1; /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) return -ENODEV; interface = &intf->cur_altsetting->desc; /* Is it an se401? */ if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 && le16_to_cpu(dev->descriptor.idProduct) == 0x0004) { camera_name="Endpoints/Aox SE401"; } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 && le16_to_cpu(dev->descriptor.idProduct) == 0x030b) { camera_name="Philips PCVC665K"; } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && le16_to_cpu(dev->descriptor.idProduct) == 0x5001) { camera_name="Kensington VideoCAM 67014"; } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && le16_to_cpu(dev->descriptor.idProduct) == 0x5002) { camera_name="Kensington VideoCAM 6701(5/7)"; } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && le16_to_cpu(dev->descriptor.idProduct) == 0x5003) { camera_name="Kensington VideoCAM 67016"; button=0; } else return -ENODEV; /* Checking vendor/product should be enough, but what the hell */ if (interface->bInterfaceClass != 0x00) return -ENODEV; if (interface->bInterfaceSubClass != 0x00) return -ENODEV; /* 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 -ENOMEM; } memset(se401, 0, sizeof(*se401)); se401->dev = dev; se401->iface = interface->bInterfaceNumber; se401->camera_name = camera_name; info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255); if (se401_init(se401, button)) { kfree(se401); return -EIO; } 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 -EIO; } info("registered new video device: video%d", se401->vdev.minor); usb_set_intfdata (intf, se401); return 0;}static void se401_disconnect(struct usb_interface *intf){ struct usb_se401 *se401 = usb_get_intfdata (intf); usb_set_intfdata (intf, NULL); if (se401) { video_unregister_device(&se401->vdev); if (!se401->user){ usb_se401_remove_disconnected(se401); } else { se401->frame[0].grabstate = FRAME_ERROR; se401->frame[0].grabstate = FRAME_ERROR; se401->streaming = 0; wake_up_interruptible(&se401->wq); se401->removed = 1; } }}static struct usb_driver se401_driver = { .owner = THIS_MODULE, .name = "se401", .id_table = device_table, .probe = se401_probe, .disconnect = se401_disconnect,};/**************************************************************************** * * Module routines * ***************************************************************************/static int __init usb_se401_init(void){ 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; } return usb_register(&se401_driver);}static void __exit usb_se401_exit(void){ usb_deregister(&se401_driver); info("SE401 driver deregistered");}module_init(usb_se401_init);module_exit(usb_se401_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -