📄 ov511_core.c
字号:
static inti2c_attach_inform(struct i2c_client *client){ struct usb_ov511 *ov = i2c_get_adapdata(client->adapter); int id = client->driver->id; if (id == I2C_DRIVERID_OVCAMCHIP) { int rc; ov->sensor_client = client; rc = sensor_cmd(ov, OVCAMCHIP_CMD_INITIALIZE, &ov->sensor_mono); if (rc < 0) { err("ERROR: Sensor init failed (rc=%d)", rc); ov->sensor_client = NULL; return rc; } down(&ov->lock); if (sensor_cmd(ov, OVCAMCHIP_CMD_Q_SUBTYPE, &ov->sensor) < 0) rc = -EIO; else if (client->addr == OV7xx0_SID) rc = ov7xx0_configure(ov); else if (client->addr == OV6xx0_SID) rc = ov6xx0_configure(ov); else rc = -EINVAL; up(&ov->lock); if (rc) { ov->sensor_client = NULL; return rc; } } else if (id == I2C_DRIVERID_TUNER) { if (ov->bclass == BCL_OV518 || ov->tuner_type < 0) return -1; ov->has_tuner = 1; call_i2c_clients(ov, TUNER_SET_TYPE, &ov->tuner_type); } else if (id == I2C_DRIVERID_TDA7313) { if (ov->bclass == BCL_OV518 || ov->tuner_type < 0) return -1; ov->has_audiochip = 1; } else if (id == I2C_DRIVERID_SAA7111A) { int arg; if (ov->bclass == BCL_OV518) return -1; down(&ov->lock); saa7111a_configure(ov); up(&ov->lock); arg = 1; call_i2c_clients(ov, DECODER_ENABLE_OUTPUT, &arg); } else { PDEBUG(1, "Rejected client [%s] with [%s]",#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) client->name, client->driver->name);#else client->name, client->driver->driver.name);#endif return -1; } PDEBUG(1, "i2c attach client [%s] with [%s]",#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) client->name, client->driver->name);#else client->name, client->driver->driver.name);#endif return 0;}static inti2c_detach_inform(struct i2c_client *client){ struct usb_ov511 *ov = i2c_get_adapdata(client->adapter); if (ov->sensor_client == client) ov->sensor_client = NULL; PDEBUG(1, "i2c detach [%s]", client->name); return 0;}static int ov51x_i2c_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg){ return 0;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)static voidov51x_i2c_inc_use(struct i2c_adapter *adap){ MOD_INC_USE_COUNT;}static voidov51x_i2c_dec_use(struct i2c_adapter *adap){ MOD_DEC_USE_COUNT;}#endifstatic struct i2c_algorithm ov518_i2c_algo = {#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) .name = "OV518 algorithm", .id = I2C_ALGO_SMBUS,#endif .smbus_xfer = ov518_smbus_xfer, .algo_control = ov51x_i2c_control, .functionality = ov518_i2c_func,};static struct i2c_algorithm ov511_i2c_algo = {#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) .name = "OV511 algorithm", .id = I2C_ALGO_SMBUS,#endif .smbus_xfer = ov511_smbus_xfer, .algo_control = ov51x_i2c_control, .functionality = ov511_i2c_func,};static struct i2c_adapter i2c_adap_template = { .name = "(unset)",#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 6) .class = I2C_CLASS_CAM_DIGITAL,#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70) .class = I2C_ADAP_CLASS_CAM_DIGITAL,#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) .inc_use = ov51x_i2c_inc_use, .dec_use = ov51x_i2c_dec_use,#else .owner = THIS_MODULE,#endif .client_register = i2c_attach_inform, .client_unregister = i2c_detach_inform,};static intov51x_init_i2c(struct usb_ov511 *ov){ memcpy(&ov->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); /* Temporary name. We'll set the final one when we know the minor # */ sprintf(ov->i2c_adap.name, "OV51x"); i2c_set_adapdata(&ov->i2c_adap, ov); // FIXME: Need separate IDs for OV511+/OV518+ if (ov->bclass == BCL_OV518) { ov->i2c_adap.algo = &ov518_i2c_algo;#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) ov->i2c_adap.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518;#else ov->i2c_adap.id = I2C_HW_SMBUS_OV518;#endif } else { ov->i2c_adap.algo = &ov511_i2c_algo;#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) ov->i2c_adap.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV511;#else ov->i2c_adap.id = I2C_HW_SMBUS_OV511;#endif } ov->internal_client.adapter = &ov->i2c_adap; PDEBUG(4, "Registering I2C bus with kernel"); return i2c_add_adapter(&ov->i2c_adap);}/*****************************************************************************//* Temporarily stops OV511 from functioning. Must do this before changing * registers while the camera is streaming */static inline intov51x_stop(struct usb_ov511 *ov){ PDEBUG(4, "stopping"); ov->stopped = 1; if (ov->bclass == BCL_OV518) return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a)); else return (reg_w(ov, R51x_SYS_RESET, 0x3d));}/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not * actually stopped (for performance). */static inline intov51x_restart(struct usb_ov511 *ov){ if (ov->stopped) { PDEBUG(4, "restarting"); ov->stopped = 0; /* Reinitialize the stream */ if (ov->bclass == BCL_OV518) reg_w(ov, 0x2f, 0x80); return (reg_w(ov, R51x_SYS_RESET, 0x00)); } return 0;}/* Sleeps until no frames are active. Returns !0 if got signal or unplugged */static intov51x_wait_frames_inactive(struct usb_ov511 *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;}/* Resets the hardware snapshot button */static voidov51x_clear_snapshot(struct usb_ov511 *ov){ if (ov->bclass == BCL_OV511) { reg_w(ov, R51x_SYS_SNAP, 0x00); reg_w(ov, R51x_SYS_SNAP, 0x02); reg_w(ov, R51x_SYS_SNAP, 0x00); } else if (ov->bclass == BCL_OV518) { warn("snapshot reset not supported yet on OV518(+)"); } else { err("clear snap: invalid bridge type"); }}#if defined(CONFIG_VIDEO_PROC_FS)/* Checks the status of the snapshot button. Returns 1 if it was pressed since * it was last cleared, and zero in all other cases (including errors) */static intov51x_check_snapshot(struct usb_ov511 *ov){ int ret, status = 0; if (ov->bclass == BCL_OV511) { ret = reg_r(ov, R51x_SYS_SNAP); if (ret < 0) { err("Error checking snspshot status (%d)", ret); } else if (ret & 0x08) { status = 1; } } else if (ov->bclass == BCL_OV518) { warn("snapshot check not supported yet on OV518(+)"); } else { err("check snap: invalid bridge type"); } return status;}#endif/* Returns 1 if image streaming needs to be stopped while setting the specified * control, and returns 0 if not */static intsensor_needs_stop(struct usb_ov511 *ov, int cid){ if (!ov->stop_during_set) return 0; /* SAA7111A always maintains a stable * image, even when setting controls */ if (ov->sensor == SEN_SAA7111A) return 0; switch (cid) { case OVCAMCHIP_CID_CONT: case OVCAMCHIP_CID_BRIGHT: case OVCAMCHIP_CID_SAT: case OVCAMCHIP_CID_HUE: case OVCAMCHIP_CID_EXP: return 1; } return 0;}static intsensor_set_control(struct usb_ov511 *ov, int cid, int val){ struct ovcamchip_control ctl; int rc; if (sensor_needs_stop(ov, cid)) if (ov51x_stop(ov) < 0) return -EIO; ctl.id = cid; ctl.value = val; rc = sensor_cmd(ov, OVCAMCHIP_CMD_S_CTRL, &ctl); if (ov51x_restart(ov) < 0) return -EIO; return rc;}static intsensor_get_control(struct usb_ov511 *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 intov511_set_packet_size(struct usb_ov511 *ov, int size){ int alt, mult; if (ov51x_stop(ov) < 0) return -EIO; mult = size >> 5; if (ov->bridge == BRG_OV511) { if (size == 0) alt = OV511_ALT_SIZE_0; else if (size == 257) alt = OV511_ALT_SIZE_257; else if (size == 513) alt = OV511_ALT_SIZE_513; else if (size == 769) alt = OV511_ALT_SIZE_769; else if (size == 993) alt = OV511_ALT_SIZE_993; else { err("Set packet size: invalid size (%d)", size); return -EINVAL; } } else if (ov->bridge == BRG_OV511PLUS) { if (size == 0) alt = OV511PLUS_ALT_SIZE_0; else if (size == 33) alt = OV511PLUS_ALT_SIZE_33; else if (size == 129) alt = OV511PLUS_ALT_SIZE_129; else if (size == 257) alt = OV511PLUS_ALT_SIZE_257; else if (size == 385) alt = OV511PLUS_ALT_SIZE_385; else if (size == 513) alt = OV511PLUS_ALT_SIZE_513; else if (size == 769) alt = OV511PLUS_ALT_SIZE_769; else if (size == 961) alt = OV511PLUS_ALT_SIZE_961; else { err("Set packet size: invalid size (%d)", size); return -EINVAL; } } else { err("Set packet size: Invalid bridge type"); return -EINVAL; } PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt); if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) return -EIO; if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; ov->packet_size = size; if (ov51x_restart(ov) < 0) return -EIO; return 0;}/* Note: Unlike the OV511/OV511+, the size argument does NOT include the * optional packet number byte. The actual size *is* stored in ov->packet_size, * though. */static intov518_set_packet_size(struct usb_ov511 *ov, int size){ int alt; if (ov51x_stop(ov) < 0) return -EIO; if (ov->bclass == BCL_OV518) { if (size == 0) alt = OV518_ALT_SIZE_0; else if (size == 128) alt = OV518_ALT_SIZE_128; else if (size == 256) alt = OV518_ALT_SIZE_256; else if (size == 384) alt = OV518_ALT_SIZE_384; else if (size == 512) alt = OV518_ALT_SIZE_512; else if (size == 640) alt = OV518_ALT_SIZE_640; else if (size == 768) alt = OV518_ALT_SIZE_768; else if (size == 896) alt = OV518_ALT_SIZE_896; else { err("Set packet size: invalid size (%d)", size); return -EINVAL; } } else { err("Set packet size: Invalid bridge type"); return -EINVAL; } PDEBUG(3, "%d, alt=%d", size, alt); ov->packet_size = size; if (size > 0) { /* Program ISO FIFO size reg (packet number isn't included) */ ov518_reg_w32(ov, 0x30, size, 2); if (ov->packet_numbering) ++ov->packet_size; } if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } /* Initialize the stream */ if (reg_w(ov, 0x2f, 0x80) < 0) return -EIO; if (ov51x_restart(ov) < 0) return -EIO; if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; return 0;}/* Upload compression params and quantization tables. Returns 0 for success. */static intov511_init_compression(struct usb_ov511 *ov){ int rc = 0; if (!ov->compress_inited) { reg_w(ov, 0x70, phy); reg_w(ov, 0x71, phuv); reg_w(ov, 0x72, pvy); reg_w(ov, 0x73, pvuv); reg_w(ov, 0x74, qhy); reg_w(ov, 0x75, qhuv); reg_w(ov, 0x76, qvy); reg_w(ov, 0x77, qvuv); if (ov511_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out; } } ov->compress_inited = 1;out: return rc;}/* Upload compression params and quantization tables. Returns 0 for success. */static intov518_init_compression(struct usb_ov511 *ov){ int rc = 0; if (!ov->compress_inited) { if (ov518_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out; } } ov->compress_inited = 1;out: return rc;}static intsensor_set_picture(struct usb_ov511 *ov, struct video_picture *p){ int rc; PDEBUG(4, "sensor_set_picture"); if (ov->has_decoder) { call_i2c_clients(ov, DECODER_SET_PICTURE, p); return 0; } /* Don't return error if a setting is unsupported, or rest of settings * will not be performed */ rc = sensor_set_control(ov, OVCAMCHIP_CID_CONT, p->contrast); if (FATAL_ERROR(rc)) return rc; rc = sensor_set_control(ov, OVCAMCHIP_CID_BRIGHT, p->brightness); if (FATAL_ERROR(rc)) return rc; rc = sensor_set_control(ov, OVCAMCHIP_CID_SAT, p->colour); if (FATAL_ERROR(rc)) return rc; rc = sensor_set_control(ov, OVCAMCHIP_CID_HUE, p->hue); if (FATAL_ERROR(rc)) return rc; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -