ov519.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,231 行 · 第 1/4 页
C
2,231 行
* output mode */ /* OV7640 is 8-bit only */ if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640) i2c_w_mask(sd, 0x13, 0x00, 0x20); /******** Clock programming ********/ /* The OV6620 needs special handling. This prevents the * severe banding that normally occurs */ if (sd->sensor == SEN_OV6620) { /* Clock down */ i2c_w(sd, 0x2a, 0x04); i2c_w(sd, 0x11, sd->clockdiv); i2c_w(sd, 0x2a, 0x84); /* This next setting is critical. It seems to improve * the gain or the contrast. The "reserved" bits seem * to have some effect in this case. */ i2c_w(sd, 0x2d, 0x85); } else if (sd->clockdiv >= 0) { i2c_w(sd, 0x11, sd->clockdiv); } /******** Special Features ********//* no evidence this is possible with OV7670, either */ /* Test Pattern */ if (sd->sensor != SEN_OV7640 && sd->sensor != SEN_OV7670) i2c_w_mask(sd, 0x12, 0x00, 0x02); /* Enable auto white balance */ if (sd->sensor == SEN_OV7670) i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB, OV7670_COM8_AWB); else i2c_w_mask(sd, 0x12, 0x04, 0x04); /* This will go away as soon as ov51x_mode_init_sensor_regs() */ /* is fully tested. */ /* 7620/6620/6630? don't have register 0x35, so play it safe */ if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { if (!qvga) i2c_w(sd, 0x35, 0x9e); else i2c_w(sd, 0x35, 0x1e); } return 0;}static void sethvflip(struct sd *sd){ if (sd->sensor != SEN_OV7670) return; if (sd->gspca_dev.streaming) ov51x_stop(sd); i2c_w_mask(sd, OV7670_REG_MVFP, OV7670_MVFP_MIRROR * sd->hflip | OV7670_MVFP_VFLIP * sd->vflip, OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP); if (sd->gspca_dev.streaming) ov51x_restart(sd);}static int set_ov_sensor_window(struct sd *sd){ struct gspca_dev *gspca_dev; int qvga; int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale; int ret, hstart, hstop, vstop, vstart; __u8 v; gspca_dev = &sd->gspca_dev; qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; /* The different sensor ICs handle setting up of window differently. * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */ switch (sd->sensor) { case SEN_OV8610: hwsbase = 0x1e; hwebase = 0x1e; vwsbase = 0x02; vwebase = 0x02; break; case SEN_OV7610: case SEN_OV76BE: hwsbase = 0x38; hwebase = 0x3a; vwsbase = vwebase = 0x05; break; case SEN_OV6620: case SEN_OV6630: hwsbase = 0x38; hwebase = 0x3a; vwsbase = 0x05; vwebase = 0x06; break; case SEN_OV7620: hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ hwebase = 0x2f; vwsbase = vwebase = 0x05; break; case SEN_OV7640: hwsbase = 0x1a; hwebase = 0x1a; vwsbase = vwebase = 0x03; break; case SEN_OV7670: /*handling of OV7670 hardware sensor start and stop values * is very odd, compared to the other OV sensors */ vwsbase = vwebase = hwebase = hwsbase = 0x00; break; default: return -EINVAL; } switch (sd->sensor) { case SEN_OV6620: case SEN_OV6630: if (qvga) { /* QCIF */ hwscale = 0; vwscale = 0; } else { /* CIF */ hwscale = 1; vwscale = 1; /* The datasheet says 0; * it's wrong */ } break; case SEN_OV8610: if (qvga) { /* QSVGA */ hwscale = 1; vwscale = 1; } else { /* SVGA */ hwscale = 2; vwscale = 2; } break; default: /* SEN_OV7xx0 */ if (qvga) { /* QVGA */ hwscale = 1; vwscale = 0; } else { /* VGA */ hwscale = 2; vwscale = 1; } } ret = mode_init_ov_sensor_regs(sd); if (ret < 0) return ret; if (sd->sensor == SEN_OV8610) { i2c_w_mask(sd, 0x2d, 0x05, 0x40); /* old 0x95, new 0x05 from windrv 090403 */ /* bits 5-7: reserved */ i2c_w_mask(sd, 0x28, 0x20, 0x20); /* bit 5: progressive mode on */ } /* The below is wrong for OV7670s because their window registers * only store the high bits in 0x17 to 0x1a */ /* SRH Use sd->max values instead of requested win values */ /* SCS Since we're sticking with only the max hardware widths * for a given mode */ /* I can hard code this for OV7670s */ /* Yes, these numbers do look odd, but they're tested and work! */ if (sd->sensor == SEN_OV7670) { if (qvga) { /* QVGA from ov7670.c by * Jonathan Corbet */ hstart = 164; hstop = 20; vstart = 14; vstop = 494; } else { /* VGA */ hstart = 158; hstop = 14; vstart = 10; vstop = 490; } /* OV7670 hardware window registers are split across * multiple locations */ i2c_w(sd, OV7670_REG_HSTART, hstart >> 3); i2c_w(sd, OV7670_REG_HSTOP, hstop >> 3); v = i2c_r(sd, OV7670_REG_HREF); v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07); msleep(10); /* need to sleep between read and write to * same reg! */ i2c_w(sd, OV7670_REG_HREF, v); i2c_w(sd, OV7670_REG_VSTART, vstart >> 2); i2c_w(sd, OV7670_REG_VSTOP, vstop >> 2); v = i2c_r(sd, OV7670_REG_VREF); v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03); msleep(10); /* need to sleep between read and write to * same reg! */ i2c_w(sd, OV7670_REG_VREF, v); sethvflip(sd); } else { i2c_w(sd, 0x17, hwsbase); i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale)); i2c_w(sd, 0x19, vwsbase); i2c_w(sd, 0x1a, vwebase + (sd->gspca_dev.height >> vwscale)); } return 0;}/* -- start the camera -- */static int sd_start(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; int ret; ret = ov519_mode_init_regs(sd); if (ret < 0) goto out; ret = set_ov_sensor_window(sd); if (ret < 0) goto out; ret = ov51x_restart(sd); if (ret < 0) goto out; PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); ov51x_led_control(sd, 1); return 0;out: PDEBUG(D_ERR, "camera start error:%d", ret); return ret;}static void sd_stopN(struct gspca_dev *gspca_dev){ ov51x_stop((struct sd *) gspca_dev); ov51x_led_control((struct sd *) gspca_dev, 0);}static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */{ /* Header of ov519 is 16 bytes: * Byte Value Description * 0 0xff magic * 1 0xff magic * 2 0xff magic * 3 0xXX 0x50 = SOF, 0x51 = EOF * 9 0xXX 0x01 initial frame without data, * 0x00 standard frame with image * 14 Lo in EOF: length of image data / 8 * 15 Hi */ if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) { switch (data[3]) { case 0x50: /* start of frame */#define HDRSZ 16 data += HDRSZ; len -= HDRSZ;#undef HDRSZ if (data[0] == 0xff || data[1] == 0xd8) gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); else gspca_dev->last_packet_type = DISCARD_PACKET; return; case 0x51: /* end of frame */ if (data[9] != 0) gspca_dev->last_packet_type = DISCARD_PACKET; gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0); return; } } /* intermediate packet */ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);}/* -- management routines -- */static void setbrightness(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; int val; val = sd->brightness; PDEBUG(D_CONF, "brightness:%d", val);/* if (gspca_dev->streaming) * ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: case SEN_OV76BE: case SEN_OV6620: case SEN_OV6630: case SEN_OV7640: i2c_w(sd, OV7610_REG_BRT, val); break; case SEN_OV7620: /* 7620 doesn't like manual changes when in auto mode *//*fixme * if (!sd->auto_brt) */ i2c_w(sd, OV7610_REG_BRT, val); break; case SEN_OV7670:/*win trace * i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */ i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val)); break; }/* if (gspca_dev->streaming) * ov51x_restart(sd); */}static void setcontrast(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; int val; val = sd->contrast; PDEBUG(D_CONF, "contrast:%d", val);/* if (gspca_dev->streaming) ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV7610: case SEN_OV6620: i2c_w(sd, OV7610_REG_CNT, val); break; case SEN_OV6630: i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f); case SEN_OV8610: { static const __u8 ctab[] = { 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f }; /* Use Y gamma control instead. Bit 0 enables it. */ i2c_w(sd, 0x64, ctab[val >> 5]); break; } case SEN_OV7620: { static const __u8 ctab[] = { 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff }; /* Use Y gamma control instead. Bit 0 enables it. */ i2c_w(sd, 0x64, ctab[val >> 4]); break; } case SEN_OV7640: /* Use gain control instead. */ i2c_w(sd, OV7610_REG_GAIN, val >> 2); break; case SEN_OV7670: /* check that this isn't just the same as ov7610 */ i2c_w(sd, OV7670_REG_CONTRAS, val >> 1); break; }/* if (gspca_dev->streaming) ov51x_restart(sd); */}static void setcolors(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; int val; val = sd->colors; PDEBUG(D_CONF, "saturation:%d", val);/* if (gspca_dev->streaming) ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: case SEN_OV76BE: case SEN_OV6620: case SEN_OV6630: i2c_w(sd, OV7610_REG_SAT, val); break; case SEN_OV7620: /* Use UV gamma control instead. Bits 0 & 7 are reserved. *//* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e); if (rc < 0) goto out; */ i2c_w(sd, OV7610_REG_SAT, val); break; case SEN_OV7640: i2c_w(sd, OV7610_REG_SAT, val & 0xf0); break; case SEN_OV7670: /* supported later once I work out how to do it * transparently fail now! */ /* set REG_COM13 values for UV sat auto mode */ break; }/* if (gspca_dev->streaming) ov51x_restart(sd); */}static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->brightness = val; setbrightness(gspca_dev); return 0;}static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->brightness; return 0;}static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->contrast = val; setcontrast(gspca_dev); return 0;}static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->contrast; return 0;}static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->colors = val; setcolors(gspca_dev); return 0;}static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->colors; return 0;}static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->hflip = val; sethvflip(sd); return 0;}static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->hflip; return 0;}static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val){ struct sd *sd = (struct sd *) gspca_dev; sd->vflip = val; sethvflip(sd); return 0;}static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val){ struct sd *sd = (struct sd *) gspca_dev; *val = sd->vflip; return 0;}/* sub-driver description */static const struct sd_desc sd_desc = { .name = MODULE_NAME, .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan,};/* -- module initialisation -- */static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4052)}, {USB_DEVICE(0x041e, 0x405f)}, {USB_DEVICE(0x041e, 0x4060)}, {USB_DEVICE(0x041e, 0x4061)}, {USB_DEVICE(0x041e, 0x4064)}, {USB_DEVICE(0x041e, 0x4068)}, {USB_DEVICE(0x045e, 0x028c)}, {USB_DEVICE(0x054c, 0x0154)}, {USB_DEVICE(0x054c, 0x0155)}, {USB_DEVICE(0x05a9, 0x0519)}, {USB_DEVICE(0x05a9, 0x0530)}, {USB_DEVICE(0x05a9, 0x4519)}, {USB_DEVICE(0x05a9, 0x8519)}, {}};#undef DVNAMEMODULE_DEVICE_TABLE(usb, device_table);/* -- device connect -- */static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id){ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), THIS_MODULE);}static struct usb_driver sd_driver = { .name = MODULE_NAME, .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect,#ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume,#endif};/* -- module insert / remove -- */static int __init sd_mod_init(void){ if (usb_register(&sd_driver) < 0) return -1; PDEBUG(D_PROBE, "registered"); return 0;}static void __exit sd_mod_exit(void){ usb_deregister(&sd_driver); PDEBUG(D_PROBE, "deregistered");}module_init(sd_mod_init);module_exit(sd_mod_exit);module_param(frame_rate, int, 0644);MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?