📄 ovfx2.c
字号:
return 0;}static intsensor_set_control(struct usb_ovfx2 *ov, int cid, int val){ struct ovcamchip_control ctl; int rc; if (sensor_needs_stop(ov, cid)) if (ovfx2_pause(ov) < 0) return -EIO; ctl.id = cid; ctl.value = val; rc = sensor_cmd(ov, OVCAMCHIP_CMD_S_CTRL, &ctl); if (ovfx2_resume(ov) < 0) return -EIO; return rc;}static intsensor_get_control(struct usb_ovfx2 *ov, int cid, int *val){ struct ovcamchip_control ctl; int rc; ctl.id = cid; rc = sensor_cmd(ov, OVCAMCHIP_CMD_G_CTRL, &ctl); if (rc >= 0) *val = ctl.value; return rc;}static intsensor_set_picture(struct usb_ovfx2 *ov, struct video_picture *p){ int rc; PDEBUG(4, "sensor_set_picture"); rc = reg_w(ov, REG_CNTR, p->contrast >> 8); if (rc < 0) return rc; rc = reg_w(ov, REG_BRIGHT, (p->brightness >> 8) - 127); if (rc < 0) return rc; rc = reg_w(ov, REG_SAT, p->colour >> 8); if (rc < 0) return rc; rc = reg_w(ov, REG_HUE, (p->hue >> 8) - 127); if (rc < 0) return rc; return 0;}static intsensor_get_picture(struct usb_ovfx2 *ov, struct video_picture *p){ int rc; PDEBUG(4, "sensor_get_picture"); /* Don't return error if a setting is unsupported, or rest of settings * will not be performed */ rc = reg_r(ov, REG_CNTR); if (rc < 0) return rc; p->contrast = rc << 8; rc = reg_r(ov, REG_BRIGHT); if (rc < 0) return rc; p->brightness = (rc + 127) << 8; rc = reg_r(ov, REG_SAT); if (rc < 0) return rc; p->colour = rc << 8; rc = reg_r(ov, REG_HUE); if (rc < 0) return rc; p->hue = (rc + 127) << 8; p->whiteness = 105 << 8; return 0;}/* Matches the sensor's internal frame rate to the lighting frequency. * Valid frequencies are: * 50 - 50Hz, for European and Asian lighting * 60 - 60Hz, for American lighting * * Returns: 0 for success */static intsensor_set_light_freq(struct usb_ovfx2 *ov, int freq){ if (freq != 50 && freq != 60) { err("Invalid light freq (%d Hz)", freq); return -EINVAL; } return sensor_set_control(ov, OVCAMCHIP_CID_FREQ, freq);}/* Returns number of bits per pixel (regardless of where they are located; * planar or not), or zero for unsupported format. */static inline intget_depth(int palette){ switch (palette) { case VIDEO_PALETTE_RGB24: return 24; /* Planar */ default: return 0; /* Invalid format */ }}/* Bytes per frame. Used by read(). Return of 0 indicates error */static inline long intget_frame_length(struct ovfx2_frame *frame){ if (!frame) return 0; else return ((frame->width * frame->height * get_depth(frame->format)) >> 3);}static intset_ov_sensor_window(struct usb_ovfx2 *ov, int width, int height, int mode, int sub_flag){ struct ovcamchip_window win; int rc; win.format = mode; /* Unless subcapture is enabled, center the image window and downsample * if possible to increase the field of view */ if (sub_flag) { win.x = ov->subx; win.y = ov->suby; win.width = ov->subw; win.height = ov->subh; win.quarter = 0; } else { win.x = 0; win.y = 0; win.width = ov->maxwidth; win.height = ov->maxheight; win.quarter = 0; } if (clockdiv >= 0) win.clockdiv = clockdiv; else win.clockdiv = 0x01; /* Always use the max frame rate */ rc = sensor_cmd(ov, OVCAMCHIP_CMD_S_MODE, &win); if (rc < 0) return rc; if (framedrop >= 0) i2c_w(ov, 0x16, framedrop); return 0;}/* Sets up the OVFX2 with the given image parameters */static intovfx2_mode_init_regs(struct usb_ovfx2 *ov, int width, int height, int mode, int sub_flag){ if (sub_flag) { width = ov->subw; height = ov->subh; } PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", width, height, mode, sub_flag); if (width < ov->minwidth || height < ov->minheight) { err("Requested dimensions are too small"); return -EINVAL; } /* Set palette */ /* Set bus width */ /* Set resolution */ /* Set framerate/clock */ reg_w_mask(ov, 0x0f, 0x08, 0x08); /* Reinitialize? */ return 0;}/* This is a wrapper around the FX2 and sensor specific functions */static intmode_init_regs(struct usb_ovfx2 *ov, int width, int height, int mode, int sub_flag){ int rc = 0; rc = ovfx2_mode_init_regs(ov, width, height, mode, sub_flag); if (FATAL_ERROR(rc)) return rc; rc = set_ov_sensor_window(ov, width, height, mode, sub_flag); if (FATAL_ERROR(rc)) return rc; /********* The following settings are specific to this camera ********/ i2c_w(ov, 0x03, 0x80); /* Hardcoded saturation value */ i2c_w_mask(ov, 0x12, 0x48, 0x48); /* Enable h-mirror and raw output */ i2c_w_mask(ov, 0x27, 0x10, 0x10); /* Bypass RGB matrix */ i2c_w_mask(ov, 0x28, 0x04, 0x04); /* G/BR (YG) mode */ i2c_w_mask(ov, 0x2a, 0x00, 0x10); /* No UV 2-pixel delay */ i2c_w_mask(ov, 0x2d, 0x40, 0x40); /* QVGA 60 FPS (redundant?) */ i2c_w(ov, 0x67, 0x00); /* Disable YUV postprocess */ i2c_w_mask(ov, 0x2d, 0x00, 0x0f); /* Disable anti-alias */ i2c_w(ov, 0x24, 0x20); /* Use QVGA white pixel ratio */ i2c_w(ov, 0x25, 0x30); /* Use QVGA black pixel ratio */ i2c_w(ov, 0x60, 0x26); /* Unknown */ i2c_w(ov, 0x74, 0x20); /* AGC max gain = 4x */ i2c_w(ov, 0x06, 0x68); /* Hardcoded brightness value */ i2c_w(ov, 0x14, 0x04); /* */ return 0;}/* Set up the camera chip with the options provided by the module params */static intcamchip_init_settings(struct usb_ovfx2 *ov){ int rc; rc = sensor_set_control(ov, OVCAMCHIP_CID_AUTOBRIGHT, autobright); if (FATAL_ERROR(rc)) return rc; rc = sensor_set_control(ov, OVCAMCHIP_CID_AUTOEXP, autoexp); if (FATAL_ERROR(rc)) return rc; rc = sensor_set_control(ov, OVCAMCHIP_CID_BANDFILT, bandingfilter); if (FATAL_ERROR(rc)) return rc; if (lightfreq) { rc = sensor_set_light_freq(ov, lightfreq); if (FATAL_ERROR(rc)) return rc; } rc = sensor_set_control(ov, OVCAMCHIP_CID_BACKLIGHT, backlight); if (FATAL_ERROR(rc)) return rc; rc = sensor_set_control(ov, OVCAMCHIP_CID_MIRROR, mirror); if (FATAL_ERROR(rc)) return rc; return 0;}/* This sets the default image parameters. This is useful for apps that use * read() and do not set these. */static intovfx2_set_default_params(struct usb_ovfx2 *ov){ int i; /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used * (using read() instead). */ for (i = 0; i < OVFX2_NUMFRAMES; i++) { ov->frame[i].width = ov->maxwidth; ov->frame[i].height = ov->maxheight; if (force_palette) ov->frame[i].format = force_palette; else ov->frame[i].format = VIDEO_PALETTE_RGB24; ov->frame[i].depth = get_depth(ov->frame[i].format); } PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight, symbolic(v4l1_plist, ov->frame[0].format)); /* Initialize to max width/height, default palette */ if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, ov->frame[0].format, 0) < 0) return -EINVAL; return 0;}#if defined(HAVE_V4L2)static int ovfx2_control_op(struct usb_ovfx2 *ov, unsigned int cmd, void *arg){ /* No controls defined yet */ return -EINVAL;}#endif/********************************************************************** * * Frame buffering * **********************************************************************//* Sleeps until no frames are active. Returns !0 if got signal or unplugged */static intov51x_wait_frames_inactive(struct usb_ovfx2 *ov){ int rc; rc = wait_event_interruptible(ov->wq, ov->curframe < 0 || !ov->present); if (rc) return rc; if (ov->present) return 0; else return -ENODEV;}/********************************************************************** * * Raw data parsing * **********************************************************************/static voidgbgr_to_bgr24(struct ovfx2_frame *frame, unsigned char *pIn, unsigned char *pOut){ const unsigned int a = frame->rawwidth * frame->rawheight / 2; int i; for (i = 0; i < a; i++) { pOut[0] = pIn[1]; pOut[1] = pIn[0]; pOut[2] = pIn[3]; pOut[3] = pIn[1]; pOut[4] = pIn[2]; pOut[5] = pIn[3]; pIn += 4; pOut += 6; }}/* Flip image vertically */static voidvert_mirror(unsigned char *pIn, unsigned char *pOut, unsigned int width, unsigned int height, unsigned int depth){ const unsigned int linesize = width * depth; int i; pOut += height * linesize; for (i = 0; i < height; i++) { pOut -= linesize; memcpy(pOut, pIn, linesize); pIn += linesize; }}/********************************************************************** * * Image processing * **********************************************************************/static voidovfx2_postprocess(struct usb_ovfx2 *ov, struct ovfx2_frame *frame){ if (dumppix == 1) { /* Dump with color decoding */ memset(frame->data, 0, MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); gbgr_to_bgr24(frame, frame->rawdata, frame->data); } else if (dumppix == 2) { /* Dump raw data */ memset(frame->data, 0, MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); memcpy(frame->data, frame->rawdata, frame->bytes_recvd); } else {// /* FIXME: Remove this once decoding is stable */// memset(frame->data, 0,// MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));// memset(frame->tempdata, 0,// MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)); vert_mirror(frame->rawdata, frame->tempdata, frame->rawwidth, frame->rawheight, 2); gbgr_to_bgr24(frame, frame->tempdata, frame->data); }}/********************************************************************** * * OV51x data transfer, IRQ handler * **********************************************************************/static inline voidovfx2_move_data(struct usb_ovfx2 *ov, unsigned char *in, int n){ int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); struct ovfx2_frame *frame = &ov->frame[ov->curframe]; struct timeval *ts;// info("bytes_recvd = %d; n = %d", frame->bytes_recvd, n); if (frame->scanstate == STATE_LOCKED) { PDEBUG(4, "Starting capture on frame %d", frame->framenum); frame->scanstate = STATE_RECEIVING; frame->bytes_recvd = 0; } if (n) { int b = n; /* Number of image data bytes */#if 1 /* The first 2560 bytes of data (first 2 lines?) are invalid */ if (frame->bytes_recvd == 0) { in += 2560; b -= 2560; }#endif frame->bytes_recvd += b; if (frame->bytes_recvd <= max_raw) memcpy(frame->rawdata + frame->bytes_recvd - b, in, b); else PDEBUG(5, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - max_raw); } else { PDEBUG(5, "Empty bulk packet"); } /* Short packets indicate EOF */ if (n < OVFX2_BULK_SIZE) { int nextf; PDEBUG(4, "Frame end, curframe = %d, recvd=%d", ov->curframe, frame->bytes_recvd);#if 1 if (frame->bytes_recvd < max_raw) { PDEBUG(3, "Frame was short; discarding"); frame->bytes_recvd = 0; frame->grabstate = FRAME_ERROR; wake_up_interruptible(&frame->wq); return; }#endif /* Don't allow byte count to exceed buffer size */ RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); do_gettimeofday(ts); // FIXME: Since we don't know the header formats yet, // there is no way to know what the actual image size is frame->rawwidth = frame->width; frame->rawheight = frame->height; /* Don't wake up user for same frame more than once */ if (frame->grabstate != FRAME_DONE) { frame->grabstate = FRAME_DONE; wake_up_interruptible(&frame->wq); } /* If next frame is ready or grabbing, point to it */ nextf = (ov->curframe + 1) % OVFX2_NUMFRAMES; if (ov->frame[nextf].grabstate == FRAME_READY || ov->frame[nextf].grabstate == FRAME_GRABBING) { ov->curframe = nextf; ov->frame[nextf].bytes_recvd = 0; ov->frame[nextf].scanstate = STATE_LOCKED; } else { if (ov->frame[nextf].grabstate == FRAME_DONE) { PDEBUG(4, "No empty frames left"); } else { PDEBUG(4, "Frame not ready? state = %d", ov->frame[nextf].grabstate); } ov->curframe = -1; } }}static void#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 51)ovfx2_bulk_irq(struct urb *urb, struct pt_regs *regs)#elseovfx2_bulk_irq(struct urb *urb)#endif{ int i; int actlen = urb->actual_length; struct usb_ovfx2 *ov; struct ovfx2_sbuf *sbuf; if (!urb->context) { PDEBUG(4, "no context"); return; } sbuf = urb->context; ov = sbuf->ov; if (!ov || !ov->dev || !ov->user) { PDEBUG(4, "no device, or not open"); return; } if (!ov->streaming) { PDEBUG(4, "hmmm... not streaming, but got interrupt"); return; } if (urb->status == -ENOENT || urb->status == -ECONNRESET) { PDEBUG(4, "URB unlinked"); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -