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

📄 usbvideo.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			vw.height = VIDEOSIZE_Y(uvd->canvas);			vw.chromakey = 0;			if (VALID_CALLBACK(uvd, getFPS))				vw.flags = GET_CALLBACK(uvd, getFPS)(uvd);			else 				vw.flags = 10; /* FIXME: do better! */			if (copy_to_user(arg, &vw, sizeof(vw)))				return -EFAULT;			return 0;		}		case VIDIOCGMBUF:		{			struct video_mbuf vm;			memset(&vm, 0, sizeof(vm));			vm.size = uvd->max_frame_size * 2;			vm.frames = 2;			vm.offsets[0] = 0;			vm.offsets[1] = uvd->max_frame_size;			if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))				return -EFAULT;			return 0;		}		case VIDIOCMCAPTURE:		{			struct video_mmap vm;			if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {				err("VIDIOCMCAPTURE: copy_from_user() failed.");				return -EFAULT;			}			if (uvd->debug >= 1) {				info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.",				    vm.frame, vm.width, vm.height, vm.format);			}			/*			 * Check if the requested size is supported. If the requestor			 * requests too big a frame then we may be tricked into accessing			 * outside of own preallocated frame buffer (in uvd->frame).			 * This will cause oops or a security hole. Theoretically, we			 * could only clamp the size down to acceptable bounds, but then			 * we'd need to figure out how to insert our smaller buffer into			 * larger caller's buffer... this is not an easy question. So we			 * here just flatly reject too large requests, assuming that the			 * caller will resubmit with smaller size. Callers should know			 * what size we support (returned by VIDIOCGCAP). However vidcat,			 * for one, does not care and allows to ask for any size.			 */			if ((vm.width > VIDEOSIZE_X(uvd->canvas)) ||			    (vm.height > VIDEOSIZE_Y(uvd->canvas))) {				if (uvd->debug > 0) {					info("VIDIOCMCAPTURE: Size=%dx%d too large; "					     "allowed only up to %ldx%ld", vm.width, vm.height,					     VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas));				}				return -EINVAL;			}			/* Check if the palette is supported */			if (((1L << vm.format) & uvd->paletteBits) == 0) {				if (uvd->debug > 0) {					info("VIDIOCMCAPTURE: format=%d. not supported"					     " (paletteBits=$%08lx)",					     vm.format, uvd->paletteBits);				}				return -EINVAL;			}			if ((vm.frame != 0) && (vm.frame != 1)) {				err("VIDIOCMCAPTURE: vm.frame=%d. !E [0,1]", vm.frame);				return -EINVAL;			}			if (uvd->frame[vm.frame].frameState == FrameState_Grabbing) {				/* Not an error - can happen */			}			uvd->frame[vm.frame].request = VIDEOSIZE(vm.width, vm.height);			uvd->frame[vm.frame].palette = vm.format;			/* Mark it as ready */			uvd->frame[vm.frame].frameState = FrameState_Ready;			return usbvideo_NewFrame(uvd, vm.frame);		}		case VIDIOCSYNC:		{			int frameNum, ret;			if (copy_from_user((void *)&frameNum, arg, sizeof(frameNum))) {				err("VIDIOCSYNC: copy_from_user() failed.");				return -EFAULT;			}			if(frameNum < 0 || frameNum >= USBVIDEO_NUMFRAMES)				return -EINVAL;							if (uvd->debug >= 1)				info("VIDIOCSYNC: syncing to frame %d.", frameNum);			if (uvd->flags & FLAGS_NO_DECODING)				ret = usbvideo_GetFrame(uvd, frameNum);			else if (VALID_CALLBACK(uvd, getFrame)) {				ret = GET_CALLBACK(uvd, getFrame)(uvd, frameNum);				if ((ret < 0) && (uvd->debug >= 1)) {					err("VIDIOCSYNC: getFrame() returned %d.", ret);				}			} else {				err("VIDIOCSYNC: getFrame is not set");				ret = -EFAULT;			}			/*			 * The frame is in FrameState_Done_Hold state. Release it			 * right now because its data is already mapped into			 * the user space and it's up to the application to			 * make use of it until it asks for another frame.			 */			uvd->frame[frameNum].frameState = FrameState_Unused;			return ret;		}		case VIDIOCGFBUF:		{			struct video_buffer vb;			memset(&vb, 0, sizeof(vb));			vb.base = NULL;	/* frame buffer not supported, not used */			if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))				return -EFAULT; 			return 0; 		}		case VIDIOCKEY:			return 0;		case VIDIOCCAPTURE:			return -EINVAL;		case VIDIOCSFBUF:		case VIDIOCGTUNER:		case VIDIOCSTUNER:		case VIDIOCGFREQ:		case VIDIOCSFREQ:		case VIDIOCGAUDIO:		case VIDIOCSAUDIO:			return -EINVAL;		default:			return -ENOIOCTLCMD;	}	return 0;}/* * usbvideo_v4l_read() * * This is mostly boring stuff. We simply ask for a frame and when it * arrives copy all the video data from it into user space. There is * no obvious need to override this method. * * History: * 20-Oct-2000 Created. * 01-Nov-2000 Added mutex (uvd->lock). */long usbvideo_v4l_read(struct video_device *dev, char *buf, unsigned long count, int noblock){	static const char proc[] = "usbvideo_v4l_read";	uvd_t *uvd = (uvd_t *) dev;	int frmx = -1;	usbvideo_frame_t *frame;	if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))		return -EFAULT;	if (uvd->debug >= 1)		info("%s: %ld. bytes, noblock=%d.", proc, count, noblock);	down(&uvd->lock);		/* See if a frame is completed, then use it. */	if ((uvd->frame[0].frameState == FrameState_Done) ||	    (uvd->frame[0].frameState == FrameState_Done_Hold) ||	    (uvd->frame[0].frameState == FrameState_Error)) {		frmx = 0;	} else if ((uvd->frame[1].frameState >= FrameState_Done) ||		   (uvd->frame[1].frameState == FrameState_Done_Hold) ||		   (uvd->frame[1].frameState >= FrameState_Done)) {		frmx = 1;	}	/* FIXME: If we don't start a frame here then who ever does? */	if (noblock && (frmx == -1)) {		count = -EAGAIN;		goto read_done;	}	/*	 * If no FrameState_Done, look for a FrameState_Grabbing state.	 * See if a frame is in process (grabbing), then use it.	 * We will need to wait until it becomes cooked, of course.	 */	if (frmx == -1) {		if (uvd->frame[0].frameState == FrameState_Grabbing)			frmx = 0;		else if (uvd->frame[1].frameState == FrameState_Grabbing)			frmx = 1;	}	/*	 * If no frame is active, start one. We don't care which one	 * it will be, so #0 is as good as any.	 * In read access mode we don't have convenience of VIDIOCMCAPTURE	 * to specify the requested palette (video format) on per-frame	 * basis. This means that we have to return data in -some- format	 * and just hope that the client knows what to do with it.	 * The default format is configured in uvd->defaultPalette field	 * as one of VIDEO_PALETTE_xxx values. We stuff it into the new	 * frame and initiate the frame filling process.	 */	if (frmx == -1) {		if (uvd->defaultPalette == 0) {			err("%s: No default palette; don't know what to do!", proc);			count = -EFAULT;			goto read_done;		}		frmx = 0;		/*		 * We have no per-frame control over video size.		 * Therefore we only can use whatever size was		 * specified as default.		 */		uvd->frame[frmx].request = uvd->videosize;		uvd->frame[frmx].palette = uvd->defaultPalette;		uvd->frame[frmx].frameState = FrameState_Ready;		usbvideo_NewFrame(uvd, frmx);		/* Now frame 0 is supposed to start filling... */	}	/*	 * Get a pointer to the active frame. It is either previously	 * completed frame or frame in progress but not completed yet.	 */	frame = &uvd->frame[frmx];	/*	 * Sit back & wait until the frame gets filled and postprocessed.	 * If we fail to get the picture [in time] then return the error.	 * In this call we specify that we want the frame to be waited for,	 * postprocessed and switched into FrameState_Done_Hold state. This	 * state is used to hold the frame as "fully completed" between	 * subsequent partial reads of the same frame.	 */	if (frame->frameState != FrameState_Done_Hold) {		long rv = -EFAULT;		if (uvd->flags & FLAGS_NO_DECODING)			rv = usbvideo_GetFrame(uvd, frmx);		else if (VALID_CALLBACK(uvd, getFrame))			rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx);		else			err("getFrame is not set");		if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) {			count = rv;			goto read_done;		}	}	/*	 * Copy bytes to user space. We allow for partial reads, which	 * means that the user application can request read less than	 * the full frame size. It is up to the application to issue	 * subsequent calls until entire frame is read.	 *	 * First things first, make sure we don't copy more than we	 * have - even if the application wants more. That would be	 * a big security embarassment!	 */	if ((count + frame->seqRead_Index) > frame->seqRead_Length)		count = frame->seqRead_Length - frame->seqRead_Index;	/*	 * Copy requested amount of data to user space. We start	 * copying from the position where we last left it, which	 * will be zero for a new frame (not read before).	 */	if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) {		count = -EFAULT;		goto read_done;	}	/* Update last read position */	frame->seqRead_Index += count;	if (uvd->debug >= 1) {		err("%s: {copy} count used=%ld, new seqRead_Index=%ld",			proc, count, frame->seqRead_Index);	}	/* Finally check if the frame is done with and "release" it */	if (frame->seqRead_Index >= frame->seqRead_Length) {		/* All data has been read */		frame->seqRead_Index = 0;		/* Mark it as available to be used again. */		uvd->frame[frmx].frameState = FrameState_Unused;		if (usbvideo_NewFrame(uvd, frmx ? 0 : 1)) {			err("%s: usbvideo_NewFrame failed.", proc);		}	}read_done:	up(&uvd->lock);		return count;}/* * Make all of the blocks of data contiguous */static int usbvideo_CompressIsochronous(uvd_t *uvd, urb_t *urb){	char *cdata;	int i, totlen = 0;	for (i = 0; i < urb->number_of_packets; i++) {		int n = urb->iso_frame_desc[i].actual_length;		int st = urb->iso_frame_desc[i].status;		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;		/* Detect and ignore errored packets */		if (st < 0) {			if (uvd->debug >= 1)				err("Data error: packet=%d. len=%d. status=%d.", i, n, st);			uvd->stats.iso_err_count++;			continue;		}		/* Detect and ignore empty packets */		if (n <= 0) {			uvd->stats.iso_skip_count++;			continue;		}		totlen += n;	/* Little local accounting */		RingQueue_Enqueue(&uvd->dp, cdata, n);	}	return totlen;}static void usbvideo_IsocIrq(struct urb *urb){	int i, len;	uvd_t *uvd = urb->context;	/* We don't want to do anything if we are about to be removed! */	if (!CAMERA_IS_OPERATIONAL(uvd))		return;#if 0	if (urb->actual_length > 0) {		info("urb=$%p status=%d. errcount=%d. length=%d.",		     urb, urb->status, urb->error_count, urb->actual_length);	} else {		static int c = 0;		if (c++ % 100 == 0)			info("No Isoc data");	}#endif	if (!uvd->streaming) {		if (uvd->debug >= 1)			info("Not streaming, but interrupt!");		return;	}		uvd->stats.urb_count++;	if (urb->actual_length <= 0)		goto urb_done_with;	/* Copy the data received into ring queue */	len = usbvideo_CompressIsochronous(uvd, urb);	uvd->stats.urb_length = len;	if (len <= 0)		goto urb_done_with;	/* Here we got some data */	uvd->stats.data_count += len;	RingQueue_WakeUpInterruptible(&uvd->dp);urb_done_with:	for (i = 0; i < FRAMES_PER_DESC; i++) {		urb->iso_frame_desc[i].status = 0;		urb->iso_frame_desc[i].actual_length = 0;	}	return;}/* * usbvideo_StartDataPump() * * History: * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead *             of hardcoded values. Simplified by using for loop, *             allowed any number of URBs. */int usbvideo_StartDataPump(uvd_t *uvd){	static const char proc[] = "usbvideo_StartDataPump";	struct usb_device *dev = uvd->dev;	int i, errFlag;	if (uvd->debug > 1)		info("%s($%p)", proc, uvd);	if (!CAMERA_IS_OPERATIONAL(uvd)) {		err("%s: Camera is not operational",proc);		return -EFAULT;	}	uvd->curframe = -1;	/* Alternate interface 1 is is the biggest frame size */	i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);	if (i < 0) {		err("%s: usb_set_interface error", proc);		uvd->last_error = i;		return -EBUSY;	}	if (VALID_CALLBACK(uvd, videoStart))		GET_CALLBACK(uvd, videoStart)(uvd);	else 		err("%s: videoStart not set", proc);	/* We double buffer the Iso lists */	for (i=0; i < USBVIDEO_NUMSBUF; i++) {		int j, k;		urb_t *urb = uvd->sbuf[i].urb;		urb->dev = dev;		urb->context = uvd;		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);		urb->transfer_flags = USB_ISO_ASAP;		urb->transfer_buffer = uvd->sbuf[i].data;		urb->complete = usbvideo_IsocIrq;		urb->number_of_packets = FRAMES_PER_DESC;		urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC;		for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) {			urb->iso_frame_desc[j].offset = k;			urb->iso_frame_desc[j].length = uvd->iso_packet_len;		}	}	/* Link URBs into a ring so that they invoke each other infinitely */	for (i=0; i < USBVIDEO_NUMSBUF; i++) {		if ((i+1) < USBVIDEO_NUMSBUF)			uvd->sbuf[i].urb->next = uvd->sbuf[i+1].urb;		else			uvd->sbuf[i].urb->next = uvd->sbuf[0].urb;	}	/* Submit all URBs */	for (i=0; i < USBVIDEO_NUMSBUF; i++) {		errFlag = usb_submit_urb(uvd->sbuf[i].urb);		if (errFlag)			err("%s: usb_submit_isoc(%d) ret %d", proc, i, errFlag);	}	uvd->streaming = 1;	if (uvd->debug > 1)		info("%s: streaming=1 video_endp=$%02x", proc, uvd->video_endp);	return 0;}/* * usbvideo_StopDataPump() * * This procedure stops streaming and deallocates URBs. Then it * activates zero-bandwidth alt. setting of the video interface. * * History: * 22-Jan-2000 Corrected order of actions to work after surprise removal. * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values. */void usbvideo_StopDataPump(uvd_t *uvd){	static const char proc[] = "usbvideo_StopDataPump";	int i, j;	if (uvd->debug > 1)		info("%s($%p)", proc, uvd);	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))

⌨️ 快捷键说明

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