qc-driver.c

来自「Webcam Linux driver for Quickcam」· C语言 代码 · 共 1,813 行 · 第 1/5 页

C
1,813
字号
  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 + =
减小字号Ctrl + -
显示快捷键?