📄 ov511.c
字号:
frame->width &= ~7L; /* Multiple of 8 */ if (frame->height > ov511->maxheight) frame->height = ov511->maxheight; frame->height &= ~3L; /* Multiple of 4 */ return 0;}/**************************************************************************** * * Buffer management * ***************************************************************************/static int ov511_alloc(struct usb_ov511 *ov511){ int i; PDEBUG(4, "entered"); down(&ov511->buf_lock); if (ov511->buf_state == BUF_PEND_DEALLOC) { ov511->buf_state = BUF_ALLOCATED; del_timer(&ov511->buf_timer); } if (ov511->buf_state == BUF_ALLOCATED) goto out; ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE); if (!ov511->fbuf) goto error; for (i = 0; i < OV511_NUMFRAMES; i++) { ov511->frame[i].grabstate = FRAME_UNUSED; ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE; PDEBUG(4, "frame[%d] @ %p", i, ov511->frame[i].data); ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); if (!ov511->sbuf[i].data) { while (--i) { kfree(ov511->sbuf[i].data); ov511->sbuf[i].data = NULL; } rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE); ov511->fbuf = NULL; goto error; } PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data); } ov511->buf_state = BUF_ALLOCATED;out: up(&ov511->buf_lock); PDEBUG(4, "leaving"); return 0;error: ov511->buf_state = BUF_NOT_ALLOCATED; up(&ov511->buf_lock); PDEBUG(4, "errored"); return -ENOMEM;}/* * - You must acquire buf_lock before entering this function. * - Because this code will free any non-null pointer, you must be sure to null * them if you explicitly free them somewhere else! */static void ov511_do_dealloc(struct usb_ov511 *ov511){ int i; PDEBUG(4, "entered"); if (ov511->fbuf) { rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE); ov511->fbuf = NULL; } for (i = 0; i < OV511_NUMFRAMES; i++) { if (ov511->sbuf[i].data) { kfree(ov511->sbuf[i].data); ov511->sbuf[i].data = NULL; } } PDEBUG(4, "buffer memory deallocated"); ov511->buf_state = BUF_NOT_ALLOCATED; PDEBUG(4, "leaving");}static void ov511_buf_callback(unsigned long data){ struct usb_ov511 *ov511 = (struct usb_ov511 *)data; PDEBUG(4, "entered"); down(&ov511->buf_lock); if (ov511->buf_state == BUF_PEND_DEALLOC) ov511_do_dealloc(ov511); up(&ov511->buf_lock); PDEBUG(4, "leaving");}static void ov511_dealloc(struct usb_ov511 *ov511, int now){ struct timer_list *bt = &(ov511->buf_timer); PDEBUG(4, "entered"); down(&ov511->buf_lock); PDEBUG(4, "deallocating buffer memory %s", now ? "now" : "later"); if (ov511->buf_state == BUF_PEND_DEALLOC) { ov511->buf_state = BUF_ALLOCATED; del_timer(bt); } if (now) ov511_do_dealloc(ov511); else { ov511->buf_state = BUF_PEND_DEALLOC; init_timer(bt); bt->function = ov511_buf_callback; bt->data = (unsigned long)ov511; bt->expires = jiffies + buf_timeout * HZ; add_timer(bt); } up(&ov511->buf_lock); PDEBUG(4, "leaving");}/**************************************************************************** * * V4L API * ***************************************************************************/static int ov511_open(struct video_device *dev, int flags){ struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; int err; MOD_INC_USE_COUNT; PDEBUG(4, "opening"); down(&ov511->lock); err = -EBUSY; if (ov511->user) goto out; err = -ENOMEM; if (ov511_alloc(ov511)) goto out; ov511->sub_flag = 0; err = ov511_init_isoc(ov511); if (err) { ov511_dealloc(ov511, 0); goto out; } ov511->user++;out: up(&ov511->lock); if (err) MOD_DEC_USE_COUNT; return err;}static void ov511_close(struct video_device *dev){ struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; PDEBUG(4, "ov511_close"); down(&ov511->lock); ov511->user--; ov511_stop_isoc(ov511); if (ov511->dev) ov511_dealloc(ov511, 0); up(&ov511->lock); if (!ov511->dev) { ov511_dealloc(ov511, 1); video_unregister_device(&ov511->vdev); kfree(ov511); ov511 = NULL; } MOD_DEC_USE_COUNT;}static int ov511_init_done(struct video_device *dev){#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) create_proc_ov511_cam((struct usb_ov511 *)dev);#endif return 0;}static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock){ return -EINVAL;}static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg){ struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev; PDEBUG(4, "IOCtl: 0x%X", cmd); if (!ov511->dev) return -EIO; switch (cmd) { case VIDIOCGCAP: { struct video_capability b; PDEBUG (4, "VIDIOCGCAP"); strcpy(b.name, "OV511 USB Camera"); b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; b.channels = 1; b.audios = 0; b.maxwidth = ov511->maxwidth; b.maxheight = ov511->maxheight; b.minwidth = 160; b.minheight = 120; 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; PDEBUG (4, "VIDIOCGPICT"); if (ov7610_get_picture(ov511, &p)) return -EIO; if (copy_to_user(arg, &p, sizeof(p))) return -EFAULT; return 0; } case VIDIOCSPICT: { struct video_picture p; int i; PDEBUG (4, "VIDIOCSPICT"); if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; if (!ov511_get_depth(p.palette)) return -EINVAL; if (ov7610_set_picture(ov511, &p)) return -EIO; PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette); for (i = 0; i < OV511_NUMFRAMES; i++) { ov511->frame[i].depth = p.depth; ov511->frame[i].format = p.palette; ov511->frame[i].segsize = GET_SEGSIZE(p.palette); } return 0; } case VIDIOCGCAPTURE: { int vf; PDEBUG (4, "VIDIOCGCAPTURE"); if (copy_from_user(&vf, arg, sizeof(vf))) return -EFAULT; ov511->sub_flag = vf; return 0; } case VIDIOCSCAPTURE: { struct video_capture vc; if (copy_from_user(&vc, arg, sizeof(vc))) return -EFAULT; if (vc.flags) return -EINVAL; if (vc.decimation) return -EINVAL; vc.x &= ~3L; vc.y &= ~1L; vc.y &= ~31L; if (vc.width == 0) vc.width = 32; vc.height /= 16; vc.height *= 16; if (vc.height == 0) vc.height = 16; ov511->subx = vc.x; ov511->suby = vc.y; ov511->subw = vc.width; ov511->subh = vc.height; return 0; } case VIDIOCSWIN: { struct video_window vw; int i, result; if (copy_from_user(&vw, arg, sizeof(vw))) return -EFAULT; PDEBUG (4, "VIDIOCSWIN: width=%d, height=%d", vw.width, vw.height);#if 0 if (vw.flags) return -EINVAL; if (vw.clipcount) return -EINVAL; if (vw.height != ov511->maxheight) return -EINVAL; if (vw.width != ov511->maxwidth) return -EINVAL;#endif /* If we're collecting previous frame wait before changing modes */ interruptible_sleep_on(&ov511->wq); if (signal_pending(current)) return -EINTR; result = ov511_mode_init_regs(ov511, vw.width, vw.height, ov511->frame[0].format, ov511->sub_flag); if (result < 0) return result; for (i = 0; i < OV511_NUMFRAMES; i++) { ov511->frame[i].width = vw.width; ov511->frame[i].height = vw.height; } return 0; } case VIDIOCGWIN: { struct video_window vw; vw.x = 0; /* FIXME */ vw.y = 0; vw.width = ov511->frame[0].width; vw.height = ov511->frame[0].height; vw.chromakey = 0; vw.flags = 30; PDEBUG (4, "VIDIOCGWIN: %dx%d", vw.width, vw.height); 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 = OV511_NUMFRAMES * MAX_DATA_SIZE; vm.frames = OV511_NUMFRAMES; vm.offsets[0] = 0; vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval); if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) return -EFAULT; return 0; } case VIDIOCMCAPTURE: { struct video_mmap vm; int ret, depth; if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) return -EFAULT; PDEBUG(4, "CMCAPTURE"); PDEBUG(4, "frame: %d, size: %dx%d, format: %d", vm.frame, vm.width, vm.height, vm.format); depth = ov511_get_depth(vm.format); if (!depth) { err("VIDIOCMCAPTURE: invalid format (%d)", vm.format); return -EINVAL; } if ((vm.frame != 0) && (vm.frame != 1)) { err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame); return -EINVAL; } if (vm.width > ov511->maxwidth || vm.height > ov511->maxheight) { err("VIDIOCMCAPTURE: requested dimensions too big"); 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->frame[vm.frame].format != vm.format) || (ov511->frame[vm.frame].sub_flag != ov511->sub_flag)) { /* If we're collecting previous frame wait before changing modes */ interruptible_sleep_on(&ov511->wq); if (signal_pending(current)) return -EINTR; ret = ov511_mode_init_regs(ov511, vm.width, vm.height, vm.format, ov511->sub_flag);#if 0 if (ret < 0) return ret;#endif } ov511->frame[vm.frame].width = vm.width; ov511->frame[vm.frame].height = vm.height; ov511->frame[vm.frame].format = vm.format; ov511->frame[vm.frame].sub_flag = ov511->sub_flag; ov511->frame[vm.frame].segsize = GET_SEGSIZE(vm.format); ov511->frame[vm.frame].depth = depth; /* 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; PDEBUG(4, "syncing to frame %d, grabstate = %d", frame, ov511->frame[frame].grabstate); switch (ov511->frame[frame].grabstate) { case FRAME_UNUSED: return -EINVAL; case FRAME_READY: case FRAME_GRA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -