📄 ov511.c
字号:
} static void create_proc_ov511_cam(struct usb_ov511 *ov) { char dirname[10]; if (!ov511_proc_entry || !ov) return; /* Create per-device directory */ snprintf(dirname, 10, "%d", ov->vdev.minor); PDEBUG(4, "creating /proc/video/ov511/%s/", dirname); ov->proc_devdir = create_proc_entry(dirname, S_IFDIR, ov511_proc_entry); if (!ov->proc_devdir) return; ov->proc_devdir->owner = THIS_MODULE; /* Create "info" entry (human readable device information) */ PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname); ov->proc_info = create_proc_read_entry("info", S_IFREG|S_IRUGO|S_IWUSR, ov->proc_devdir, ov511_read_proc_info, ov); if (!ov->proc_info) return; ov->proc_info->owner = THIS_MODULE; /* Don't create it if old snapshot mode on (would cause race cond.) */ if (!snapshot) { /* Create "button" entry (snapshot button status) */ PDEBUG(4, "creating /proc/video/ov511/%s/button", dirname); ov->proc_button = create_proc_read_entry("button", S_IFREG|S_IRUGO|S_IWUSR, ov->proc_devdir, ov511_read_proc_button, ov); if (!ov->proc_button) return; } ov->proc_button->owner = THIS_MODULE; /* Create "control" entry (ioctl() interface) */ PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname); lock_kernel(); ov->proc_control = create_proc_entry("control", S_IFREG|S_IRUGO|S_IWUSR, ov->proc_devdir); if (!ov->proc_control) { unlock_kernel(); return; } ov->proc_control->owner = THIS_MODULE; ov->proc_control->data = ov; ov->proc_control->proc_fops = &ov511_control_fops; unlock_kernel(); } static void destroy_proc_ov511_cam(struct usb_ov511 *ov) { char dirname[10]; if (!ov || !ov->proc_devdir) return; snprintf(dirname, 10, "%d", ov->vdev.minor); /* Destroy "control" entry */ if (ov->proc_control) { PDEBUG(4, "destroying /proc/video/ov511/%s/control", dirname); remove_proc_entry("control", ov->proc_devdir); ov->proc_control = NULL; } /* Destroy "button" entry */ if (ov->proc_button) { PDEBUG(4, "destroying /proc/video/ov511/%s/button", dirname); remove_proc_entry("button", ov->proc_devdir); ov->proc_button = NULL; } /* Destroy "info" entry */ if (ov->proc_info) { PDEBUG(4, "destroying /proc/video/ov511/%s/info", dirname); remove_proc_entry("info", ov->proc_devdir); ov->proc_info = NULL; } /* Destroy per-device directory */ PDEBUG(4, "destroying /proc/video/ov511/%s/", dirname); remove_proc_entry(dirname, ov511_proc_entry); ov->proc_devdir = NULL; } static void proc_ov511_create(void) { /* No current standard here. Alan prefers /proc/video/ as it keeps * /proc "less cluttered than /proc/randomcardifoundintheshed/" * -claudio */ if (video_proc_entry == NULL) { err("Error: /proc/video/ does not exist"); return; } ov511_proc_entry = create_proc_entry("ov511", S_IFDIR, video_proc_entry); if (ov511_proc_entry) ov511_proc_entry->owner = THIS_MODULE; else err("Unable to create /proc/video/ov511"); } static void proc_ov511_destroy(void) { PDEBUG(3, "removing /proc/video/ov511"); if (ov511_proc_entry == NULL) return; remove_proc_entry("ov511", video_proc_entry); }#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ /********************************************************************** * * Register I/O * **********************************************************************/ /* Write an OV51x register */ static int reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc; PDEBUG(5, "0x%02X:0x%02X", reg, value); down(&ov->cbuf_lock); ov->cbuf[0] = value; rc = usb_control_msg(ov->dev, usb_sndctrlpipe(ov->dev, 0), (ov->bclass == BCL_OV518)?1:2 /* REG_IO */, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, (__u16)reg, &ov->cbuf[0], 1, HZ); up(&ov->cbuf_lock); if (rc < 0) err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc)); return rc; } /* Read from an OV51x register */ /* returns: negative is error, pos or zero is data */ static int reg_r(struct usb_ov511 *ov, unsigned char reg) { int rc; down(&ov->cbuf_lock); rc = usb_control_msg(ov->dev, usb_rcvctrlpipe(ov->dev, 0), (ov->bclass == BCL_OV518)?1:3 /* REG_IO */, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, (__u16)reg, &ov->cbuf[0], 1, HZ); if (rc < 0) { err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc)); } else { rc = ov->cbuf[0]; PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); } up(&ov->cbuf_lock); return rc; } /* * Writes bits at positions specified by mask to an OV51x reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value". */ static int reg_w_mask(struct usb_ov511 *ov, unsigned char reg, unsigned char value, unsigned char mask) { int ret; unsigned char oldval, newval; ret = reg_r(ov, reg); if (ret < 0) return ret; oldval = (unsigned char) ret; oldval &= (~mask); /* Clear the masked bits */ value &= mask; /* Enforce mask on value */ newval = oldval | value; /* Set the desired bits */ return (reg_w(ov, reg, newval)); } /* * Writes multiple (n) byte value to a single register. Only valid with certain * registers (0x30 and 0xc4 - 0xce). */ static int ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) { int rc; PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); down(&ov->cbuf_lock); *((u32 *)ov->cbuf) = __cpu_to_le32(val); rc = usb_control_msg(ov->dev, usb_sndctrlpipe(ov->dev, 0), 1 /* REG_IO */, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, (__u16)reg, ov->cbuf, n, HZ); up(&ov->cbuf_lock); if (rc < 0) err("reg write multiple: error %d: %s", rc, symbolic(urb_errlist, rc)); return rc; } static int ov511_upload_quan_tables(struct usb_ov511 *ov) { unsigned char *pYTable = yQuanTable511; unsigned char *pUVTable = uvQuanTable511; unsigned char val0, val1; int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) { if (ENABLE_Y_QUANTABLE) { val0 = *pYTable++; val1 = *pYTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } if (ENABLE_UV_QUANTABLE) { val0 = *pUVTable++; val1 = *pUVTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); if (rc < 0) return rc; } reg++; } return 0; } /* OV518 quantization tables are 8x4 (instead of 8x8) */ static int ov518_upload_quan_tables(struct usb_ov511 *ov) { unsigned char *pYTable = yQuanTable518; unsigned char *pUVTable = uvQuanTable518; unsigned char val0, val1; int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) { if (ENABLE_Y_QUANTABLE) { val0 = *pYTable++; val1 = *pYTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } if (ENABLE_UV_QUANTABLE) { val0 = *pUVTable++; val1 = *pUVTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); if (rc < 0) return rc; } reg++; } return 0; } static int ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) { int rc; /* Setting bit 0 not allowed on 518/518Plus */ if (ov->bclass == BCL_OV518) reset_type &= 0xfe; PDEBUG(4, "Reset: type=0x%02X", reset_type); rc = reg_w(ov, R51x_SYS_RESET, reset_type); rc = reg_w(ov, R51x_SYS_RESET, 0); if (rc < 0) err("reset: command failed"); return rc; } /********************************************************************** * * Low-level I2C I/O functions * **********************************************************************/ /* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. * This is normally only called from i2c_w(). Note that this function * always succeeds regardless of whether the sensor is present and working. */ static int ov518_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc; PDEBUG(5, "0x%02X:0x%02X", reg, value); /* Select camera register */ rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) return rc; /* Write "value" to I2C data port of OV511 */ rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) return rc; /* Initiate 3-byte write cycle */ rc = reg_w(ov, R518_I2C_CTL, 0x01); if (rc < 0) return rc; return 0; } /* NOTE: Do not call this function directly! */ static int ov511_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc, retries; PDEBUG(5, "0x%02X:0x%02X", reg, value); /* Three byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) return rc; /* Write "value" to I2C data port of OV511 */ rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) return rc; /* Initiate 3-byte write cycle */ rc = reg_w(ov, R511_I2C_CTL, 0x01); if (rc < 0) return rc; do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) return rc; if ((rc&2) == 0) /* Ack? */ break;#if 0 /* I2C abort */ reg_w(ov, R511_I2C_CTL, 0x10);#endif if (--retries < 0) { err("i2c write retries exhausted"); return -1; } } return 0; } /* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. * This is normally only called from i2c_r(). Note that this function * always succeeds regardless of whether the sensor is present and working. */ static int ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) { int rc, value; /* Select camera register */ rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) return rc; /* Initiate 2-byte write cycle */ rc = reg_w(ov, R518_I2C_CTL, 0x03); if (rc < 0) return rc; /* Initiate 2-byte read cycle */ rc = reg_w(ov, R518_I2C_CTL, 0x05); if (rc < 0) return rc; value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); return value; } /* NOTE: Do not call this function directly! * returns: negative is error, pos or zero is data */ static int ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) { int rc, value, retries; /* Two byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) return rc; /* Initiate 2-byte write cycle */ rc = reg_w(ov, R511_I2C_CTL, 0x03); if (rc < 0) return rc; do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) return rc; if ((rc&2) == 0) /* Ack? */ break; /* I2C abort */ reg_w(ov, R511_I2C_CTL, 0x10); if (--retries < 0) { err("i2c write retries exhausted"); return -1; } } /* Two byte read cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Initiate 2-byte read cycle */ rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) return rc; do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) return rc; if ((rc&2) == 0) /* Ack? */ break; /* I2C abort */ rc = reg_w(ov, R511_I2C_CTL, 0x10); if (rc < 0) return rc; if (--retries < 0) { err("i2c read retries exhausted"); return -1; } } value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); /* This is needed to make i2c_w() work */ rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) return rc; return value; } /* returns: negative is error, pos or zero is data */ static int i2c_r(struct usb_ov511 *ov, unsigned char reg) { int rc; down(&ov->i2c_lock); if (ov->bclass == BCL_OV518) rc = ov518_i2c_read_internal(ov, reg); else rc = ov511_i2c_read_internal(ov, reg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -