📄 qc-driver.c
字号:
/* Start of file *//* {{{ [fold] Comments *//* * qc-usb, Logitech QuickCam video driver with V4L support * Derived from qce-ga, linux V4L driver for the QuickCam Express and Dexxa QuickCam * * qc-driver.c - main driver part * * Copyright (C) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland * Copyright (C) 2002,2003 Tuukka Toivonen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *//* Cam variations of Logitech QuickCam: P/N 861037: Sensor HDCS1000 ASIC STV0600 P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 ("QuickCam Express") P/N 861055: Sensor ST VV6410 ASIC STV0610 ("LEGO cam") P/N 861075-0040: Sensor HDCS1000 ASIC P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 (Dexxa WebCam USB) P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 ("QuickCam Web") For any questions ask qce-ga-devel@lists.sourceforge.net - about code qce-ga-discussion@lists.sourceforge.net - about usage*//* }}} *//* {{{ [fold] Includes */#ifdef NOKERNEL#include "quickcam.h"#else#include <linux/quickcam.h>#endif#include <linux/module.h>#include "qc-memory.h"#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)#include <linux/slab.h>#else#include <linux/malloc.h>#endif#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/list.h>#include <linux/mm.h>#include <linux/proc_fs.h>#include <linux/smp_lock.h>#include <linux/vmalloc.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/page.h>#include <linux/capability.h>#include <linux/poll.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)#include <linux/moduleparam.h>#endif/* }}} *//* {{{ [fold] Module parameters */MODULE_PARM_DESC(qcdebug, "Sets the debug output (bitfield)");MODULE_PARM(qcdebug, "i");int qcdebug = DEBUGLEVEL;MODULE_PARM_DESC(keepsettings, "Keep picture settings across one open to another (0-1)");MODULE_PARM(keepsettings, "i");static int keepsettings = 0;MODULE_PARM_DESC(settle, "Maximum number of frames to wait picture brightness to settle (0-255)");MODULE_PARM(settle, "i");static int settle = 0;/* Subsampling is used to allow higher scan rate with smaller images. */MODULE_PARM_DESC(subsample, "Sets subsampling (0-1)");MODULE_PARM(subsample, "i");static int subsample = 0; /* normal or sub-sample (sub-sample to increase the speed) */MODULE_PARM_DESC(compress, "Enable compressed mode (0-1)");MODULE_PARM(compress, "i");static int compress = 0; /* Enable compressed mode if available (higher framerate) */MODULE_PARM_DESC(frameskip, "How frequently capture frames (0-10)");MODULE_PARM(frameskip, "i");static int frameskip = 0;MODULE_PARM_DESC(quality, "Sets the picture quality (0-5)");MODULE_PARM(quality, "i");static int quality = 5; /* 5 = generalized adjustable Pei-Tam method */MODULE_PARM_DESC(adaptive, "Automatic adaptive brightness control (0-1)");MODULE_PARM(adaptive, "i");static int adaptive = 1;MODULE_PARM_DESC(equalize, "Equalize image (0-1)");MODULE_PARM(equalize, "i");static int equalize = 0; /* Disabled by default */MODULE_PARM_DESC(userlut, "Apply user-specified lookup-table (0-1)");MODULE_PARM(userlut, "i");static int userlut = 0; /* Disabled by default */MODULE_PARM_DESC(retryerrors, "Retry if image capture fails, otherwise return error code (0-1)");MODULE_PARM(retryerrors, "i");static int retryerrors = 1; /* Enabled by default *//* Bug in Xvideo(?): if the width is not divisible by 8 and Xvideo is used, the frame is shown wrongly */MODULE_PARM_DESC(compatible, "Enable workaround for bugs in application programs (bitfield)");MODULE_PARM(compatible, "i");static int compatible = 0; /* Disabled by default */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,5)MODULE_PARM_DESC(video_nr, "Set videodevice number (/dev/videoX)");MODULE_PARM(video_nr,"i");/* video_nr option allows to specify a certain /dev/videoX device *//* (like /dev/video0 or /dev/video1 ...) *//* for autodetect first available use video_nr=-1 (defaultvalue) */static int video_nr = -1;#endif/* }}} *//* {{{ [fold] Miscellaneous data */#ifndef MODULE_LICENSE /* Appeared in 2.4.10 */#ifdef MODULE#define MODULE_LICENSE(license) \static const char __module_license[] __attribute__((section(".modinfo"))) = \ "license=" license#else#define MODULE_LICENSE(license)#endif#endifMODULE_SUPPORTED_DEVICE("video");MODULE_DESCRIPTION("Logitech QuickCam USB driver");MODULE_AUTHOR("See README");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;static const int min_framewidth = 32; /* Minimum image size we allow delivering to user application */static const int min_frameheight = 32;static const char qc_proc_name[] = "video/quickcam";#define qc_name (&qc_proc_name[6])static struct usb_device_id qc_device_table[] = { { USB_DEVICE(0x046D, 0x0840) }, /* QuickCam Express */ { USB_DEVICE(0x046D, 0x0850) }, /* LEGO cam / QuickCam Web */ { USB_DEVICE(0x046D, 0x0870) }, /* Dexxa WebCam USB */ { }};MODULE_DEVICE_TABLE(usb, qc_device_table);extern const struct qc_sensor qc_sensor_pb0100;extern const struct qc_sensor qc_sensor_hdcs1000;extern const struct qc_sensor qc_sensor_hdcs1020;extern const struct qc_sensor qc_sensor_vv6410;static const struct qc_sensor *sensors[] = { &qc_sensor_hdcs1000, &qc_sensor_hdcs1020, &qc_sensor_pb0100, &qc_sensor_vv6410,};static LIST_HEAD(quickcam_list); /* Linked list containing all QuickCams */static DECLARE_MUTEX(quickcam_list_lock); /* Always lock first quickcam_list_lock, then qc->lock *//* Default values for user-specified lookup-table; may be overwritten by user */static unsigned char userlut_contents[QC_LUT_SIZE] = { /* Red */ 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 220, 220, 221, 221, /* Green */ 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 245, 245, 246, 246, /* Blue */ 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};static void qc_usb_exit(struct quickcam *qc);static int qc_capt_init(struct quickcam *qc);static void qc_capt_exit(struct quickcam *qc);static int qc_capt_get(struct quickcam *qc, unsigned char **frame);static int qc_isoc_init(struct quickcam *qc);static void qc_isoc_exit(struct quickcam *qc);/* }}} *//* {{{ [fold] **** Miscellaneous functions ************************************** */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)/* {{{ [fold] usb_kill_urb(struct urb *urb) *//* Unlink URB synchronously (usb_unlink_urb may not be synchronous). * Note: at this moment the URB completion handler must not resubmit the same URB. */static void qc_usb_kill_urb(struct urb *urb) { int r; while ((r=usb_unlink_urb(urb)) == -EBUSY) { /* The URB is not anymore linked (status!=-EINPROGRESS) but * usb_unlink_urb() was asynchronous and URB's completion handler still will run */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout( (HZ/100)==0 ? 1 : HZ/100); } /* if (r!=-EBUSY), * usb_unlink_urb() called synchronously the completion handler and * there's no need to wait or anything else */ if (r) PDEBUG("qc_usb_kill_urb(%p): r=%i", urb, r);}#undef usb_kill_urb#define usb_kill_urb(urb) qc_usb_kill_urb(urb)/* }}} */#endif/* {{{ [fold] qc_usleep(long usec) */void qc_usleep(unsigned long usec){ wait_queue_head_t wq; init_waitqueue_head(&wq); interruptible_sleep_on_timeout(&wq, usec*HZ/1000000);}/* }}} *//* {{{ [fold] int qc_get_i2c(struct quickcam *qc, const struct qc_sensor *sensor, int reg) *//* Read a sensor byte or word wide register value via STV0600 I2C bus * qc_i2c_init() must be called first! */int qc_get_i2c(struct quickcam *qc, const struct qc_sensor *sensor, int reg){ struct usb_device *dev = qc->dev; int ret; if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_get_i2c(qc=%p,sensor=%p,reg=0x%04X)",qc,sensor,reg); TEST_BUGR(dev==NULL); if (sizeof(qc->dmabuf)<35) BUG(); /* We need here extra write to the STV register before reading the I2C register */ /* Also wait until there are no pending control URB requests */ if ((ret = qc_stv_set(qc, STV_REG23, sensor->reg23))<0) goto fail; memset(qc->dmabuf, 0, 35); qc->dmabuf[0] = reg; qc->dmabuf[0x20] = sensor->i2c_addr; qc->dmabuf[0x21] = 0; /* 0+1 = 1 value, one byte or word wide register */ qc->dmabuf[0x22] = 3; /* Read I2C register */ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x04, 0x40, 0x1400, 0, /* Write I2C register address, 35 bytes */ qc->dmabuf, 0x23, 3*HZ); if (ret < 0) goto fail; ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x04, 0xC0, 0x1410, 0, /* Read register contents from I2C, 1 or 2 bytes */ qc->dmabuf, sensor->length_id, 3*HZ); if (ret < 0) goto fail; ret = qc->dmabuf[0]; if (sensor->length_id>1) ret |= qc->dmabuf[1]<<8; /* Assume LSB is always first from data received via USB */ if (qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_get_i2c(reg=0x%04X) = %04X", reg, ret); return ret;fail: PDEBUG("qc_get_i2c failed, code=%i",ret); return ret;}/* }}} *//* {{{ [fold] int qc_stv_set(struct quickcam *qc, unsigned short reg, unsigned char val) *//* * Set one byte register in the STV-chip. qc_i2c_init() must be called first! */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -