⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qc-driver.c

📁 在Linux下用于webeye的摄像头的驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
 * and set buf to point to the frame. If error happens, * return standard Linux negative error number. * qc_frame_free() must be called after the frame is not needed anymore. * qc->lock must be acquired when entering this routine * (it may release it temporarily and sleep). */static int qc_frame_get(struct quickcam *qc, unsigned char **buf){	struct qc_frame_data *fd = &qc->frame_data;	int ret;	TEST_BUGR(qc==NULL || fd==NULL || fd->tail_in_use);	TEST_BUGR(in_interrupt());	IDEBUG_TEST(*fd);	/* Wait until the next frame is available */	if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_get/consume(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head);	fd->waiting++;	if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_frame_get() : %i", qc, sem_getcount(&qc->lock));	up(&qc->lock);					/* Release lock while waiting */	ret = wait_event_interruptible(fd->wq, fd->head!=fd->tail || fd->exiting);	//FIXME:What if we get -ERESTARTSYS?	if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down(%p) in qc_frame_get() : %i", qc, sem_getcount(&qc->lock));	down(&qc->lock);	if (!ret) {		if (!fd->exiting) {			unsigned int t;			spin_lock(&fd->tail_lock);			fd->tail_in_use = TRUE;			t = fd->tail;			spin_unlock(&fd->tail_lock);			if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_get/consume(qc=%p,tail=%i,head=%i,tail->rawdatalen=%i), got frame",qc,t,fd->head,fd->buffers[t].rawdatalen);			*buf = fd->rawdatabuf + t*FRAME_DATASIZE;			ret  = fd->buffers[t].rawdatalen;		} else {			ret = -ENODATA;		}	}	fd->waiting--;	fd->lost_frames = 0;	if (ret<0 && (qcdebug&(QC_DEBUGERRORS|QC_DEBUGFRAME))) PDEBUG("failed qc_frame_get()=%i",ret);	return ret;}/* }}} *//* {{{ [fold] qc_frame_free(struct quickcam *qc) *//* Free up the last frame returned from qc_frame_get() (it must be called first) */static inline void qc_frame_free(struct quickcam *qc){	struct qc_frame_data *fd = &qc->frame_data;	TEST_BUG(qc==NULL || fd==NULL);	TEST_BUG(in_interrupt());	TEST_BUG(fd->head==fd->tail);			/* The current fd->tail is not available to be freed! */	IDEBUG_TEST(*fd);	if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_free/consume(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head);	/* Free up previous frame and advance to next */	spin_lock(&fd->tail_lock);	fd->tail_in_use = FALSE;	fd->tail = (fd->tail + 1) % FRAME_BUFFERS;	spin_unlock(&fd->tail_lock);}/* }}} *//* {{{ [fold] qc_frame_test(struct quickcam *qc) *//* Return TRUE if next frame is immediately available, FALSE otherwise. */static inline Bool qc_frame_test(struct quickcam *qc){	struct qc_frame_data *fd = &qc->frame_data;	IDEBUG_TEST(*fd);	if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_test/consume(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head);	return fd->head != fd->tail;}/* }}} *//* Producer routines, called from interrupt context *//* {{{ [fold] qc_frame_begin(struct quickcam *qc) *//* Begin capturing next frame from camera. If buffer is full, the frame will be lost */static void qc_frame_begin(struct quickcam *qc){	struct qc_frame_data *fd = &qc->frame_data;	int framesize, h;	TEST_BUG(qc==NULL || fd==NULL);	IDEBUG_TEST(*fd);	if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_begin/produce(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head);	if (fd->exiting) return;	TEST_BUG(fd->rawdatabuf==NULL);	h = fd->head;	fd->buffers[h].rawdatalen = 0;	/* Use sensor information to get the framesize (i.e. how much we expect to receive bytes per image) */	/* FIXME: should compute data size differently in compressed mode */	framesize = qc->sensor_data.width * qc->sensor_data.height;	fd->maxrawdatalen = MIN(framesize, FRAME_DATASIZE);}/* }}} *//* {{{ [fold] qc_frame_add(struct quickcam *qc, unsigned char *data, int datalen) *//* Store more data for a frame, return nonzero if too much data or other error */static int qc_frame_add(struct quickcam *qc, unsigned char *data, int datalen){	struct qc_frame_data *fd = &qc->frame_data;	int h = fd->head;	int bytes;	TEST_BUGR(qc==NULL || fd==NULL);	IDEBUG_TEST(*fd);	TEST_BUGR(fd->rawdatabuf==NULL);	if (fd->maxrawdatalen <= fd->buffers[h].rawdatalen) {		if (qcdebug&QC_DEBUGERRORS) PDEBUG("buffer disabled, maxrawdatalen=%i rawdatalen=%i datalen=%i",fd->maxrawdatalen,fd->buffers[h].rawdatalen, datalen);		return -EBUSY;	}	bytes = MIN(datalen, fd->maxrawdatalen - fd->buffers[h].rawdatalen);	memcpy(fd->rawdatabuf + h*FRAME_DATASIZE + fd->buffers[h].rawdatalen, data, bytes);	fd->buffers[h].rawdatalen += bytes;	if (bytes < datalen) {		if (qcdebug&QC_DEBUGERRORS) PRINTK(KERN_ERR,"out of buffer space by %i, maxrawdatalen=%i rawdatalen=%i datalen=%i", datalen-bytes,fd->maxrawdatalen,fd->buffers[h].rawdatalen, datalen);		return -ENOSPC;	}	return 0;}/* }}} *//* {{{ [fold] qc_frame_end(struct quickcam *qc) *//* Finished capturing most recent frame from camera *//* (may be premature end, in which case some data is missing) */static void qc_frame_end(struct quickcam *qc){	static const int minrawdatalen = 32*32;	/* If frame length is less than this many bytes, discard it */	struct qc_frame_data *fd = &qc->frame_data;	unsigned int t, h;	Bool lost_frame;	TEST_BUG(qc==NULL || fd==NULL);	h = fd->head;	if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_end/produce(qc=%p,tail=%i,head=%i), got %i bytes",qc,fd->tail,h,fd->buffers[h].rawdatalen);	IDEBUG_TEST(*fd);	fd->maxrawdatalen = 0;			/* Stop frame data capturing */#if DUMPDATA	PDEBUG("frame_end: got %i bytes", fd->buffers[h].rawdatalen);#endif	if (fd->buffers[h].rawdatalen < minrawdatalen) {		/* No enough data in buffer, don't advance index */		if (qcdebug&QC_DEBUGERRORS) PDEBUG("discarding frame with only %u bytes", fd->buffers[h].rawdatalen);		return;	}	h = (h + 1) % FRAME_BUFFERS;		/* Select next frame buffer to fill */	lost_frame = FALSE;	spin_lock(&fd->tail_lock);	t = fd->tail;	if (t == h) {		lost_frame = TRUE;		/* FIXME: the below should work fine for two buffers, but not so well for more. It should be possible		 * to drop oldest frame even when the current tail is in use. */		if (fd->tail_in_use) {			/* Can not drop the oldest frame, it is in use. Drop the newest frame */			h = (h + FRAME_BUFFERS - 1) % FRAME_BUFFERS;		/* Decrease head by one back to the original */			if (qcdebug&QC_DEBUGFRAME) PDEBUG("dropping newest frame");		} else {			/* Drop the oldest frame */			fd->tail = (t + 1) % FRAME_BUFFERS;			/* Drop the oldest frame away */			if (qcdebug&QC_DEBUGFRAME) PDEBUG("dropping oldest frame");		}	}	spin_unlock(&fd->tail_lock);	if (lost_frame) {		if (qcdebug&QC_DEBUGCOMMON || qcdebug&QC_DEBUGFRAME) PRINTK(KERN_NOTICE,"frame lost");		fd->lost_frames++;		if (fd->lost_frames > 10) {			/* Here we should call qc_isoc_stop() to stop isochronous			 * streaming since the application is clearly not reading frames at all.			 * However, we are now in interrupt context but qc_isoc_stop() has			 * to be in process context... so we can't do that.			 * FIXME: add tasklet/bottomhalf/whatever needed to do it.			 */			if (qcdebug&QC_DEBUGFRAME) PDEBUG("too many lost frames: %i", fd->lost_frames);		}	}	fd->head = h;	wake_up(&fd->wq);}/* }}} *//* {{{ [fold] qc_frame_flush(struct quickcam *qc)  *//* Reject the current data already captured into buffer and end frame */void qc_frame_flush(struct quickcam *qc){	struct qc_frame_data *fd = &qc->frame_data;	unsigned int h = fd->head;	TEST_BUG(qc==NULL || fd==NULL);	IDEBUG_TEST(*fd);	if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_flush/produce(qc=%p,tail=%i,head=%i), flush %i bytes",qc,fd->tail,h,fd->buffers[h].rawdatalen);	fd->buffers[h].rawdatalen = 0;		/* Empty buffer */	fd->maxrawdatalen = 0;			/* Stop frame data capturing */}/* }}} *//* }}} *//* {{{ [fold] **** qc_stream: USB datastream processing functions *************** *//* {{{ [fold] qc_stream_init(struct quickcam *qc) *//* Initialize datastream processing */static int qc_stream_init(struct quickcam *qc){	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_stream_init(quickcam=%p)",qc);	qc->stream_data.capturing = FALSE;	qc->stream_data.frameskip = qc->settings.frameskip;	IDEBUG_INIT(qc->stream_data);	return 0;}/* }}} *//* {{{ [fold] qc_stream_exit(struct quickcam *qc) *//* Stop datastream processing, after this qc_stream_add should not be called */static void qc_stream_exit(struct quickcam *qc){	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_stream_exit(quickcam=%p)",qc);	if (qc->stream_data.capturing)		qc_frame_end(qc);	IDEBUG_EXIT(qc->stream_data);}/* }}} *//* {{{ [fold] qc_stream_error(struct quickcam *qc) *//* This is called when there are data lost due to errors in the stream */static void qc_stream_error(struct quickcam *qc){	/* Skip rest of data for this frame */	if (qcdebug&QC_DEBUGERRORS) PDEBUG("qc_stream_error(qc=%p)", qc);	if (qc->stream_data.capturing)		qc_frame_end(qc);	IDEBUG_EXIT(qc->stream_data);	qc_stream_init(qc);}/* }}} *//* {{{ [fold] qc_stream_add(struct quickcam *qc, unsigned char *data, int datalen) *//* * Analyse an USB packet of the data stream and store it appropriately. * Each packet contains an integral number of chunks. Each chunk has * 2-bytes identification, followed by 2-bytes that describe the chunk * length. Known/guessed chunk identifications are: * 8001/8005/C001/C005 - Begin new frame * 8002/8006/C002/C006 - End frame * 0200/4200           - Contains actual image data, bayer or compressed * 0005                - 11 bytes of unknown data * 0100                - 2 bytes of unknown data * The 0005 and 0100 chunks seem to appear only in compressed stream. * Return the amount of image data received or negative value on error. */static int qc_stream_add(struct quickcam *qc, unsigned char *data, int datalen){	struct qc_stream_data *sd = &qc->stream_data;	int id, len, error, totaldata = 0;		IDEBUG_TEST(*sd);	while (datalen) {		if (datalen < 4) {			if (qcdebug&QC_DEBUGBITSTREAM) PRINTK(KERN_ERR,"missing chunk header");			break;		}		id  = (data[0]<<8) | data[1];		len = (data[2]<<8) | data[3];		data    += 4;		datalen -= 4;		if (datalen < len) {			if (qcdebug&QC_DEBUGBITSTREAM) PRINTK(KERN_ERR,"missing chunk contents");			break;		}		switch (id) {		case 0x8001:		case 0x8005:		case 0xC001:		case 0xC005:			/* Begin new frame, len should be zero */			if (PARANOID && len!=0) PDEBUG("New frame: len!=0");			if (sd->capturing) {				if (qcdebug&QC_DEBUGBITSTREAM) PDEBUG("Missing frame end mark in stream");				qc_frame_end(qc);			}			sd->capturing = TRUE;			if (--sd->frameskip < 0) sd->frameskip = qc->settings.frameskip;			if (sd->frameskip==0) qc_frame_begin(qc);			break;		case 0x8002:		case 0x8006:		case 0xC002:		case 0xC006:			/* End frame, len should be zero */			if (PARANOID && len!=0) PDEBUG("End frame: len!=0");			if (sd->capturing) {				if (sd->frameskip==0) qc_frame_end(qc);			} else {				if (qcdebug&QC_DEBUGBITSTREAM) PDEBUG("Missing frame begin mark in stream");			}			sd->capturing = FALSE;			break;		case 0x0200:		case 0x4200:			/* Image data */			if (!sd->capturing && (qcdebug&QC_DEBUGBITSTREAM)) PDEBUG("Chunk of data outside frames!");			if (sd->capturing && sd->frameskip==0) {				error = qc_frame_add(qc, data, len);			} else {				error = 0;			}			if (error) {				/* If qc_frame_add returns error, there is more data than the frame may have,				 * in which case we assume stream is corrupted and skip rest packet */				if (qcdebug&QC_DEBUGERRORS) PDEBUG("qc_frame_add error %i",error);			} else {				totaldata += len;			}			break;		case 0x0005:			/* Unknown chunk with 11 bytes of data, occurs just before end of each frame in compressed mode */			if (len==11) break;		case 0x0100:			/* Unknown chunk with 2 bytes of data, occurs 2-3 times per USB interrupt */			if (len==2) break;		default:			/* Unknown chunk */			#ifdef DEBUG			if (qcdebug&QC_DEBUGBITSTREAM) {				static char dump[4*1024];				char *dump_p = dump;				int i;				for (i=0; i<len && (3*i+9)<sizeof(dump); i++) dump_p+=sprintf(dump_p, "%02X ", data[i]);				PDEBUG("Unknown chunk %04X: %s", id, dump);			}			#endif			break;		}		data    += len;		datalen -= len;	}	return totaldata;}/* }}} *//* }}} *//* {{{ [fold] **** qc_isoc:   Isochronous USB transfer related routines ********* *//* * On my system (Acer Travelmate 332T, usb-ohci) there happens frequently * errors. Most common are: * -18	EXDEV	(even inside individual frames) * -84	EILSEQ * -71	EPROTO * -110	ETIMEDOUT * -75	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -