📄 qc-driver.c
字号:
107, 108, 110, 111, 113, 114, 115, 117, 118, 120, 121, 123, 124, 126, 127, 128, 130, 131, 133, 134, 136, 137, 139, 140, 142, 143, 145, 146, 148, 149, 151, 152, 154, 156, 157, 159, 160, 162, 163, 165, 166, 168, 170, 171, 173, 174, 176, 178, 179, 181, 182, 184, 186, 187, 189, 190, 192, 194, 195, 197, 199, 200, 202, 204, 205, 207, 209, 210, 212, 214, 215, 217, 219, 221, 222, 224, 226, 227, 229, 231, 233, 234, 236, 238, 240, 241, 243, 245, 247, 248, 250, 252, 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, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};#endifstatic 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));}void qc_msleep(unsigned long usec){ wait_queue_head_t wq; init_waitqueue_head(&wq); interruptible_sleep_on_timeout(&wq, usec*(HZ/1000));}/* }}} *//* {{{ [fold] int qc_stv_set(struct quickcam *qc, unsigned short reg, unsigned char val) *//* * Set one byte register in the STV-chip. */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); ret = usb_control_msg(qc->dev, usb_sndctrlpipe(qc->dev, 0), 0x04, /* Request */ 0x40, /* RequestType */ reg, 0, /* Value, Index */ &val, 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, unsigned char *val) *//* * Read one byte register in the STV-chip. * Return the unsigned register value or negative error code on error. */int qc_stv_get(struct quickcam *qc, unsigned short reg, unsigned char *val){ 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); ret = usb_control_msg(qc->dev, usb_rcvctrlpipe(qc->dev, 0), 0x04, /* Request */ 0xC0, /* RequestType */ reg, 0, /* Value, Index */ val, 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, *val); return 0;}int qc_stv_getw(struct quickcam *qc, unsigned short reg, __le16 *val){ 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); ret = usb_control_msg(qc->dev, usb_rcvctrlpipe(qc->dev, 0), 0x04, /* Request */ 0xC0, /* RequestType */ reg, 0, /* Value, Index */ val, 2, 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_getw(reg=0x%04X)=%02X", reg, le16_to_cpu(*val)); return 0;}/* }}} *//* {{{ [fold] int qc_stv_setw(struct quickcam *qc, unsigned short reg, unsigned short val) *//* * Set two byte register in the STV-chip. * "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); ret = usb_control_msg(qc->dev, usb_sndctrlpipe(qc->dev, 0), 0x04, 0x40, reg, 0, &val, 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;}/* }}} */int qc_i2c_wait(struct quickcam *qc){ // just a dummy function for all old calls return 0;}int qc_int_abort(struct quickcam *qc){ struct qc_int_data *id = &qc->int_data; int r = 0; if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_int_abort(quickcam=%p)",qc); TEST_BUGR(in_interrupt()); TEST_BUGR(qc==NULL); IDEBUG_TEST(*id); /* This is to abort INT URBs with timeout. I don't see any other * good way to be sure it won't be re-submitted again. */ id->abort_polling = 1; if(NOT_POISONED_PTR(id->urb)) { /* r = qc_unlink_urb_sync(id->urb); if(r<0) PDEBUG("qc_int_abort: error unlink_urb %d", r); */ usb_kill_urb(id->urb);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* make sure interrupt is executed one last time. Just in case * polling already was set to 0 by misstake */ wait_ms(100);#endif r = wait_event_interruptible(id->wq, id->polling==0); if(r<0) PDEBUG("qc_int_abort: wait_event_interruptible returned %d", r); } return 0;}#ifndef DISABLE_INT_URBS#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)static void qc_int_handler(struct urb *urb, struct pt_regs *ptregs)#elsestatic void qc_int_handler(struct urb *urb)#endif{ struct quickcam *qc = urb->context; struct qc_int_data *id; int r = 0; if (qcdebug&QC_DEBUGINTERRUPTS) PDEBUG("[INTR] qc_int_handler(urb=%p)",urb); TEST_BUG(urb==NULL); TEST_BUG(qc==NULL); IDEBUG_TEST(qc->int_data); id = &qc->int_data; if (qcdebug&QC_DEBUGLOGIC) { PDEBUG("INT URB status=%i tb_length=%i act_length=%i interval=%d frame=%d data=%02X", urb->status, urb->transfer_buffer_length, urb->actual_length, urb->interval, urb->start_frame, ((unsigned char *)urb->transfer_buffer)[0]); } if(qc->dev == NULL) { /* if we have a postponed exit, this will exit this function */ PDEBUG("qc_int_handler: qc->dev == NULL"); goto end2; } if (urb->status<0) { urb->actual_length = 0; // reset length urb->transfer_buffer_length = 1; switch (urb->status) { case -ECONNABORTED: // 2.4 kernels return this after timeout break; case -ESHUTDOWN: /* Shutdown */ if ((jiffies-int_init_jiffy) < HZ/4) { PDEBUG("Very quick shutdown in int_handler !!"); PDEBUG("The driver probably failed to initialize the usb-interface."); PDEBUG("Please reload module: rmmod quickcam ; modprobe quickcam"); } case -ECONNRESET: /* Asynchronous unlink, should not happen */ case -ENODEV: /* Device was removed */ case -ENOENT: /* URB was unlinked */ goto endpolling; default: PDEBUG("Unhandled INT URB error %i",urb->status); case -EPROTO: /* Bitstuff error or unknown USB error */ case -EILSEQ: /* CRC mismatch (seen when unplugging camera and at postponed exit) */ case -ETIMEDOUT: /* Transfer timed out */ case -EREMOTEIO: /* Short packet detected */ case -EPIPE: /* Babble detect or endpoint stalled */ /* We could try resubmitting the URB here */ id->errorcount++;#if 1 PDEBUG("INT URB error status=%i tb_length=%i act_length=%i interval=%d frame=%d data=%02X", urb->status, urb->transfer_buffer_length, urb->actual_length, urb->interval, urb->start_frame, ((unsigned char *)urb->transfer_buffer)[0]);#endif#if 0 goto endpolling;#else urb->actual_length = 0; urb->transfer_buffer_length = 1; if(id->abort_polling) { PDEBUG("end due to abort_polling"); goto endpolling; } if (qcdebug&QC_DEBUGLOGIC) PDEBUG("submit_urb called()");#if 0 if(urb->dev != qc->dev) { PDEBUG("urb->dev != qc->dev %p %p", urb->dev, qc->dev); urb->dev = qc->dev; }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -