📄 ovfx2.c
字号:
if (urb->status != -EINPROGRESS && urb->status != 0) { err("ERROR: urb->status=%d: %s", urb->status, symbolic(urb_errlist, urb->status)); } PDEBUG(5, "sbuf[%d]: Got bulk completion: actlen=%d", sbuf->n, actlen); /* Warning: Don't copy data if no frame active! */ if (ov->curframe >= 0) { ovfx2_move_data(ov, urb->transfer_buffer, actlen); } else if (waitqueue_active(&ov->wq)) { wake_up_interruptible(&ov->wq); } /* Resubmit this URB */ urb->status = 0; // FIXME: Is this necessary? What about w/ OV511/OV518? urb->dev = ov->dev;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 4) if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)#else if ((i = usb_submit_urb(urb)) != 0)#endif err("usb_submit_urb() ret %d", i); return;}/**************************************************************************** * * Stream initialization and termination * ***************************************************************************/static intovfx2_start_stream(struct usb_ovfx2 *ov){ struct urb *urb; int err, n, size; PDEBUG(3, "*** Starting video stream ***"); /* Start stream */ err = reg_w_mask(ov, 0x0f, 0x02, 0x02); if (err) return err; ov->curframe = -1; size = OVFX2_BULK_SIZE; for (n = 0; n < OVFX2_NUMSBUF; n++) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) urb = usb_alloc_urb(0, GFP_KERNEL);#else urb = usb_alloc_urb(0);#endif if (!urb) { err("start stream: usb_alloc_urb ret. NULL"); return -ENOMEM; } usb_fill_bulk_urb(urb, ov->dev, usb_rcvbulkpipe(ov->dev, OVFX2_BULK_ENDPOINT_ADDR), ov->sbuf[n].data, size, ovfx2_bulk_irq, &ov->sbuf[n]); ov->sbuf[n].urb = urb; } ov->streaming = 1; for (n = 0; n < OVFX2_NUMSBUF; n++) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 4) err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL);#else err = usb_submit_urb(ov->sbuf[n].urb);#endif if (err) { err("start stream: usb_submit_urb(%d) ret %d", n, err); return err; } } return 0;}static voidovfx2_unlink_bulk(struct usb_ovfx2 *ov){ int n; /* Unschedule all of the bulk td's */ for (n = OVFX2_NUMSBUF - 1; n >= 0; n--) { if (ov->sbuf[n].urb) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) usb_kill_urb(ov->sbuf[n].urb);#else usb_unlink_urb(ov->sbuf[n].urb);#endif usb_free_urb(ov->sbuf[n].urb); ov->sbuf[n].urb = NULL; } }}static intovfx2_stop_stream(struct usb_ovfx2 *ov){ if (!ov->streaming) return -ENODEV; PDEBUG(3, "*** Stopping capture ***"); ov->streaming = 0; ovfx2_unlink_bulk(ov); /* Stop stream */ return reg_w_mask(ov, 0x0f, 0x00, 0x02);}static intovfx2_new_frame(struct usb_ovfx2 *ov, int framenum){ struct ovfx2_frame *frame; int newnum; PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); /* If we're not grabbing a frame right now and the other frame is */ /* ready to be grabbed into, then use it instead */ if (ov->curframe == -1) { newnum = (framenum - 1 + OVFX2_NUMFRAMES) % OVFX2_NUMFRAMES; if (ov->frame[newnum].grabstate == FRAME_READY) framenum = newnum; } else if (ov->frame[framenum].grabstate == FRAME_ERROR) { PDEBUG(4, "restoring broken frame #%d", framenum); } else return 0; frame = &ov->frame[framenum]; PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, frame->width, frame->height); frame->bytes_read = 0; frame->bytes_recvd = 0; frame->grabstate = FRAME_GRABBING; frame->scanstate = STATE_SCANNING; ov->curframe = framenum; /* Make sure it's not too big */ if (frame->width > ov->maxwidth) frame->width = ov->maxwidth; frame->width &= ~7L; /* Multiple of 8 */ if (frame->height > ov->maxheight) frame->height = ov->maxheight; frame->height &= ~3L; /* Multiple of 4 */ return 0;}/**************************************************************************** * * Buffer management * ***************************************************************************//* * - 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 voidovfx2_do_dealloc(struct usb_ovfx2 *ov){ int i; PDEBUG(4, "entered"); rvfree(ov->fbuf, OVFX2_NUMFRAMES * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); ov->fbuf = NULL; vfree(ov->rawfbuf); ov->rawfbuf = NULL; vfree(ov->tempfbuf); ov->tempfbuf = NULL; for (i = 0; i < OVFX2_NUMSBUF; i++) { kfree(ov->sbuf[i].data); ov->sbuf[i].data = NULL; } for (i = 0; i < OVFX2_NUMFRAMES; i++) { ov->frame[i].data = NULL; ov->frame[i].rawdata = NULL; ov->frame[i].tempdata = NULL; } PDEBUG(4, "buffer memory deallocated"); ov->buf_state = BUF_NOT_ALLOCATED; PDEBUG(4, "leaving");}static intovfx2_alloc(struct usb_ovfx2 *ov){ int i; const int w = ov->maxwidth; const int h = ov->maxheight; const int data_bufsize = OVFX2_NUMFRAMES * MAX_DATA_SIZE(w, h); const int raw_bufsize = OVFX2_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); PDEBUG(4, "entered"); down(&ov->buf_lock); if (ov->buf_state == BUF_ALLOCATED) goto out; ov->fbuf = rvmalloc(data_bufsize); if (!ov->fbuf) goto error; ov->rawfbuf = vmalloc(raw_bufsize); if (!ov->rawfbuf) goto error; memset(ov->rawfbuf, 0, raw_bufsize); ov->tempfbuf = vmalloc(raw_bufsize); if (!ov->tempfbuf) goto error; memset(ov->tempfbuf, 0, raw_bufsize); for (i = 0; i < OVFX2_NUMSBUF; i++) { ov->sbuf[i].data = kmalloc(OVFX2_BULK_SIZE, GFP_KERNEL); if (!ov->sbuf[i].data) goto error; PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); } for (i = 0; i < OVFX2_NUMFRAMES; i++) { ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); ov->frame[i].rawdata = ov->rawfbuf + i * MAX_RAW_DATA_SIZE(w, h); ov->frame[i].tempdata = ov->tempfbuf + i * MAX_RAW_DATA_SIZE(w, h); PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); } ov->buf_state = BUF_ALLOCATED;out: up(&ov->buf_lock); PDEBUG(4, "leaving"); return 0;error: ovfx2_do_dealloc(ov); up(&ov->buf_lock); PDEBUG(4, "errored"); return -ENOMEM;}static voidovfx2_dealloc(struct usb_ovfx2 *ov){ PDEBUG(4, "entered"); down(&ov->buf_lock); ovfx2_do_dealloc(ov); up(&ov->buf_lock); PDEBUG(4, "leaving");}/**************************************************************************** * * V4L API * ***************************************************************************/#if defined(HAVE_V4L2)//static const struct v4l2_fmtdesc ovfx2_fmt_grey = {// .description = "8 bpp, gray",// .pixelformat = V4L2_PIX_FMT_GREY,//};static const struct v4l2_fmtdesc ovfx2_fmt_bgr24 = { .description = "24 bpp, BGR, packed", .pixelformat = V4L2_PIX_FMT_BGR24,};#endifstatic intovfx2_open(struct inode *inode, struct file *file){ struct video_device *vdev = video_devdata(file); struct usb_ovfx2 *ov = video_get_drvdata(vdev); int err, i; PDEBUG(4, "opening"); down(&ov->lock); err = -ENODEV; if (!ov->dev) goto out; if (ov->sensor == CC_UNKNOWN) { err("No sensor is detected yet"); goto out; } err = -EBUSY; if (ov->user) goto out; ov->sub_flag = 0; /* In case app doesn't set them... */ err = ovfx2_set_default_params(ov); if (err < 0) goto out; /* Make sure frames are reset */ for (i = 0; i < OVFX2_NUMFRAMES; i++) ov->frame[i].grabstate = FRAME_UNUSED; err = ovfx2_alloc(ov); if (err < 0) goto out; err = ovfx2_start_stream(ov); if (err) { ovfx2_dealloc(ov); goto out; } ov->user++; file->private_data = vdev;out: up(&ov->lock); return err;}static intovfx2_release(struct inode *inode, struct file *file){ struct video_device *vdev = file->private_data; struct usb_ovfx2 *ov = video_get_drvdata(vdev); PDEBUG(4, "close"); down(&ov->lock); ov->user--; ovfx2_stop_stream(ov); ovfx2_dealloc(ov); up(&ov->lock); /* Device unplugged while open. Only a minimum of unregistration is done * here; the disconnect callback already did the rest. */ down(&ov_free_lock); if (!ov->dev) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) if (ov->vdev) video_device_release(ov->vdev);#endif kfree(ov); ov = NULL; } up(&ov_free_lock); file->private_data = NULL; return 0;}/* Do not call this function directly! */static intovfx2_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct video_device *vdev = file->private_data; struct usb_ovfx2 *ov = video_get_drvdata(vdev);#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) switch (_IOC_TYPE(cmd)) { case 'v': PDEBUG(4, "ioctl 0x%x (v4l1, VIDIOC%s)", cmd, (_IOC_NR(cmd) < NUM_V4L1_IOCTLS) ? v4l1_ioctls[_IOC_NR(cmd)] : "???"); break;# if defined(HAVE_V4L2) case 'V': PDEBUG(4, "ioctl 0x%x (v4l2, %s)", cmd, v4l2_ioctl_names[_IOC_NR(cmd)]); break;# endif default: PDEBUG(4, "ioctl 0x%x (?)", cmd); }#else if (debug >= 4) v4l_print_ioctl("ovfx2", cmd);#endif if (!ov->dev) return -EIO; switch (cmd) { case VIDIOCGCAP: { struct video_capability *b = arg; memset(b, 0, sizeof(struct video_capability)); sprintf(b->name, "OVFX2 USB Camera"); b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; b->channels = 1; b->maxwidth = ov->maxwidth; b->maxheight = ov->maxheight; b->minwidth = ov->minwidth; b->minheight = ov->minheight; return 0; } case VIDIOCGCHAN: { struct video_channel *v = arg; if ((unsigned)(v->channel) > 0) return -EINVAL; v->norm = 0; v->type = VIDEO_TYPE_CAMERA; v->flags = 0; v->tuners = 0; sprintf(v->name, "%s", "Camera"); return 0; } case VIDIOCSCHAN: { struct video_channel *v = arg; return (v->channel == 0) ? 0 : -EINVAL; } case VIDIOCGPICT: { struct video_picture *p = arg; memset(p, 0, sizeof(struct video_picture)); if (sensor_get_picture(ov, p)) return -EIO; /* Can we get these from frame[0]? -claudio? */ p->depth = ov->frame[0].depth; p->palette = ov->frame[0].format; return 0; } case VIDIOCSPICT: { struct video_picture *p = arg; int i, rc; if (!get_depth(p->palette)) return -EINVAL; if (sensor_set_picture(ov, p)) return -EIO; if (force_palette && p->palette != force_palette) { info("SPICT: Palette rejected (%s)", symbolic(v4l1_plist, p->palette)); return -EINVAL; } // FIXME: Format should be independent of frames if (p->palette != ov->frame[0].format) { PDEBUG(4, "SPICT: Detected format change"); rc = ov51x_wait_frames_inactive(ov); if (rc) return rc; mode_init_regs(ov, ov->frame[0].width, ov->frame[0].height, p->palette, ov->sub_flag); } PDEBUG(4, "SPICT: Setting depth=%d, palette=%s", p->depth, symbolic(v4l1_plist, p->palette)); for (i = 0; i < OVFX2_NUMFRAMES; i++) { ov->frame[i].depth = p->depth; ov->frame[i].format = p->palette; } return 0; } case VIDIOCGCAPTURE: { int *vf = arg; ov->sub_flag = *vf; return 0; } case VIDIOCSCAPTURE: { struct video_capture *vc = arg; if (vc->flags || 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; ov->subx = vc->x; ov->suby = vc->y; ov->subw = vc->width; ov->subh = vc->height; return 0; } case VIDIOCSWIN: { struct video_window *vw = arg; int i, rc; PDEBUG(4, "Set window: %dx%d", vw->width, vw->height);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -