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

📄 usbvideo.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
 * usbvideo_v4l_open() * * This is part of Video 4 Linux API. The driver can be opened by one * client only (checks internal counter 'uvdser'). The procedure * then allocates buffers needed for video processing. * * History: * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the *             camera is also initialized here (once per connect), at *             expense of V4L client (it waits on open() call). * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). */static int usbvideo_v4l_open(struct inode *inode, struct file *file){	struct video_device *dev = video_devdata(file);	struct uvd *uvd = (struct uvd *) dev;	const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;	int i, errCode = 0;	if (uvd->debug > 1)		info("%s($%p)", __FUNCTION__, dev);	usbvideo_ClientIncModCount(uvd);	down(&uvd->lock);	if (uvd->user) {		err("%s: Someone tried to open an already opened device!", __FUNCTION__);		errCode = -EBUSY;	} else {		/* Clear statistics */		memset(&uvd->stats, 0, sizeof(uvd->stats));		/* Clean pointers so we know if we allocated something */		for (i=0; i < USBVIDEO_NUMSBUF; i++)			uvd->sbuf[i].data = NULL;		/* Allocate memory for the frame buffers */		uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;		uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);		RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);		if ((uvd->fbuf == NULL) ||		    (!RingQueue_IsAllocated(&uvd->dp))) {			err("%s: Failed to allocate fbuf or dp", __FUNCTION__);			errCode = -ENOMEM;		} else {			/* Allocate all buffers */			for (i=0; i < USBVIDEO_NUMFRAMES; i++) {				uvd->frame[i].frameState = FrameState_Unused;				uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size);				/*				 * Set default sizes in case IOCTL (VIDIOCMCAPTURE)				 * is not used (using read() instead).				 */				uvd->frame[i].canvas = uvd->canvas;				uvd->frame[i].seqRead_Index = 0;			}			for (i=0; i < USBVIDEO_NUMSBUF; i++) {				uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL);				if (uvd->sbuf[i].data == NULL) {					errCode = -ENOMEM;					break;				}			}		}		if (errCode != 0) {			/* Have to free all that memory */			if (uvd->fbuf != NULL) {				usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);				uvd->fbuf = NULL;			}			RingQueue_Free(&uvd->dp);			for (i=0; i < USBVIDEO_NUMSBUF; i++) {				if (uvd->sbuf[i].data != NULL) {					kfree (uvd->sbuf[i].data);					uvd->sbuf[i].data = NULL;				}			}		}	}	/* If so far no errors then we shall start the camera */	if (errCode == 0) {		/* Start data pump if we have valid endpoint */		if (uvd->video_endp != 0)			errCode = GET_CALLBACK(uvd, startDataPump)(uvd);		if (errCode == 0) {			if (VALID_CALLBACK(uvd, setupOnOpen)) {				if (uvd->debug > 1)					info("%s: setupOnOpen callback", __FUNCTION__);				errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);				if (errCode < 0) {					err("%s: setupOnOpen callback failed (%d.).",					    __FUNCTION__, errCode);				} else if (uvd->debug > 1) {					info("%s: setupOnOpen callback successful", __FUNCTION__);				}			}			if (errCode == 0) {				uvd->settingsAdjusted = 0;				if (uvd->debug > 1)					info("%s: Open succeeded.", __FUNCTION__);				uvd->user++;				file->private_data = uvd;			}		}	}	up(&uvd->lock);	if (errCode != 0)		usbvideo_ClientDecModCount(uvd);	if (uvd->debug > 0)		info("%s: Returning %d.", __FUNCTION__, errCode);	return errCode;}/* * usbvideo_v4l_close() * * This is part of Video 4 Linux API. The procedure * stops streaming and deallocates all buffers that were earlier * allocated in usbvideo_v4l_open(). * * History: * 22-Jan-2000 Moved scratch buffer deallocation here. * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep. */static int usbvideo_v4l_close(struct inode *inode, struct file *file){	struct video_device *dev = file->private_data;	struct uvd *uvd = (struct uvd *) dev;	int i;	if (uvd->debug > 1)		info("%s($%p)", __FUNCTION__, dev);	down(&uvd->lock);	GET_CALLBACK(uvd, stopDataPump)(uvd);	usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);	uvd->fbuf = NULL;	RingQueue_Free(&uvd->dp);	for (i=0; i < USBVIDEO_NUMSBUF; i++) {		kfree(uvd->sbuf[i].data);		uvd->sbuf[i].data = NULL;	}#if USBVIDEO_REPORT_STATS	usbvideo_ReportStatistics(uvd);#endif    	uvd->user--;	if (uvd->remove_pending) {		if (uvd->debug > 0)			info("usbvideo_v4l_close: Final disconnect.");		usbvideo_CameraRelease(uvd);	}	up(&uvd->lock);	usbvideo_ClientDecModCount(uvd);	if (uvd->debug > 1)		info("%s: Completed.", __FUNCTION__);	file->private_data = NULL;	return 0;}/* * usbvideo_v4l_ioctl() * * This is part of Video 4 Linux API. The procedure handles ioctl() calls. * * History: * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. */static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,				 unsigned int cmd, void *arg){	struct uvd *uvd = file->private_data;	if (!CAMERA_IS_OPERATIONAL(uvd))		return -EIO;	switch (cmd) {		case VIDIOCGCAP:		{			struct video_capability *b = arg;			*b = uvd->vcap;			return 0;		}		case VIDIOCGCHAN:		{			struct video_channel *v = arg;			*v = uvd->vchan;			return 0;		}		case VIDIOCSCHAN:		{				struct video_channel *v = arg;			if (v->channel != 0)				return -EINVAL;			return 0;		}		case VIDIOCGPICT:		{			struct video_picture *pic = arg;			*pic = uvd->vpic;			return 0;		}		case VIDIOCSPICT:		{			struct video_picture *pic = arg;			/*			 * Use temporary 'video_picture' structure to preserve our			 * own settings (such as color depth, palette) that we			 * aren't allowing everyone (V4L client) to change.			 */			uvd->vpic.brightness = pic->brightness;			uvd->vpic.hue = pic->hue;			uvd->vpic.colour = pic->colour;			uvd->vpic.contrast = pic->contrast;			uvd->settingsAdjusted = 0;	/* Will force new settings */			return 0;		}		case VIDIOCSWIN:		{			struct video_window *vw = arg;			if(VALID_CALLBACK(uvd, setVideoMode)) {				return GET_CALLBACK(uvd, setVideoMode)(uvd, vw);			}			if (vw->flags)				return -EINVAL;			if (vw->clipcount)				return -EINVAL;			if (vw->width != VIDEOSIZE_X(uvd->canvas))				return -EINVAL;			if (vw->height != VIDEOSIZE_Y(uvd->canvas))				return -EINVAL;			return 0;		}		case VIDIOCGWIN:		{			struct video_window *vw = arg;			vw->x = 0;			vw->y = 0;			vw->width = VIDEOSIZE_X(uvd->videosize);			vw->height = VIDEOSIZE_Y(uvd->videosize);			vw->chromakey = 0;			if (VALID_CALLBACK(uvd, getFPS))				vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);			else 				vw->flags = 10; /* FIXME: do better! */			return 0;		}		case VIDIOCGMBUF:		{			struct video_mbuf *vm = arg;			int i;			memset(vm, 0, sizeof(*vm));			vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES;			vm->frames = USBVIDEO_NUMFRAMES;			for(i = 0; i < USBVIDEO_NUMFRAMES; i++) 			  vm->offsets[i] = i * uvd->max_frame_size;			return 0;		}		case VIDIOCMCAPTURE:		{			struct video_mmap *vm = arg;			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 >= USBVIDEO_NUMFRAMES)) {				err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1);				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 = arg;			int ret;			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 = arg;			memset(vb, 0, sizeof(*vb)); 			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;}static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,		       unsigned int cmd, unsigned long arg){	return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);}/* * 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). */static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,		      size_t count, loff_t *ppos){	struct uvd *uvd = file->private_data;	int noblock = file->f_flags & O_NONBLOCK;	int frmx = -1, i;	struct usbvideo_frame *frame;	if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))		return -EFAULT;	if (uvd->debug >= 1)		info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);	down(&uvd->lock);		/* See if a frame is completed, then use it. */	for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {		if ((uvd->frame[i].frameState == FrameState_Done) ||		    (uvd->frame[i].frameState == FrameState_Done_Hold) ||		    (uvd->frame[i].frameState == FrameState_Error)) {			frmx = i;			break;		}	}	/* 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) {		for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {			if (uvd->frame[i].frameState == FrameState_Grabbing) {				frmx = i;				break;			}		}	}	/*	 * 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!", __FUNCTION__);			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=%Zd, new seqRead_Index=%ld",			__FUNCTION__, 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 + 1) % USBVIDEO_NUMFRAMES)) {			err("%s: usbvideo_NewFrame failed.", __FUNCTION__);		}	}read_done:

⌨️ 快捷键说明

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