📄 qc-driver.c
字号:
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! */int qc_stv_set(struct quickcam *qc, unsigned short reg, unsigned char val){ int ret; if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_set(qc=%p,reg=0x%04X,val=%u)",qc,(int)reg,(int)val); TEST_BUGR(qc==NULL); if (sizeof(qc->dmabuf)<1) BUG(); qc_i2c_wait(qc); /* Wait until no pending commands from qc_i2c_* */ qc->dmabuf[0] = val; ret = usb_control_msg(qc->dev, usb_sndctrlpipe(qc->dev, 0), 0x04, /* Request */ 0x40, /* RequestType */ reg, 0, /* Value, Index */ qc->dmabuf, 1, 3*HZ); if ((qcdebug&QC_DEBUGERRORS || qcdebug&QC_DEBUGLOGIC) && ret<0) PDEBUG("Failed qc_stv_set()=%i", ret); if (ret<0) return ret; return 0;}/* }}} *//* {{{ [fold] int qc_stv_get(struct quickcam *qc, unsigned short reg) *//* * Read one byte register in the STV-chip. qc_i2c_init() must be called first! * Return the unsigned register value or negative error code on error. */int qc_stv_get(struct quickcam *qc, unsigned short reg){ int ret; if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_get(qc=%p,reg=0x%04X)",qc,(int)reg); TEST_BUGR(qc==NULL); if (sizeof(qc->dmabuf)<1) BUG(); qc_i2c_wait(qc); /* Wait until no pending commands from qc_i2c_* */ ret = usb_control_msg(qc->dev, usb_rcvctrlpipe(qc->dev, 0), 0x04, /* Request */ 0xC0, /* RequestType */ reg, 0, /* Value, Index */ qc->dmabuf, 1, 3*HZ); if ((qcdebug&QC_DEBUGERRORS || qcdebug&QC_DEBUGLOGIC) && ret<0) PDEBUG("Failed qc_stv_get()=%i", ret); if (ret<0) return ret; if (qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_get(reg=0x%04X)=%02X", reg, qc->dmabuf[0]); return qc->dmabuf[0];}/* }}} *//* {{{ [fold] int qc_stv_setw(struct quickcam *qc, unsigned short reg, unsigned short val) *//* * Set two byte register in the STV-chip. qc_i2c_init() must be called first! * "w" means either "word" or "wide", depending on your religion ;) */int qc_stv_setw(struct quickcam *qc, unsigned short reg, unsigned short val){ int ret; if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_setw(qc=%p,reg=0x%04X,val=%i)",qc,(int)reg,(int)val); TEST_BUGR(qc==NULL); if (sizeof(qc->dmabuf)<2) BUG(); qc_i2c_wait(qc); qc->dmabuf[0] = val & 0xFF; qc->dmabuf[1] = (val >> 8) & 0xFF; ret = usb_control_msg(qc->dev, usb_sndctrlpipe(qc->dev, 0), 0x04, 0x40, reg, 0, qc->dmabuf, 2, 3*HZ); if ((qcdebug&QC_DEBUGERRORS || qcdebug&QC_DEBUGLOGIC) && ret<0) PDEBUG("Failed qc_stv_setw()=%i", ret); if (ret<0) return ret; return 0;}/* }}} *//* {{{ [fold] void qc_hsv2rgb(s16 hue, u16 sat, u16 val, int *red, int *green, int *blue) *//* Convert HSI (hue, saturation, intensity) to RGB (red, green, blue). * All input and output values are 0..65535. * Hue is actually signed, so it is -32768..32767, but this is equivalent * since it is the angle around full circle (0=Red, 21845=Green, 43690=Blue). * Based on libgimp, converted to 16.16 fixed point by tuukkat. */void qc_hsv2rgb(s16 hue, u16 sat, u16 val, int *red, int *green, int *blue){ unsigned int segment, valsat; signed int h = (u16)hue; unsigned int s = (sat<32768) ? 0 : (sat-32768)*2; /* 32768 or less = no saturation */ unsigned int v = val; /* value = intensity */ unsigned int p;#if 1 /* Make common case more efficient */ if (s == 0) { *red = v; *green = v; *blue = v; return; }#endif segment = (h + 10923) & 0xFFFF; segment = segment*3 >> 16; /* 0..2: 0=R, 1=G, 2=B */ hue -= segment * 21845; /* -10923..10923 */ h = hue; h *= 3; valsat = v*s >> 16; /* 0..65534 */ p = v - valsat; if (h>=0) { unsigned int t = v - (valsat * (32769 - h) >> 15); switch (segment) { default: PDEBUG("hsi2rgb: this can never happen!"); case 0: /* R-> */ *red = v; *green = t; *blue = p; break; case 1: /* G-> */ *red = p; *green = v; *blue = t; break; case 2: /* B-> */ *red = t; *green = p; *blue = v; break; } } else { unsigned int q = v - (valsat * (32769 + h) >> 15); switch (segment) { default: PDEBUG("hsi2rgb: this can never happen!"); case 0: /* ->R */ *red = v; *green = p; *blue = q; break; case 1: /* ->G */ *red = q; *green = v; *blue = p; break; case 2: /* ->B */ *red = p; *green = q; *blue = v; break; } } //PDEBUG("hue=%i sat=%i val=%i segment=%i h=%i r=%i g=%i b=%i",hue,sat,val, segment,h, *red,*green,*blue);}/* }}} *//* {{{ [fold] int qc_lock(struct quickcam *qc) *//* Takes a lock on quickcam_list_lock and verifies that the given qc is available *//* Returns 0 on success in which case the lock must be freed later or negative error code */static int qc_lock(struct quickcam *qc){ struct quickcam *q; if (down_interruptible(&quickcam_list_lock)) return -ERESTARTSYS; /* Search for the device in the list of plugged quickcams (this prevents a race condition) */ list_for_each_entry(q, &quickcam_list, list) { if (q == qc) break; /* Found it? */ } if (q != qc) { PDEBUG("can not find the device to open"); up(&quickcam_list_lock); return -ENODEV; } return 0;}/* }}} *//* }}} *//* {{{ [fold] **** qc_i2c: I2C URB messaging routines (qc_i2c_*) ************* *//* We have here a quite typical producer-consumer scheme: * URB interrupt handler routine consumes i2c data, while * kernel mode processes create more of it. * Ref: Linux Device Drivers, Alessandro Rubini et al, 2nd edition, pg. 279 * "Using Circular Buffers" */static const int qc_i2c_maxbufsize = 0x23;/* {{{ [fold] (private) qc_i2c_nextpacket(struct quickcam *qc) *//* Fill URB and submit it, if there are more data to send * Consume data from "commands" array. May be called from interrupt context. * Return standard error code. */static int qc_i2c_nextpacket(struct quickcam *qc){ struct qc_i2c_data *id = &qc->i2c_data; struct urb *urb = id->urb; u8 *tb = urb->transfer_buffer, flags; struct usb_ctrlrequest *cr = (struct usb_ctrlrequest *)urb->setup_packet; unsigned int newtail, length, regnum, i, j; signed int r; if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_nextpacket(quickcam=%p), tail=%i, head=%i, interrupt=%i",qc,id->tail,id->head,(int)in_interrupt()); IDEBUG_TEST(*id); if (!qc->connected) { /* Device was disconnected, cancel all pending packets and return */ id->tail = id->head = id->newhead = 0; id->packets = 0; return -ENODEV; } newtail = id->tail; /* First data to fetch */ if (id->packets<=1 && newtail==id->head) { /* packets==0 or 1: no extra URB need to be scheduled */ if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("No more control URBs to send"); r = 0; goto nourbs; } if (id->packets<=1) { /* Collect data from circular buffer to URB transfer buffer */ /* Now id->tail!=id->head: there's at least one packet to send */ TEST_BUGR(newtail==id->head); id->packets = 1; if (GET_PRODUCTID(qc)==0x0850) id->packets = 2; regnum = 0x0400; length = qc_i2c_maxbufsize; i = 0; /* Transfer buffer position */ if (!(id->commands[newtail].flags & I2C_FLAG_WORD)) { /* Normal byte-wide register write */ if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("Setting byte-wide registers"); do { tb[i] = id->commands[newtail].regnum; tb[i+0x10] = id->commands[newtail].loval; flags = id->commands[newtail].flags; i++; newtail = (newtail + 1) % I2C_MAXCOMMANDS; /* Next data to fetch */ if (flags & I2C_FLAG_BREAK) break; /* Start new packet */ if (newtail == id->head) break; /* No more data? */ if (i > 0x0F) break; /* Transfer buffer full? */ if (id->commands[newtail].flags & I2C_FLAG_WORD) break; } while (TRUE);/*if (flags&I2C_FLAG_BREAK) PDEBUG("breaking!!!!!!!!!!");{int mm;for(mm=0;mm<i;mm++) printk("%02X=%02X ",tb[mm],tb[mm+0x10]);printk("\n");}*/ for (j=i; j<0x10; j++) tb[j+0x10] = 0; /* Zero out unused register values just to be sure */ } else { /* Two-byte-wide register write (used in Photobit) */ if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("Setting word-wide registers"); do { tb[i] = id->commands[newtail].regnum; tb[i*2+0x10] = id->commands[newtail].loval; tb[i*2+0x11] = id->commands[newtail].hival; flags = id->commands[newtail].flags; i++; newtail = (newtail + 1) % I2C_MAXCOMMANDS; /* Next data to fetch */ if (flags & I2C_FLAG_BREAK) break; /* Start new packet */ if (newtail == id->head) break; /* No more data? */ if (i > 0x07) break; /* Transfer buffer full? */ if (!(id->commands[newtail].flags & I2C_FLAG_WORD)) break; } while (TRUE); for (j=i*2; j<0x10; j++) tb[j+0x10] = 0; /* Zero out unused register values just to be sure */ } for (j=i; j<0x10; j++) tb[j] = 0; /* Zero out unused register addresses just to be sure */ tb[0x20] = qc->sensor_data.sensor->i2c_addr; tb[0x21] = i-1; /* Number of commands to send - 1 */ tb[0x22] = 1; /* Write cmd, 03 would be read. */ id->tail = newtail; if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("sending i2c packet, cmds=%i, reg0=%02X, val0=%02X",tb[0x21]+1,tb[0],tb[0x10]); } else { /* id->packets==2: send extra packet for QuickCam Web */ if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("sending finalization packet"); id->packets = 1; regnum = 0x1704; length = 1; tb[0] = 1; } urb->dev = qc->dev; /* 2.4.x zeroes urb->dev after submission */ urb->pipe = usb_sndctrlpipe(qc->dev, 0); urb->transfer_buffer_length = length; cr->wValue = cpu_to_le16(regnum); cr->wLength = cpu_to_le16(length); r = usb_submit_urb(urb,GFP_ATOMIC); CHECK_ERROR(r<0, nourbs, "Failed qc_i2c_nextpacket()=%i", r); return 0;nourbs: id->packets = 0; /* No more URBs are scheduled */ wake_up(&id->wq); //FIXME: race condition: now packets=0, so id could be freed and wake_up do oops return r;}/* }}} *//* {{{ [fold] (private) qc_i2c_handler(struct urb *urb) *//* This is URB completion handler and is called in interrupt context. * For each submitted URB, this function is guaranteed to be called exactly once. * This function may not be called reentrantly for the same qc (should be ok, IRQs don't nest). * It will resubmit the same URB, if * - The previous URB completed without error * - Camera is still connected (qc->connected == TRUE) * - There is still commands to be sent in commands buffer or pid=0x850 and finalization packet is not yet sent. */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)static void qc_i2c_handler(struct urb *urb, struct pt_regs *ptregs)#elsestatic void qc_i2c_handler(struct urb *urb)#endif{ struct quickcam *qc = urb->context; if (qcdebug&QC_DEBUGINTERRUPTS) PDEBUG("[INTR] qc_i2c_handler(urb=%p)",urb); TEST_BUG(urb==NULL); TEST_BUG(qc==NULL); IDEBUG_TEST(qc->i2c_data); if (urb->status<0) { switch (urb->status) { default: /* Seen here: ECONNABORTED 103 Software caused connection abort */ PRINTK(KERN_ERR,"Unhandled control URB error %i",urb->status); case -EPROTO: /* Bitstuff error or unknown USB error */ case -EILSEQ: /* CRC mismatch */ case -ETIMEDOUT: /* Transfer timed out */ case -EREMOTEIO: /* Short packet detected */ case -EPIPE: /* Babble detect or endpoint stalled */ /* We could try resubmitting the URB here */ case -ENOENT: /* URB was unlinked */ case -ENODEV: /* Device was removed */ case -ECONNRESET: /* Asynchronous unlink, should not happen */ PRINTK(KERN_ERR,"Control URB error %i",urb->status); qc->i2c_data.packets = 0; /* Don't schedule more URBs */ wake_up(&qc->i2c_data.wq); return; } } qc_i2c_nextpacket(qc);}/* }}} *//* {{{ [fold] qc_i2c_flush(struct quickcam *qc) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -