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

📄 pwc-if.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	pdev->fill_image = 0;	spin_unlock_irqrestore(&pdev->ptrlock, flags);}/**  \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. */static int pwc_handle_frame(struct pwc_device *pdev){	int ret = 0;	unsigned long flags;		spin_lock_irqsave(&pdev->ptrlock, flags);	/* First grab our read_frame; this is removed from all lists, so	   we can release the lock after this without problems */	if (pdev->read_frame != NULL) {		/* This can't theoretically happen */		Err("Huh? Read frame still in use?\n");	}	else {		if (pdev->full_frames == NULL) {			Err("Woops. No frames ready.\n");		}		else {			pdev->read_frame = pdev->full_frames;			pdev->full_frames = pdev->full_frames->next;			pdev->read_frame->next = NULL;		}		if (pdev->read_frame != NULL) {#if PWC_DEBUG			Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);#endif			/* Decompression is a lenghty process, so it's outside of the lock.			   This gives the isoc_handler the opportunity to fill more frames 			   in the mean time.			*/			spin_unlock_irqrestore(&pdev->ptrlock, flags);			ret = pwc_decompress(pdev);			spin_lock_irqsave(&pdev->ptrlock, flags);			/* We're done with read_buffer, tack it to the end of the empty buffer list */			if (pdev->empty_frames == NULL) {				pdev->empty_frames = pdev->read_frame;				pdev->empty_frames_tail = pdev->empty_frames;			}			else {				pdev->empty_frames_tail->next = pdev->read_frame;				pdev->empty_frames_tail = pdev->read_frame;			}			pdev->read_frame = NULL;		}	}	spin_unlock_irqrestore(&pdev->ptrlock, flags);	return ret;}/**  \brief Advance pointers of image buffer (after each user request) */static inline void pwc_next_image(struct pwc_device *pdev){	pdev->image_used[pdev->fill_image] = 0;	pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;}/* 2001-10-14: The YUV420 is still there, but you can only set it from within    a program (YUV420P being the default) */static int pwc_set_palette(struct pwc_device *pdev, int pal){	if (   pal == VIDEO_PALETTE_YUV420            || pal == VIDEO_PALETTE_YUV420P#if PWC_DEBUG            || pal == VIDEO_PALETTE_RAW#endif	) {		pdev->vpalette = pal;		pwc_set_image_buffer_size(pdev);		return 0;	}	Trace(TRACE_READ, "Palette %d not supported.\n", pal);	return -1;}/* This gets called for the Isochronous pipe (video). This is done in * interrupt time, so it has to be fast, not crash, and not stall. Neat. */static void pwc_isoc_handler(struct urb *urb){	struct pwc_device *pdev;	int i, fst, flen;	int awake;	struct pwc_frame_buf *fbuf;	unsigned char *fillptr, *iso_buf;	pdev = (struct pwc_device *)urb->context;	if (pdev == NULL) {		Err("isoc_handler() called with NULL device?!\n");		return;	}#ifdef PWC_MAGIC		if (pdev->magic != PWC_MAGIC) {		Err("isoc_handler() called with bad magic!\n");		return;	}#endif	if (urb->status == -ENOENT || urb->status == -ECONNRESET) {		Trace(TRACE_OPEN, "pwc_isoc_handler(): URB unlinked.\n");		return;	}	if (urb->status != -EINPROGRESS && urb->status != 0) {		char *errmsg;				errmsg = "Unknown";		switch(urb->status) {			case -ENOSR:		errmsg = "Buffer error (overrun)"; break;			case -EPIPE:		errmsg = "Stalled (device not responding)"; break;			case -EOVERFLOW:	errmsg = "Babble (bad cable?)"; break;			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break;			case -EILSEQ:		errmsg = "CRC/Timeout"; break;			case -ETIMEDOUT:	errmsg = "NAK (device does not respond)"; break;		}		Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);		return;	}	fbuf = pdev->fill_frame;	if (fbuf == NULL) {		Err("pwc_isoc_handler without valid fill frame.\n");		wake_up_interruptible(&pdev->frameq);		return;	}	fillptr = fbuf->data + fbuf->filled;	awake = 0;	/* vsync: 0 = don't copy data	          1 = sync-hunt	          2 = synched 	 */	/* Compact data */	for (i = 0; i < urb->number_of_packets; i++) {		fst  = urb->iso_frame_desc[i].status;		flen = urb->iso_frame_desc[i].actual_length;		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;		if (fst == 0) {			if (flen > 0) { /* if valid data... */				if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */					pdev->vsync = 2;					/* ...copy data to frame buffer, if possible */					if (flen + fbuf->filled > pdev->frame_size) {						Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_size = %d).\n", flen, pdev->frame_size);						pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */						pdev->vframes_error++;					}					else {						memmove(fillptr, iso_buf, flen);						fillptr += flen;					}				}				fbuf->filled += flen;			} /* ..flen > 0 */			if (flen < pdev->vlast_packet_size) {				/* Shorter packet... We probably have the end of an image-frame; 				   wake up read() process and let select()/poll() do something.				   Decompression is done in user time over there. 				 */				if (pdev->vsync == 2) {					/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus 					   frames on the USB wire after an exposure change. This conditition is 					   however detected  in the cam and a bit is set in the header.					 */					if (pdev->type == 730) {						unsigned char *ptr = (unsigned char *)fbuf->data;												if (ptr[1] == 1 && ptr[0] & 0x10) {#if PWC_DEBUG							Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);#endif							pdev->drop_frames = 2;							pdev->vframes_error++;						}						/* Sometimes the trailer of the 730 is still sent as a 4 byte packet 						   after a short frame; this condition is filtered out specifically. A 4 byte						   frame doesn't make sense anyway.						   So we get either this sequence: 						   	drop_bit set -> 4 byte frame -> short frame -> good frame						   Or this one:						   	drop_bit set -> short frame -> good frame						   So we drop either 3 or 2 frames in all!						 */						if (fbuf->filled == 4)							pdev->drop_frames++;					}					/* In case we were instructed to drop the frame, do so silently.					   The buffer pointers are not updated either (but the counters are reset below).					 */					if (pdev->drop_frames)						pdev->drop_frames--;					else {						/* Check for underflow first */						if (fbuf->filled < pdev->frame_size) {							Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);							pdev->vframes_error++;						}						else {							/* Send only once per EOF */							awake = 1; /* delay wake_ups */														/* Find our next frame to fill. This will always succeed, since we							 * nick a frame from either empty or full list, but if we had to							 * take it from the full list, it means a frame got dropped.							 */							if (pwc_next_fill_frame(pdev)) {								pdev->vframes_dumped++;								if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {									if (pdev->vframes_dumped < 20)										Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);									if (pdev->vframes_dumped == 20)										Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);								}							}							fbuf = pdev->fill_frame;						}					} /* !drop_frames */					pdev->vframe_count++;				}				fbuf->filled = 0;				fillptr = fbuf->data;				pdev->vsync = 1;			} /* .. flen < last_packet_size */			pdev->vlast_packet_size = flen;		} /* ..status == 0 */#ifdef PWC_DEBUG		/* This is normally not interesting to the user, unless you are really debugging something */		else 			Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);#endif				}	if (awake)		wake_up_interruptible(&pdev->frameq);}static int pwc_isoc_init(struct pwc_device *pdev){	struct usb_device *udev;	struct urb *urb;	int i, j, ret;	struct usb_interface_descriptor *idesc;	int cur_alt;	if (pdev == NULL)		return -EFAULT;	if (pdev->iso_init)		return 0;	pdev->vsync = 0;	udev = pdev->udev;		/* Get the current alternate interface, adjust packet size */	if (!udev->actconfig)		return -EFAULT;	cur_alt = udev->actconfig->interface[0].act_altsetting;	idesc = &udev->actconfig->interface[0].altsetting[cur_alt];	if (!idesc)		return -EFAULT;	/* Search video endpoint */	pdev->vmax_packet_size = -1;	for (i = 0; i < idesc->bNumEndpoints; i++)		if ((idesc->endpoint[i].bEndpointAddress & 0xF) == pdev->vendpoint) {			pdev->vmax_packet_size = idesc->endpoint[i].wMaxPacketSize;			break;		}		if (pdev->vmax_packet_size < 0) {		Err("Failed to find packet size for video endpoint in current alternate setting.\n");		return -ENFILE; /* Odd error, that should be noticable */	}	ret = 0;	for (i = 0; i < MAX_ISO_BUFS; i++) {		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);		if (urb == NULL) {			Err("Failed to allocate urb %d\n", i);			ret = -ENOMEM;			break;		}		pdev->sbuf[i].urb = urb;	}	if (ret) {		/* De-allocate in reverse order */		while (i >= 0) {			if (pdev->sbuf[i].urb != NULL)				usb_free_urb(pdev->sbuf[i].urb);			pdev->sbuf[i].urb = NULL;			i--;		}		return ret;	}			/* init URB structure */		for (i = 0; i < MAX_ISO_BUFS; i++) {		urb = pdev->sbuf[i].urb;		urb->next = pdev->sbuf[(i + 1) % MAX_ISO_BUFS].urb;		urb->dev = udev;	        urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);		urb->transfer_flags = USB_ISO_ASAP;	        urb->transfer_buffer = pdev->sbuf[i].data;	        urb->transfer_buffer_length = ISO_BUFFER_SIZE;	        urb->complete = pwc_isoc_handler;	        urb->context = pdev;		urb->start_frame = 0;		urb->number_of_packets = ISO_FRAMES_PER_DESC;		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;			urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;		}	}	/* link */	for (i = 0; i < MAX_ISO_BUFS; i++) {		ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);		if (ret)			Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);		else			Trace(TRACE_OPEN, "pwc_isoc_init(): URB submitted.\n");	}	/* data should stream in now */	pdev->iso_init = 1;	return 0;}static void pwc_isoc_cleanup(struct pwc_device *pdev){	int i;		if (pdev == NULL)		return;	if (!pdev->iso_init)		return;	/* Stop camera, but only if we are sure the camera is still there */	if (!pdev->unplugged)		usb_set_interface(pdev->udev, 0, 0);	/* Unlinking ISOC buffers one by one */	for (i = MAX_ISO_BUFS - 1; i >= 0; i--) {		pdev->sbuf[i].urb->next = NULL;		usb_unlink_urb(pdev->sbuf[i].urb);		usb_free_urb(pdev->sbuf[i].urb);		pdev->sbuf[i].urb = NULL;	}	pdev->iso_init = 0;}int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot){	int ret;	/* Stop isoc stuff */	pwc_isoc_cleanup(pdev);	/* Reset parameters */	pwc_reset_buffers(pdev);	/* Try to set video mode... */	ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);	if (ret) /* That failed... restore old mode (we know that worked) */		ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);	else /* Set (new) alternate interface */		ret = usb_set_interface(pdev->udev, 0, pdev->valternate);	if (!ret)		ret = pwc_isoc_init(pdev);	pdev->drop_frames = 1; /* try to avoid garbage during switch */	return ret;}static inline void set_mem_leak(void *ptr){	down(&mem_lock);	if (mem_leak != NULL)		Err("Memleak: overwriting mem_leak pointer!\n");	Trace(TRACE_MEMORY, "Setting mem_leak to 0x%p.\n", ptr);	mem_leak = ptr;	up(&mem_lock);}static inline void free_mem_leak(void){	down(&mem_lock);	if (mem_leak != NULL) {		Trace(TRACE_MEMORY, "Freeing mem_leak ptr 0x%p.\n", mem_leak);		kfree(mem_leak);		mem_leak = NULL;	}	up(&mem_lock);}/***************************************************************************//* Video4Linux functions */static int pwc_video_open(struct inode *inode, struct file *file){	int i;	struct video_device *vdev = video_devdata(file);	struct pwc_device *pdev;	Trace(TRACE_OPEN, "video_open called(0x%p).\n", vdev);		pdev = (struct pwc_device *)vdev->priv;	if (pdev == NULL)		BUG();	if (pdev->vopen)		return -EBUSY;		down(&pdev->modlock);	if (!pdev->usb_init) {		Trace(TRACE_OPEN, "Doing first time initialization.\n");		/* Reset camera */		if (usb_set_interface(pdev->udev, 0, 0))			Info("Failed to set alternate interface to 0.\n");		pdev->usb_init = 1;	}	/* Turn on camera */	if (power_save) {		i = pwc_camera_power(pdev, 1);		if (i < 0)			Info("Failed to restore power to the camera! (%d)\n", i);	}	/* Set LED on/off time */	if (pwc_set_leds(pdev, led_on, led_off) < 0)		Info("Failed to set LED on/off time.\n");	/* Find our decompressor, if any */	pdev->decompressor = pwc_find_decompressor(pdev->type);#if PWC_DEBUG		Debug("Found decompressor for %d at 0x%p\n", pdev->type, pdev->decompressor);#endif	/* So far, so good. Allocate memory. */	i = pwc_allocate_buffers(pdev);	if (i < 0) {		Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");		up(&pdev->modlock);		return i;	}		/* Reset buffers & parameters */	pwc_reset_buffers(pdev);	for (i = 0; i < default_mbufs; i++)		pdev->image_used[i] = 0;	pdev->vframe_count = 0;	pdev->vframes_dumped = 0;	pdev->vframes_error = 0;	pdev->vpalette = default_palette;#if PWC_DEBUG		pdev->sequence = 0;#endif	/* Set some defaults */	pdev->vsnapshot = 0;	if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)		pdev->vsize = PSZ_QSIF;	else		pdev->vsize = PSZ_QCIF;	pdev->vframes = 10;	/* Start iso pipe for video; first try user-supplied size/fps, if	   that fails try QCIF/10 or QSIF/10 (a reasonable default), 	   then give up 	 */	i = pwc_set_video_mode(pdev, pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y, default_fps, pdev->vcompression, 0);	if (i)	{		Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");		if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)			i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);		else			i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);	}	if (i) {		Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");		up(&pdev->modlock);		return i;	}		i = usb_set_interface(pdev->udev, 0, pdev->valternate);	if (i) {		Trace(TRACE_OPEN, "Failed to set alternate interface = %d.\n", i);		up(&pdev->modlock);		return -EINVAL;	}	i = pwc_isoc_init(pdev);	if (i) {		Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);		MOD_DEC_USE_COUNT;		up(&pdev->modlock);

⌨️ 快捷键说明

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