?? ov511.c
字號:
struct video_picture p; unsigned char exp; if (!ov511 || !ov511->dev) return -ENODEV; sensor_get_picture(ov511, &p); sensor_get_exposure(ov511, &exp); /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ out += sprintf(out, "driver_version : %s\n", DRIVER_VERSION); out += sprintf(out, "custom_id : %d\n", ov511->customid); out += sprintf(out, "model : %s\n", ov511->desc ? clist[ov511->desc].description : "unknown"); out += sprintf(out, "streaming : %s\n", YES_NO(ov511->streaming)); out += sprintf(out, "grabbing : %s\n", YES_NO(ov511->grabbing)); out += sprintf(out, "compress : %s\n", YES_NO(ov511->compress)); out += sprintf(out, "subcapture : %s\n", YES_NO(ov511->sub_flag)); out += sprintf(out, "sub_size : %d %d %d %d\n", ov511->subx, ov511->suby, ov511->subw, ov511->subh); out += sprintf(out, "data_format : %s\n", force_rgb ? "RGB" : "BGR"); out += sprintf(out, "brightness : %d\n", p.brightness >> 8); out += sprintf(out, "colour : %d\n", p.colour >> 8); out += sprintf(out, "contrast : %d\n", p.contrast >> 8); out += sprintf(out, "hue : %d\n", p.hue >> 8); out += sprintf(out, "exposure : %d\n", exp); out += sprintf(out, "num_frames : %d\n", OV511_NUMFRAMES); for (i = 0; i < OV511_NUMFRAMES; i++) { out += sprintf(out, "frame : %d\n", i); out += sprintf(out, " depth : %d\n", ov511->frame[i].depth); out += sprintf(out, " size : %d %d\n", ov511->frame[i].width, ov511->frame[i].height); out += sprintf(out, " format : "); for (j = 0; plist[j].num >= 0; j++) { if (plist[j].num == ov511->frame[i].format) { out += sprintf(out, "%s\n", plist[j].name); break; } } if (plist[j].num < 0) out += sprintf(out, "unknown\n"); out += sprintf(out, " data_buffer : 0x%p\n", ov511->frame[i].data); } out += sprintf(out, "snap_enabled : %s\n", YES_NO(ov511->snap_enabled)); out += sprintf(out, "bridge : %s\n", ov511->bridge == BRG_OV511 ? "OV511" : ov511->bridge == BRG_OV511PLUS ? "OV511+" : ov511->bridge == BRG_OV518 ? "OV518" : ov511->bridge == BRG_OV518PLUS ? "OV518+" : "unknown"); out += sprintf(out, "sensor : %s\n", ov511->sensor == SEN_OV6620 ? "OV6620" : ov511->sensor == SEN_OV6630 ? "OV6630" : ov511->sensor == SEN_OV7610 ? "OV7610" : ov511->sensor == SEN_OV7620 ? "OV7620" : ov511->sensor == SEN_OV7620AE ? "OV7620AE" : ov511->sensor == SEN_OV8600 ? "OV8600" : ov511->sensor == SEN_KS0127 ? "KS0127" : ov511->sensor == SEN_KS0127B ? "KS0127B" : ov511->sensor == SEN_SAA7111A ? "SAA7111A" : "unknown"); out += sprintf(out, "packet_size : %d\n", ov511->packet_size); out += sprintf(out, "framebuffer : 0x%p\n", ov511->fbuf); len = out - page; len -= off; if (len < count) { *eof = 1; if (len <= 0) return 0; } else len = count; *start = page + off; return len;}/* /proc/video/ov511/<minor#>/button * * When the camera's button is pressed, the output of this will change from a * 0 to a 1 (ASCII). It will retain this value until it is read, after which * it will reset to zero. * * SECURITY NOTE: Since reading this file can change the state of the snapshot * status, it is important for applications that open it to keep it locked * against access by other processes, using flock() or a similar mechanism. No * locking is provided by this driver. */static int ov511_read_proc_button(char *page, char **start, off_t off, int count, int *eof, void *data){ char *out = page; int len, status; struct usb_ov511 *ov511 = data; if (!ov511 || !ov511->dev) return -ENODEV; status = ov51x_check_snapshot(ov511); out += sprintf(out, "%d", status); if (status) ov51x_clear_snapshot(ov511); len = out - page; len -= off; if (len < count) { *eof = 1; if (len <= 0) return 0; } else { len = count; } *start = page + off; return len;}static void create_proc_ov511_cam(struct usb_ov511 *ov511){ char dirname[4]; if (!ov511_proc_entry || !ov511) return; /* Create per-device directory */ sprintf(dirname, "%d", ov511->vdev.minor); PDEBUG(4, "creating /proc/video/ov511/%s/", dirname); ov511->proc_devdir = create_proc_entry(dirname, S_IFDIR, ov511_proc_entry); if (!ov511->proc_devdir) return; /* Create "info" entry (human readable device information) */ PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname); ov511->proc_info = create_proc_read_entry("info", S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir, ov511_read_proc_info, ov511); if (!ov511->proc_info) return; /* 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); ov511->proc_button = create_proc_read_entry("button", S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir, ov511_read_proc_button, ov511); if (!ov511->proc_button) return; } /* Create "control" entry (ioctl() interface) */ PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname); lock_kernel(); ov511->proc_control = create_proc_entry("control", S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir); if (!ov511->proc_control) { unlock_kernel(); return; } ov511->proc_control->data = ov511; ov511->proc_control->proc_fops = &ov511_control_fops; unlock_kernel();}static void destroy_proc_ov511_cam(struct usb_ov511 *ov511){ char dirname[4]; if (!ov511 || !ov511->proc_devdir) return; sprintf(dirname, "%d", ov511->vdev.minor); /* Destroy "control" entry */ if (ov511->proc_control) { PDEBUG(4, "destroying /proc/video/ov511/%s/control", dirname); remove_proc_entry("control", ov511->proc_devdir); ov511->proc_control = NULL; } /* Destroy "button" entry */ if (ov511->proc_button) { PDEBUG(4, "destroying /proc/video/ov511/%s/button", dirname); remove_proc_entry("button", ov511->proc_devdir); ov511->proc_button = NULL; } /* Destroy "info" entry */ if (ov511->proc_info) { PDEBUG(4, "destroying /proc/video/ov511/%s/info", dirname); remove_proc_entry("info", ov511->proc_devdir); ov511->proc_info = NULL; } /* Destroy per-device directory */ PDEBUG(4, "destroying /proc/video/ov511/%s/", dirname); remove_proc_entry(dirname, ov511_proc_entry); ov511->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 * **********************************************************************/static int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value){ int rc; PDEBUG(5, "0x%02X:0x%02X", reg, value); rc = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 2 /* REG_IO */, USB_TYPE_CLASS | USB_RECIP_DEVICE, 0, (__u16)reg, &value, 1, HZ); if (rc < 0) err("reg write: error %d", rc); return rc;}/* returns: negative is error, pos or zero is data */static int ov511_reg_read(struct usb_device *dev, unsigned char reg){ int rc; unsigned char buffer[1]; rc = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 2 /* REG_IO */, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, 0, (__u16)reg, buffer, 1, HZ); PDEBUG(5, "0x%02X:0x%02X", reg, buffer[0]); if (rc < 0) { err("reg read: error %d", rc); return rc; } else { return buffer[0]; }}/* * Writes bits at positions specified by mask to a 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 ov511_reg_write_mask(struct usb_device *dev, unsigned char reg, unsigned char value, unsigned char mask){ int ret; unsigned char oldval, newval; ret = ov511_reg_read(dev, 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 (ov511_reg_write(dev, reg, newval));}/* Writes multiple (n) values to a single register. Only valid with certain * registers (0x30 and 0xc4 - 0xce). Used for writing 16 and 24-bit values. */static int ov518_reg_write_multi(struct usb_device *dev, unsigned char reg, unsigned char *values, int n){ int rc; PDEBUG(5, "0x%02X:[multiple], n=%d", reg, n); // FIXME if (values == NULL) { err("reg write multiple: NULL buffer"); return -EINVAL; } rc = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 2 /* REG_IO */, USB_TYPE_CLASS | USB_RECIP_DEVICE, 0, (__u16)reg, values, n, HZ); if (rc < 0) err("reg write multiple: error %d", rc); return rc;}static int ov511_upload_quan_tables(struct usb_device *dev){ unsigned char *pYTable = yQuanTable511; unsigned char *pUVTable = uvQuanTable511; unsigned char val0, val1; int i, rc, reg = OV511_OMNICE_Y_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 = ov511_reg_write(dev, reg, val0); if (rc < 0) return rc; } if (ENABLE_UV_QUANTABLE) { val0 = *pUVTable++; val1 = *pUVTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = ov511_reg_write(dev, 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_device *dev){ unsigned char *pYTable = yQuanTable518; unsigned char *pUVTable = uvQuanTable518; unsigned char val0, val1; int i, rc, reg = OV511_OMNICE_Y_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 = ov511_reg_write(dev, reg, val0); if (rc < 0) return rc; } if (ENABLE_UV_QUANTABLE) { val0 = *pUVTable++; val1 = *pUVTable++; val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; rc = ov511_reg_write(dev, reg + OV518_QUANTABLESIZE / 2, val0); if (rc < 0) return rc; } reg++; } 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 ov51x_i2c_write(). Note that this function * always succeeds regardless of whether the sensor is present and working. */static int ov518_i2c_write_internal(struct usb_device *dev, unsigned char reg, unsigned char value){ int rc; PDEBUG(5, "0x%02X:0x%02X", reg, value); /* Select camera register */ rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); if (rc < 0) goto error; /* Initiate 3-byte write cycle */ rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x01); if (rc < 0) goto error; return 0;error: err("ov518 i2c write: error %d", rc); return rc;}/* NOTE: Do not call this function directly! */static int ov511_i2c_write_internal(struct usb_device *dev, 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 = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); if (rc < 0) goto error; /* Initiate 3-byte write cycle */ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01); if (rc < 0) goto error; do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; if ((rc&2) == 0) /* Ack? */ break;#if 0 /* I2C abort */ ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);#endif if (--retries < 0) { err("i2c write retries exhausted"); rc = -1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -