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

📄 ov511.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	frame->width &= ~7L;		/* Multiple of 8 */	if (frame->height > ov511->maxheight)		frame->height = ov511->maxheight;	frame->height &= ~3L;		/* Multiple of 4 */	return 0;}/**************************************************************************** * * Buffer management * ***************************************************************************/static int ov511_alloc(struct usb_ov511 *ov511){	int i;	PDEBUG(4, "entered");	down(&ov511->buf_lock);	if (ov511->buf_state == BUF_PEND_DEALLOC) {		ov511->buf_state = BUF_ALLOCATED;		del_timer(&ov511->buf_timer);	}	if (ov511->buf_state == BUF_ALLOCATED)		goto out;	ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE);	if (!ov511->fbuf)		goto error;	for (i = 0; i < OV511_NUMFRAMES; i++) {		ov511->frame[i].grabstate = FRAME_UNUSED;		ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE;		PDEBUG(4, "frame[%d] @ %p", i, ov511->frame[i].data);		ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC *			MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);		if (!ov511->sbuf[i].data) {			while (--i) {				kfree(ov511->sbuf[i].data);				ov511->sbuf[i].data = NULL;			}			rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE);			ov511->fbuf = NULL;			goto error;		}		PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data);	}	ov511->buf_state = BUF_ALLOCATED;out:	up(&ov511->buf_lock);	PDEBUG(4, "leaving");	return 0;error:	ov511->buf_state = BUF_NOT_ALLOCATED;	up(&ov511->buf_lock);	PDEBUG(4, "errored");	return -ENOMEM;}/*  * - You must acquire buf_lock before entering this function. * - Because this code will free any non-null pointer, you must be sure to null *   them if you explicitly free them somewhere else! */static void ov511_do_dealloc(struct usb_ov511 *ov511){	int i;	PDEBUG(4, "entered");	if (ov511->fbuf) {		rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE);		ov511->fbuf = NULL;	}	for (i = 0; i < OV511_NUMFRAMES; i++) {		if (ov511->sbuf[i].data) {			kfree(ov511->sbuf[i].data);			ov511->sbuf[i].data = NULL;		}	}	PDEBUG(4, "buffer memory deallocated");	ov511->buf_state = BUF_NOT_ALLOCATED;	PDEBUG(4, "leaving");}static void ov511_buf_callback(unsigned long data){	struct usb_ov511 *ov511 = (struct usb_ov511 *)data;	PDEBUG(4, "entered");	down(&ov511->buf_lock);	if (ov511->buf_state == BUF_PEND_DEALLOC)		ov511_do_dealloc(ov511);	up(&ov511->buf_lock);	PDEBUG(4, "leaving");}static void ov511_dealloc(struct usb_ov511 *ov511, int now){	struct timer_list *bt = &(ov511->buf_timer);	PDEBUG(4, "entered");	down(&ov511->buf_lock);	PDEBUG(4, "deallocating buffer memory %s", now ? "now" : "later");	if (ov511->buf_state == BUF_PEND_DEALLOC) {		ov511->buf_state = BUF_ALLOCATED;		del_timer(bt);	}	if (now)		ov511_do_dealloc(ov511);	else {		ov511->buf_state = BUF_PEND_DEALLOC;		init_timer(bt);		bt->function = ov511_buf_callback;		bt->data = (unsigned long)ov511;		bt->expires = jiffies + buf_timeout * HZ;		add_timer(bt);	}	up(&ov511->buf_lock);	PDEBUG(4, "leaving");}/**************************************************************************** * * V4L API * ***************************************************************************/static int ov511_open(struct video_device *dev, int flags){	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;	int err;	MOD_INC_USE_COUNT;	PDEBUG(4, "opening");	down(&ov511->lock);	err = -EBUSY;	if (ov511->user) 		goto out;	err = -ENOMEM;	if (ov511_alloc(ov511))		goto out;	ov511->sub_flag = 0;	err = ov511_init_isoc(ov511);	if (err) {		ov511_dealloc(ov511, 0);		goto out;	}	ov511->user++;out:	up(&ov511->lock);	if (err)		MOD_DEC_USE_COUNT;	return err;}static void ov511_close(struct video_device *dev){	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;	PDEBUG(4, "ov511_close");		down(&ov511->lock);	ov511->user--;	ov511_stop_isoc(ov511);	if (ov511->dev)		ov511_dealloc(ov511, 0);	up(&ov511->lock);	if (!ov511->dev) {		ov511_dealloc(ov511, 1);		video_unregister_device(&ov511->vdev);		kfree(ov511);		ov511 = NULL;	}	MOD_DEC_USE_COUNT;}static int ov511_init_done(struct video_device *dev){#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)	create_proc_ov511_cam((struct usb_ov511 *)dev);#endif	return 0;}static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock){	return -EINVAL;}static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg){	struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;	PDEBUG(4, "IOCtl: 0x%X", cmd);	if (!ov511->dev)		return -EIO;		switch (cmd) {	case VIDIOCGCAP:	{		struct video_capability b;		PDEBUG (4, "VIDIOCGCAP");		strcpy(b.name, "OV511 USB Camera");		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;		b.channels = 1;		b.audios = 0;		b.maxwidth = ov511->maxwidth;		b.maxheight = ov511->maxheight;		b.minwidth = 160;		b.minheight = 120;		if (copy_to_user(arg, &b, sizeof(b)))			return -EFAULT;						return 0;	}	case VIDIOCGCHAN:	{		struct video_channel v;		if (copy_from_user(&v, arg, sizeof(v)))			return -EFAULT;		if (v.channel != 0)			return -EINVAL;		v.flags = 0;		v.tuners = 0;		v.type = VIDEO_TYPE_CAMERA;		strcpy(v.name, "Camera");		if (copy_to_user(arg, &v, sizeof(v)))			return -EFAULT;						return 0;	}	case VIDIOCSCHAN:	{		int v;		if (copy_from_user(&v, arg, sizeof(v)))			return -EFAULT;		if (v != 0)			return -EINVAL;		return 0;	}	case VIDIOCGPICT:	{		struct video_picture p;		PDEBUG (4, "VIDIOCGPICT");		if (ov7610_get_picture(ov511, &p))			return -EIO;									if (copy_to_user(arg, &p, sizeof(p)))			return -EFAULT;		return 0;	}	case VIDIOCSPICT:	{		struct video_picture p;		int i;		PDEBUG (4, "VIDIOCSPICT");		if (copy_from_user(&p, arg, sizeof(p)))			return -EFAULT;		if (!ov511_get_depth(p.palette))			return -EINVAL;					if (ov7610_set_picture(ov511, &p))			return -EIO;		PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette);		for (i = 0; i < OV511_NUMFRAMES; i++) {			ov511->frame[i].depth = p.depth;			ov511->frame[i].format = p.palette;			ov511->frame[i].segsize = GET_SEGSIZE(p.palette);		}		return 0;	}	case VIDIOCGCAPTURE:	{		int vf;		PDEBUG (4, "VIDIOCGCAPTURE");		if (copy_from_user(&vf, arg, sizeof(vf)))			return -EFAULT;		ov511->sub_flag = vf;		return 0;	}	case VIDIOCSCAPTURE:	{		struct video_capture vc;		if (copy_from_user(&vc, arg, sizeof(vc)))			return -EFAULT;		if (vc.flags)			return -EINVAL;		if (vc.decimation)			return -EINVAL;		vc.x &= ~3L;		vc.y &= ~1L;		vc.y &= ~31L;		if (vc.width == 0)			vc.width = 32;		vc.height /= 16;		vc.height *= 16;		if (vc.height == 0)			vc.height = 16;		ov511->subx = vc.x;		ov511->suby = vc.y;		ov511->subw = vc.width;		ov511->subh = vc.height;		return 0;	}	case VIDIOCSWIN:	{		struct video_window vw;		int i, result;		if (copy_from_user(&vw, arg, sizeof(vw)))			return -EFAULT;		PDEBUG (4, "VIDIOCSWIN: width=%d, height=%d",			vw.width, vw.height);#if 0		if (vw.flags)			return -EINVAL;		if (vw.clipcount)			return -EINVAL;		if (vw.height != ov511->maxheight)			return -EINVAL;		if (vw.width != ov511->maxwidth)			return -EINVAL;#endif		/* If we're collecting previous frame wait		   before changing modes */		interruptible_sleep_on(&ov511->wq);		if (signal_pending(current)) return -EINTR;		result = ov511_mode_init_regs(ov511, vw.width, vw.height,			ov511->frame[0].format, ov511->sub_flag);		if (result < 0)			return result;		for (i = 0; i < OV511_NUMFRAMES; i++) {			ov511->frame[i].width = vw.width;			ov511->frame[i].height = vw.height;		}		return 0;	}	case VIDIOCGWIN:	{		struct video_window vw;		vw.x = 0;		/* FIXME */		vw.y = 0;		vw.width = ov511->frame[0].width;		vw.height = ov511->frame[0].height;		vw.chromakey = 0;		vw.flags = 30;		PDEBUG (4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);		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 = OV511_NUMFRAMES * MAX_DATA_SIZE;		vm.frames = OV511_NUMFRAMES;		vm.offsets[0] = 0;		vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval);		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))			return -EFAULT;		return 0;	}	case VIDIOCMCAPTURE:	{		struct video_mmap vm;		int ret, depth;		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))			return -EFAULT;		PDEBUG(4, "CMCAPTURE");		PDEBUG(4, "frame: %d, size: %dx%d, format: %d",			vm.frame, vm.width, vm.height, vm.format);		depth = ov511_get_depth(vm.format);		if (!depth) {			err("VIDIOCMCAPTURE: invalid format (%d)", vm.format);			return -EINVAL;		}		if ((vm.frame != 0) && (vm.frame != 1)) {			err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);			return -EINVAL;		}		if (vm.width > ov511->maxwidth || vm.height > ov511->maxheight) {			err("VIDIOCMCAPTURE: requested dimensions too big");			return -EINVAL;		}		if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING)			return -EBUSY;		/* Don't compress if the size changed */		if ((ov511->frame[vm.frame].width != vm.width) ||		    (ov511->frame[vm.frame].height != vm.height) ||		    (ov511->frame[vm.frame].format != vm.format) ||		    (ov511->frame[vm.frame].sub_flag !=		     ov511->sub_flag)) {			/* If we're collecting previous frame wait			   before changing modes */			interruptible_sleep_on(&ov511->wq);			if (signal_pending(current)) return -EINTR;			ret = ov511_mode_init_regs(ov511, vm.width, vm.height,				vm.format, ov511->sub_flag);#if 0			if (ret < 0)				return ret;#endif		}		ov511->frame[vm.frame].width = vm.width;		ov511->frame[vm.frame].height = vm.height;		ov511->frame[vm.frame].format = vm.format;		ov511->frame[vm.frame].sub_flag = ov511->sub_flag;		ov511->frame[vm.frame].segsize = GET_SEGSIZE(vm.format);		ov511->frame[vm.frame].depth = depth;		/* Mark it as ready */		ov511->frame[vm.frame].grabstate = FRAME_READY;		return ov511_new_frame(ov511, vm.frame);	}	case VIDIOCSYNC:	{		int frame;		if (copy_from_user((void *)&frame, arg, sizeof(int)))			return -EFAULT;		PDEBUG(4, "syncing to frame %d, grabstate = %d", frame,		       ov511->frame[frame].grabstate);		switch (ov511->frame[frame].grabstate) {		case FRAME_UNUSED:			return -EINVAL;		case FRAME_READY:		case FRAME_GRA

⌨️ 快捷键说明

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