📄 camera_ov6x30.c
字号:
}; if (qm->id == V4L2_CID_EXPOSURE) { if (qm->index < 0 || qm->index >= sizeof(expo_menu)/sizeof(char *)) return -EINVAL; memcpy(qm->name, expo_menu[qm->index], sizeof(qm->name)); return 0; }#else // No menu controls have been defined return -EINVAL;#endif}static intov6x30_query_control(struct v4l2_queryctrl *qc){ int i; i = find_vctrl(qc->id); if (i == -EINVAL) { qc->flags = V4L2_CTRL_FLAG_DISABLED; return 0; } if (i < 0) return -EINVAL; /* V4L2 filled in category and group, preserve them */ control[i].qc.category = qc->category; memcpy(control[i].qc.group, qc->group, sizeof(qc->group)); *qc = control[i].qc; return 0;}static int ov6x30_write_control(struct vcontrol * lvc, u8 value){ struct camera_serial_bus * sbus = this->camif->sbus; u8 oldval, newval; u8 reg = lvc->reg; u8 mask = lvc->mask; int rc; value <<= lvc->start_bit; if (mask == 0xff) { newval = value; } else { if ((rc = sbus->read(reg, &oldval, 1))) return rc; oldval &= ~mask; /* Clear the masked bits */ value &= mask; /* Enforce mask on value */ newval = oldval | value; /* Set the desired bits */ } if ((rc = sbus->write(reg, &newval, 1))) return rc; if ((rc = sbus->read(reg, &newval, 1))) return rc; return (newval & mask) >> lvc->start_bit;}static int ov6x30_read_control(struct vcontrol * lvc){ struct camera_serial_bus * sbus = this->camif->sbus; u8 val; u8 reg = lvc->reg; u8 mask = lvc->mask; int rc; if ((rc = sbus->read(reg, &val, 1))) return rc; return (val & mask) >> lvc->start_bit;}static intov6x30_control(struct v4l2_control *vc, int write){ int i, val; struct vcontrol * lvc; i = find_vctrl(vc->id); if (i < 0) return -EINVAL; lvc = &control[i]; if (write) val = ov6x30_write_control(lvc, vc->value); else val = ov6x30_read_control(lvc); if (val >= 0) { vc->value = lvc->current_value = val; return 0; } else return val;}static intov6x30_set_control(struct v4l2_control *vc){ return ov6x30_control(vc, 1);}static intov6x30_get_control(struct v4l2_control *vc){ return ov6x30_control(vc, 0);}static intov6x30_restore_current_controls(void){ struct v4l2_control vc; int i, rc=0; for (i=0; i<NUM_CONTROLS; i++) { vc.id = control[i].qc.id; vc.value = control[i].current_value; if ((rc = ov6x30_set_control(&vc))) break; } return rc;}static intov6x30_save_current_controls(void){ struct v4l2_control vc; int i, rc=0; for (i=0; i<NUM_CONTROLS; i++) { vc.id = control[i].qc.id; if ((rc = ov6x30_get_control(&vc))) break; } return rc;}#define MIN_FP_24MHZ 245820 // 40.68 fps#define MIN_FP_12MHZ 492410 // 20.31 fps#define MAX_FP_24MHZ 512560 // 19.51 fps#define MAX_FP_12MHZ 1022890 // 9.78 fps#define MIN_FP 250000 // 40 fps#define MAX_FR 40#define MAX_FP 666667 // 15 fps#define MIN_FR 15/* starts at MAX_FP, increments by 0.2 sec (5 Hz) */static struct { int exclk; // MHz int regval;} fp_tbl[6] = { { 12000000, 165 }, // 15 fps { 12000000, 7 }, // 20 fps { 24000000, 295 }, // 25 fps { 24000000, 167 }, // 30 fps { 24000000, 77 }, // 35 fps { 24000000, 8 } // 40 fps};static int ov6x30_set_fp(int fp, int xclk, int test){ int ret; unsigned int fr_x100, i; ENTRY(); if (fp < MIN_FP || fp > MAX_FP) { err("fp out of range: %d\n", fp); return -EINVAL; } if (fp == 333667) fr_x100 = 30 * 100; else fr_x100 = (1000000000 + fp/2) / fp; // desired framerate * 100 if (fr_x100 % 500) { err("fp must be in intervals of 0.2 sec (5 Hz): %d\n", fp); return -EINVAL; } i = (fr_x100 - MIN_FR*100) / 500; if (xclk != fp_tbl[i].exclk) { err("need %d MHz XCLK for fp %d\n", fp_tbl[i].exclk, fp); return -EINVAL; } if (!test) { struct camera_serial_bus * sbus = this->camif->sbus; unsigned int regval = fp_tbl[i].regval; ret = sbus->write_verify(0x2a, 0x84 | ((regval & (1<<8))?(1<<5):0)); if (ret < 0) return ret; ret = sbus->write_verify(0x2b, regval & ~(1<<8)); if (ret < 0) return ret; current_frame_period = fp; current_xclk = xclk; } return fp;}static int ov6x30_get_fp(void){ return current_frame_period;}static int ov6x30_set_mode(void){#if 0 int H_start,H_end; int V_start,V_end; int width = omap_image_size[this->imgfmt].width; int height = omap_image_size[this->imgfmt].height;#endif struct camera_serial_bus * sbus = this->camif->sbus; int qcif = (this->imgfmt == QCIF); int ret = 0; u8 reg14; if ((ret = sbus->read(0x14, ®14, 1))) return ret; if (qcif) reg14 |= 0x20; else reg14 &= ~0x20; if ((ret = sbus->write_verify(0x2b, reg14)) < 0) return ret;#if 0 // FIXME: fix this // Calculate a centered image within the full CCD grid. H_start = ((MAXWIDTH - width)/4) + HORZCONST; H_end = H_start + (width/2); if (H_start < HORZCONST) { H_start = HORZCONST; // keep within bounds. H_end = MAXWIDTH/2; } V_start = ((MAXHEIGHT - height)/4) + VERTCONST; V_end = V_start + (height/2); if (V_start < VERTCONST) { // keep within bounds. V_start = VERTCONST; V_end = MAXHEIGHT/2; } ret = sbus->write_verify(0x17, (u8)H_start); ret = sbus->write_verify(0x18, (u8)H_end); ret = sbus->write_verify(0x19, (u8)V_start); ret = sbus->write_verify(0x1A, (u8)V_end);#endif return ret;}/* * This camera only supports RGB565 pixel format, but it can * convert to any of the following V4L2 pixel formats. */static intov6x30_find_format(struct v4l2_pix_format* fmt){ switch (fmt->pixelformat) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_BGR24: return RGB565; } return -1;}// **************************// Routine:// Description:// This the setup that must occur to adjust the// reg settings as per any new VIDIOC_S_FMT command// the client may have just performed to the driver.// **************************static int ov6x30_setup(struct v4l2_pix_format* fmt){ enum pixel_format pixfmt; enum image_format imgfmt; if ((pixfmt = ov6x30_find_format(fmt)) < 0) return -EINVAL; if (fmt->width >= omap_image_size[CIF].width) { imgfmt = CIF; } else { imgfmt = QCIF; } fmt->width = omap_image_size[imgfmt].width; fmt->height = omap_image_size[imgfmt].height; this->imgfmt = imgfmt; this->pixfmt = pixfmt; return ov6x30_set_mode();}static int ov6x30_open(void){ struct camera_serial_bus * sbus = this->camif->sbus; int i, rc; for (i=0; i < INIT_REGTBL_SIZE; i++) { if (init_regtbl[i].no_verify) sbus->write(init_regtbl[i].reg, &init_regtbl[i].val, 1); else sbus->write_verify(init_regtbl[i].reg, init_regtbl[i].val); } if ((rc = ov6x30_set_fp(current_frame_period, current_xclk, 0)) < 0) { err("failed to set frame period\n"); return rc; } if ((rc = ov6x30_set_mode())) return rc; return ov6x30_restore_current_controls();}static int ov6x30_close(void){ /* * save the current controls so they can be restored on * next open. */ return ov6x30_save_current_controls();}static int ov6x30_init(void){ int i; for (i=0; i<NUM_CONTROLS; i++) control[i].current_value = control[i].qc.default_value; this->imgfmt = QCIF; this->pixfmt = RGB565; return 0;}static void ov6x30_cleanup(void){ // nothing to do}static int ov6x30_detect(void){ struct camera_serial_bus * sbus; this = &camera_ov6x30; sbus = this->camif->sbus; sbus->set_devid(CAMERA_OV6630_DEV_ID); // Just an arbitrary OmniVision camera command return sbus->write_verify(0x11, 0x40);}struct camera camera_ov6x30 = { imgfmt: QCIF, pixfmt: RGB565, detect: ov6x30_detect, init: ov6x30_init, cleanup: ov6x30_cleanup, open: ov6x30_open, close: ov6x30_close, set_format: ov6x30_setup, set_frame_period: ov6x30_set_fp, get_frame_period: ov6x30_get_fp, convert_image: ov6x30_convert_image, query_control: ov6x30_query_control, get_control: ov6x30_get_control, set_control: ov6x30_set_control, query_menu: ov6x30_querymenu,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -