📄 ov511.c
字号:
p.colour = 0x8000; p.hue = 0x8000; p.brightness = 180 << 8; /* XXX */ p.contrast = 192 << 8; /* XXX */ p.whiteness = 105 << 8; /* XXX */ p.depth = 24; p.palette = VIDEO_PALETTE_RGB24; 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; 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 (vw.height != DEFAULT_HEIGHT) return -EINVAL; if (vw.width != DEFAULT_WIDTH) return -EINVAL; ov511->compress = 0; return 0; } case VIDIOCGWIN: { struct video_window vw; vw.x = 0; vw.y = 0; vw.width = DEFAULT_WIDTH; vw.height = DEFAULT_HEIGHT; vw.chromakey = 0; vw.flags = 30; if (copy_to_user(arg, &vw, sizeof(vw))) return -EFAULT; return 0; } case VIDIOCGMBUF: { struct video_mbuf vm; memset(&vm, 0, sizeof(vm)); vm.size = MAX_FRAME_SIZE * 2; vm.frames = 2; vm.offsets[0] = 0; vm.offsets[1] = MAX_FRAME_SIZE; if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) return -EFAULT; return 0; } case VIDIOCMCAPTURE: { struct video_mmap vm; if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) return -EFAULT;#if 0 PDEBUG("MCAPTURE\n"); PDEBUG("frame: %d, size: %dx%d, format: %d\n", vm.frame, vm.width, vm.height, vm.format);#endif if (vm.format != VIDEO_PALETTE_RGB24) return -EINVAL; if ((vm.frame != 0) && (vm.frame != 1)) return -EINVAL; if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) return -EBUSY; /* Don't compress if the size changed */ if ((ov511->frame[vm.frame].width != vm.width) || (ov511->frame[vm.frame].height != vm.height)) { ov511->compress = 0; ov511_mode_init_regs(ov511, vm.width, vm.height, 0);#if 0 PDEBUG("ov511: Setting frame %d to (%d, %d) : %d\n", vm.frame, vm.width, vm.height, 0);#endif } ov511->frame[vm.frame].width = vm.width; ov511->frame[vm.frame].height = vm.height; /* Mark it as ready */ ov511->frame[vm.frame].grabstate = FRAME_READY; return ov511_new_frame(ov511, vm.frame); } case VIDIOCSYNC: { int frame; if (copy_from_user((void *)&frame, arg, sizeof(int))) return -EFAULT;#if 0 PDEBUG("syncing to frame %d\n", frame);#endif switch (ov511->frame[frame].grabstate) { case FRAME_UNUSED: return -EINVAL; case FRAME_READY: case FRAME_GRABBING: case FRAME_ERROR:redo: do {#if 0 init_waitqueue_head(&ov511->frame[frame].wq);#endif interruptible_sleep_on(&ov511->frame[frame].wq); if (signal_pending(current)) return -EINTR; } while (ov511->frame[frame].grabstate == FRAME_GRABBING); if (ov511->frame[frame].grabstate == FRAME_ERROR) { int ret; if ((ret = ov511_new_frame(ov511, frame)) < 0) return ret; goto redo; } case FRAME_DONE: ov511->frame[frame].grabstate = FRAME_UNUSED; break; } ov511->frame[frame].grabstate = FRAME_UNUSED; return 0; } 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; } return 0;}static long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock){ struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; int frmx = -1; volatile struct ov511_frame *frame; PDEBUG("ov511_read: %ld bytes, noblock=%d\n", count, noblock); if (!dev || !buf) return -EFAULT; /* See if a frame is completed, then use it. */ if (ov511->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ frmx = 0; else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ frmx = 1; if (noblock && (frmx == -1)) return -EAGAIN; /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ /* See if a frame is in process (grabbing), then use it. */ if (frmx == -1) { if (ov511->frame[0].grabstate == FRAME_GRABBING) frmx = 0; else if (ov511->frame[1].grabstate == FRAME_GRABBING) frmx = 1; } /* If no frame is active, start one. */ if (frmx == -1) ov511_new_frame(ov511, frmx = 0); frame = &ov511->frame[frmx];restart: while (frame->grabstate == FRAME_GRABBING) { interruptible_sleep_on(&ov511->frame[frmx].wq); if (signal_pending(current)) return -EINTR; } if (frame->grabstate == FRAME_ERROR) { frame->bytes_read = 0; printk(KERN_ERR "ov511_read: errored frame %d\n", ov511->curframe); if (ov511_new_frame(ov511, frmx)) printk(KERN_ERR "ov511_read: ov511_new_frame error\n"); goto restart; } PDEBUG("ov511_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n", frmx, frame->bytes_read, frame->scanlength); /* copy bytes to user space; we allow for partials reads */ if ((count + frame->bytes_read) > frame->scanlength) count = frame->scanlength - frame->bytes_read; if (copy_to_user(buf, frame->data + frame->bytes_read, count)) return -EFAULT; frame->bytes_read += count; PDEBUG("ov511_read: {copy} count used=%ld, new bytes_read=%ld\n", count, frame->bytes_read); if (frame->bytes_read >= frame->scanlength) { /* All data has been read */ frame->bytes_read = 0; /* Mark it as available to be used again. */ ov511->frame[frmx].grabstate = FRAME_UNUSED; if (ov511_new_frame(ov511, frmx ? 0 : 1)) printk(KERN_ERR "ov511_read: ov511_new_frame returned error\n"); } return count;}static int ov511_mmap(struct video_device *dev, const char *adr, unsigned long size){ struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; unsigned long start = (unsigned long)adr; unsigned long page, pos; PDEBUG("mmap: %ld (%lX) bytes\n", size, size); if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) return -EINVAL; pos = (unsigned long)ov511->fbuf; while (size > 0) { page = kvirt_to_pa(pos); if (remap_page_range(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;}// FIXME - needs V4L ID to be assignedstatic struct video_device ov511_template = { "OV511 USB Camera", VID_TYPE_CAPTURE, VID_HARDWARE_CPIA, /* FIXME */ ov511_open, ov511_close, ov511_read, ov511_write, NULL, ov511_ioctl, ov511_mmap, ov511_init_done, NULL, 0, 0};static int ov7610_configure(struct usb_device *dev){ if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, OV7610_I2C_WRITE_ID) < 0) return -1; if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, OV7610_I2C_READ_ID) < 0) return -1; /* Reset the camera chip */ if (ov511_i2c_reset(dev) < 0) return -1;#if 0 if(usb_ov511_reg_write(dev, OV511_REG_I2C_CLOCK_PRESCALER, OV511_I2C_CLOCK_PRESCALER)) return -1;#endif if (ov511_reset(dev, OV511_RESET_NOREGS) < 0) return -1; /* Dummy read to sync I2C */ if(ov511_i2c_read(dev, 0x00) < 0) return -1; if((ov511_i2c_read(dev, 0x1C) != 0x7F) || (ov511_i2c_read(dev, 0x1D) != 0xA2)) { printk(KERN_ERR "ov511: Failed to read OV7610 ID. You might\n"); printk(KERN_ERR "ov511: not have an OV7610, or it may be\n"); printk(KERN_ERR "ov511: not responding. Report this to\n"); printk(KERN_ERR "ov511: mmcclelland@delphi.com\n"); return -1; } return 0;}static int ov511_configure(struct usb_ov511 *ov511){ struct usb_device *dev = ov511->dev; /* Set altsetting 0 */ if (usb_set_interface(dev, ov511->iface, 0) < 0) { printk(KERN_ERR "ov511: usb_set_interface error\n"); return -EBUSY; } memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template)); init_waitqueue_head(&ov511->frame[0].wq); init_waitqueue_head(&ov511->frame[1].wq); if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) { printk(KERN_ERR "ov511: video_register_device failed\n"); return -EBUSY; } /* Reset in case driver was unloaded and reloaded without unplug */ if (ov511_reset(dev, OV511_RESET_ALL) < 0) goto error; /* Initialize system */ if (ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) { printk(KERN_ERR "ov511: enable system: command failed\n"); goto error; } /* This seems to be necessary */ if (ov511_reset(dev, OV511_RESET_ALL) < 0) goto error; if(ov7610_configure(dev) < 0) { printk(KERN_ERR "ov511: failed to configure OV7610\n"); goto error; } /* Disable compression */ if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) { printk(KERN_ERR "ov511: disable compression: command failed\n"); goto error; } ov511->compress = 0; /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used * (using read() instead). */ ov511->frame[0].width = DEFAULT_WIDTH; ov511->frame[0].height = DEFAULT_HEIGHT; ov511->frame[0].bytes_read = 0; ov511->frame[1].width = DEFAULT_WIDTH; ov511->frame[1].height = DEFAULT_HEIGHT; ov511->frame[1].bytes_read = 0; /* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */ ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0); return 0; error: video_unregister_device(&ov511->vdev); usb_driver_release_interface(&ov511_driver, &dev->actconfig->interface[ov511->iface]); kfree(ov511); return -EBUSY; }static void* ov511_probe(struct usb_device *dev, unsigned int ifnum){ struct usb_interface_descriptor *interface; struct usb_ov511 *ov511; int rc; PDEBUG("probing for device...\n"); /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) return NULL; interface = &dev->actconfig->interface[ifnum].altsetting[0]; /* Is it an OV511? */ if (dev->descriptor.idVendor != 0x05a9) return NULL; if (dev->descriptor.idProduct != 0x0511) return NULL; /* Checking vendor/product should be enough, but what the hell */ if (interface->bInterfaceClass != 0xFF) return NULL; if (interface->bInterfaceSubClass != 0x00) return NULL; /* We found one */ printk(KERN_INFO "ov511: USB OV511-based camera found\n"); if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) { printk(KERN_ERR "ov511: couldn't kmalloc ov511 struct\n"); return NULL; } memset(ov511, 0, sizeof(*ov511)); ov511->dev = dev; ov511->iface = interface->bInterfaceNumber; rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); if (rc < 0) { printk("ov511: Unable to read camera bridge registers\n"); return NULL; } switch(ov511->customid = rc) { case 0: /* This also means that no custom ID was set */ printk("ov511: Camera is probably a MediaForte MV300\n"); break; case 3: printk("ov511: Camera is a D-Link DSB-C300\n"); break; case 21: printk("ov511: Camera is a Creative Labs WebCam 3\n"); break; case 100: printk("ov511: Camera is a Lifeview RoboCam\n"); break; case 102: printk("ov511: Camera is a AverMedia InterCam Elite\n"); break; default: printk("ov511: Specific camera type (%d) not recognized\n", rc); printk("ov511: Please contact mmcclelland@delphi.com to request\n"); printk("ov511: support for your camera.\n"); return NULL; } if (!ov511_configure(ov511)) { ov511->user=0; init_MUTEX(&ov511->lock); /* to 1 == available */ return ov511; } else { printk(KERN_ERR "ov511: Failed to configure camera\n"); return NULL; } return ov511;}static void ov511_disconnect(struct usb_device *dev, void *ptr){ struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr; video_unregister_device(&ov511->vdev); usb_driver_release_interface(&ov511_driver, &ov511->dev->actconfig->interface[ov511->iface]); /* Free the memory */ kfree(ov511); ov511 = NULL;}static struct usb_driver ov511_driver = { "ov511", ov511_probe, ov511_disconnect, { NULL, NULL }};int usb_ov511_init(void){ PDEBUG("usb_ov511_init()\n"); EXPORT_NO_SYMBOLS; return usb_register(&ov511_driver);}void usb_ov511_cleanup(void){ usb_deregister(&ov511_driver);}#ifdef MODULEint init_module(void){ return usb_ov511_init();}void cleanup_module(void){ usb_ov511_cleanup(); PDEBUG("Module unloaded\n");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -