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

📄 gspca.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index);	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	if (mutex_lock_interruptible(&gspca_dev->queue_lock))		return -ERESTARTSYS;	index = v4l2_buf->index;	if ((unsigned) index >= gspca_dev->nframes) {		PDEBUG(D_FRAM,			"qbuf idx %d >= %d", index, gspca_dev->nframes);		ret = -EINVAL;		goto out;	}	if (v4l2_buf->memory != gspca_dev->memory) {		PDEBUG(D_FRAM, "qbuf bad memory type");		ret = -EINVAL;		goto out;	}	frame = &gspca_dev->frame[index];	if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) {		PDEBUG(D_FRAM, "qbuf bad state");		ret = -EINVAL;		goto out;	}	frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;	if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {		frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;		frame->v4l2_buf.length = v4l2_buf->length;	}	/* put the buffer in the 'queued' queue */	i = gspca_dev->fr_q;	gspca_dev->fr_queue[i] = index;	gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;	PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",		gspca_dev->fr_q,		gspca_dev->fr_i,		gspca_dev->fr_o);	v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;	v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;	ret = 0;out:	mutex_unlock(&gspca_dev->queue_lock);	return ret;}/* * allocate the resources for read() */static int read_alloc(struct gspca_dev *gspca_dev,			struct file *file){	struct v4l2_buffer v4l2_buf;	int i, ret;	PDEBUG(D_STREAM, "read alloc");	if (gspca_dev->nframes == 0) {		struct v4l2_requestbuffers rb;		memset(&rb, 0, sizeof rb);		rb.count = gspca_dev->nbufread;		rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		rb.memory = GSPCA_MEMORY_READ;		ret = vidioc_reqbufs(file, gspca_dev, &rb);		if (ret != 0) {			PDEBUG(D_STREAM, "read reqbuf err %d", ret);			return ret;		}		memset(&v4l2_buf, 0, sizeof v4l2_buf);		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		v4l2_buf.memory = GSPCA_MEMORY_READ;		for (i = 0; i < gspca_dev->nbufread; i++) {			v4l2_buf.index = i;			ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);			if (ret != 0) {				PDEBUG(D_STREAM, "read qbuf err: %d", ret);				return ret;			}		}		gspca_dev->memory = GSPCA_MEMORY_READ;	}	/* start streaming */	ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE);	if (ret != 0)		PDEBUG(D_STREAM, "read streamon err %d", ret);	return ret;}static unsigned int dev_poll(struct file *file, poll_table *wait){	struct gspca_dev *gspca_dev = file->private_data;	int i, ret;	PDEBUG(D_FRAM, "poll");	poll_wait(file, &gspca_dev->wq, wait);	if (!gspca_dev->present)		return POLLERR;	/* if reqbufs is not done, the user would use read() */	if (gspca_dev->nframes == 0) {		if (gspca_dev->memory != GSPCA_MEMORY_NO)			return POLLERR;		/* not the 1st time */		ret = read_alloc(gspca_dev, file);		if (ret != 0)			return POLLERR;	}	if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)		return POLLERR;	if (!gspca_dev->present) {		ret = POLLERR;		goto out;	}	/* check the next incoming buffer */	i = gspca_dev->fr_o;	i = gspca_dev->fr_queue[i];	if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)		ret = POLLIN | POLLRDNORM;	/* something to read */	else		ret = 0;out:	mutex_unlock(&gspca_dev->queue_lock);	return ret;}static ssize_t dev_read(struct file *file, char __user *data,		    size_t count, loff_t *ppos){	struct gspca_dev *gspca_dev = file->private_data;	struct gspca_frame *frame;	struct v4l2_buffer v4l2_buf;	struct timeval timestamp;	int n, ret, ret2;	PDEBUG(D_FRAM, "read (%zd)", count);	if (!gspca_dev->present)		return -ENODEV;	switch (gspca_dev->memory) {	case GSPCA_MEMORY_NO:			/* first time */		ret = read_alloc(gspca_dev, file);		if (ret != 0)			return ret;		break;	case GSPCA_MEMORY_READ:		if (gspca_dev->capt_file == file)			break;		/* fall thru */	default:		return -EINVAL;	}	/* get a frame */	jiffies_to_timeval(get_jiffies_64(), &timestamp);	timestamp.tv_sec--;	n = 2;	for (;;) {		memset(&v4l2_buf, 0, sizeof v4l2_buf);		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		v4l2_buf.memory = GSPCA_MEMORY_READ;		ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf);		if (ret != 0) {			PDEBUG(D_STREAM, "read dqbuf err %d", ret);			return ret;		}		/* if the process slept for more than 1 second,		 * get a newer frame */		frame = &gspca_dev->frame[v4l2_buf.index];		if (--n < 0)			break;			/* avoid infinite loop */		if (frame->v4l2_buf.timestamp.tv_sec >= timestamp.tv_sec)			break;		ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);		if (ret != 0) {			PDEBUG(D_STREAM, "read qbuf err %d", ret);			return ret;		}	}	/* copy the frame */	if (count > frame->v4l2_buf.bytesused)		count = frame->v4l2_buf.bytesused;	ret = copy_to_user(data, frame->data, count);	if (ret != 0) {		PDEBUG(D_ERR|D_STREAM,			"read cp to user lack %d / %zd", ret, count);		ret = -EFAULT;		goto out;	}	ret = count;out:	/* in each case, requeue the buffer */	ret2 = vidioc_qbuf(file, gspca_dev, &v4l2_buf);	if (ret2 != 0)		return ret2;	return ret;}static void dev_release(struct video_device *vfd){	/* nothing */}static struct file_operations dev_fops = {	.owner = THIS_MODULE,	.open = dev_open,	.release = dev_close,	.read = dev_read,	.mmap = dev_mmap,	.ioctl = video_ioctl2,#ifdef CONFIG_COMPAT	.compat_ioctl = v4l_compat_ioctl32,#endif	.llseek = no_llseek,	.poll	= dev_poll,};static const struct v4l2_ioctl_ops dev_ioctl_ops = {	.vidioc_querycap	= vidioc_querycap,	.vidioc_dqbuf		= vidioc_dqbuf,	.vidioc_qbuf		= vidioc_qbuf,	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,	.vidioc_streamon	= vidioc_streamon,	.vidioc_queryctrl	= vidioc_queryctrl,	.vidioc_g_ctrl		= vidioc_g_ctrl,	.vidioc_s_ctrl		= vidioc_s_ctrl,	.vidioc_querymenu	= vidioc_querymenu,	.vidioc_enum_input	= vidioc_enum_input,	.vidioc_g_input		= vidioc_g_input,	.vidioc_s_input		= vidioc_s_input,	.vidioc_reqbufs		= vidioc_reqbufs,	.vidioc_querybuf	= vidioc_querybuf,	.vidioc_streamoff	= vidioc_streamoff,	.vidioc_g_jpegcomp	= vidioc_g_jpegcomp,	.vidioc_s_jpegcomp	= vidioc_s_jpegcomp,	.vidioc_g_parm		= vidioc_g_parm,	.vidioc_s_parm		= vidioc_s_parm,	.vidioc_s_std		= vidioc_s_std,#ifdef CONFIG_VIDEO_V4L1_COMPAT	.vidiocgmbuf          = vidiocgmbuf,#endif};static struct video_device gspca_template = {	.name = "gspca main driver",	.fops = &dev_fops,	.ioctl_ops = &dev_ioctl_ops,	.release = dev_release,		/* mandatory */	.minor = -1,};/* * probe and create a new gspca device * * This function must be called by the sub-driver when it is * called for probing a new device. */int gspca_dev_probe(struct usb_interface *intf,		const struct usb_device_id *id,		const struct sd_desc *sd_desc,		int dev_size,		struct module *module){	struct usb_interface_descriptor *interface;	struct gspca_dev *gspca_dev;	struct usb_device *dev = interface_to_usbdev(intf);	int ret;	PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);	/* we don't handle multi-config cameras */	if (dev->descriptor.bNumConfigurations != 1)		return -ENODEV;	interface = &intf->cur_altsetting->desc;	if (interface->bInterfaceNumber > 0)		return -ENODEV;	/* create the device */	if (dev_size < sizeof *gspca_dev)		dev_size = sizeof *gspca_dev;	gspca_dev = kzalloc(dev_size, GFP_KERNEL);	if (!gspca_dev) {		err("couldn't kzalloc gspca struct");		return -ENOMEM;	}	kref_init(&gspca_dev->kref);	gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);	if (!gspca_dev->usb_buf) {		err("out of memory");		ret = -ENOMEM;		goto out;	}	gspca_dev->dev = dev;	gspca_dev->iface = interface->bInterfaceNumber;	gspca_dev->nbalt = intf->num_altsetting;	gspca_dev->sd_desc = sd_desc;	gspca_dev->nbufread = 2;	/* configure the subdriver and initialize the USB device */	ret = gspca_dev->sd_desc->config(gspca_dev, id);	if (ret < 0)		goto out;	ret = gspca_dev->sd_desc->init(gspca_dev);	if (ret < 0)		goto out;	ret = gspca_set_alt0(gspca_dev);	if (ret < 0)		goto out;	gspca_set_default_mode(gspca_dev);	mutex_init(&gspca_dev->usb_lock);	mutex_init(&gspca_dev->read_lock);	mutex_init(&gspca_dev->queue_lock);	init_waitqueue_head(&gspca_dev->wq);	/* init video stuff */	memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);	gspca_dev->vdev.parent = &dev->dev;	memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops);	gspca_dev->vdev.fops = &gspca_dev->fops;	gspca_dev->fops.owner = module;		/* module protection */	gspca_dev->present = 1;	ret = video_register_device(&gspca_dev->vdev,				  VFL_TYPE_GRABBER,				  video_nr);	if (ret < 0) {		err("video_register_device err %d", ret);		goto out;	}	usb_set_intfdata(intf, gspca_dev);	PDEBUG(D_PROBE, "probe ok");	return 0;out:	kref_put(&gspca_dev->kref, gspca_delete);	return ret;}EXPORT_SYMBOL(gspca_dev_probe);/* * USB disconnection * * This function must be called by the sub-driver * when the device disconnects, after the specific resources are freed. */void gspca_disconnect(struct usb_interface *intf){	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);	usb_set_intfdata(intf, NULL);/* We don't want people trying to open up the device */	video_unregister_device(&gspca_dev->vdev);	gspca_dev->present = 0;	gspca_dev->streaming = 0;	kref_put(&gspca_dev->kref, gspca_delete);	PDEBUG(D_PROBE, "disconnect complete");}EXPORT_SYMBOL(gspca_disconnect);#ifdef CONFIG_PMint gspca_suspend(struct usb_interface *intf, pm_message_t message){	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);	if (!gspca_dev->streaming)		return 0;	gspca_dev->frozen = 1;		/* avoid urb error messages */	if (gspca_dev->sd_desc->stopN)		gspca_dev->sd_desc->stopN(gspca_dev);	destroy_urbs(gspca_dev);	gspca_set_alt0(gspca_dev);	if (gspca_dev->sd_desc->stop0)		gspca_dev->sd_desc->stop0(gspca_dev);	return 0;}EXPORT_SYMBOL(gspca_suspend);int gspca_resume(struct usb_interface *intf){	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);	gspca_dev->frozen = 0;	gspca_dev->sd_desc->init(gspca_dev);	if (gspca_dev->streaming)		return gspca_init_transfer(gspca_dev);	return 0;}EXPORT_SYMBOL(gspca_resume);#endif/* -- cam driver utility functions -- *//* auto gain and exposure algorithm based on the knee algorithm described here:   http://ytse.tricolour.net/docs/LowLightOptimization.html   Returns 0 if no changes were made, 1 if the gain and or exposure settings   where changed. */int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,	int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee){	int i, steps, gain, orig_gain, exposure, orig_exposure, autogain;	const struct ctrl *gain_ctrl = NULL;	const struct ctrl *exposure_ctrl = NULL;	const struct ctrl *autogain_ctrl = NULL;	int retval = 0;	for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {		if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN)			gain_ctrl = &gspca_dev->sd_desc->ctrls[i];		if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE)			exposure_ctrl = &gspca_dev->sd_desc->ctrls[i];		if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN)			autogain_ctrl = &gspca_dev->sd_desc->ctrls[i];	}	if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) {		PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called "			"on cam without (auto)gain/exposure");		return 0;	}	if (gain_ctrl->get(gspca_dev, &gain) ||			exposure_ctrl->get(gspca_dev, &exposure) ||			autogain_ctrl->get(gspca_dev, &autogain) || !autogain)		return 0;	orig_gain = gain;	orig_exposure = exposure;	/* If we are of a multiple of deadzone, do multiple steps to reach the	   desired lumination fast (with the risc of a slight overshoot) */	steps = abs(desired_avg_lum - avg_lum) / deadzone;	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n",		avg_lum, desired_avg_lum, steps);	for (i = 0; i < steps; i++) {		if (avg_lum > desired_avg_lum) {			if (gain > gain_knee)				gain--;			else if (exposure > exposure_knee)				exposure--;			else if (gain > gain_ctrl->qctrl.default_value)				gain--;			else if (exposure > exposure_ctrl->qctrl.minimum)				exposure--;			else if (gain > gain_ctrl->qctrl.minimum)				gain--;			else				break;		} else {			if (gain < gain_ctrl->qctrl.default_value)				gain++;			else if (exposure < exposure_knee)				exposure++;			else if (gain < gain_knee)				gain++;			else if (exposure < exposure_ctrl->qctrl.maximum)				exposure++;			else if (gain < gain_ctrl->qctrl.maximum)				gain++;			else				break;		}	}	if (gain != orig_gain) {		gain_ctrl->set(gspca_dev, gain);		retval = 1;	}	if (exposure != orig_exposure) {		exposure_ctrl->set(gspca_dev, exposure);		retval = 1;	}	return retval;}EXPORT_SYMBOL(gspca_auto_gain_n_exposure);/* -- module insert / remove -- */static int __init gspca_init(void){	info("main v%d.%d.%d registered",		(DRIVER_VERSION_NUMBER >> 16) & 0xff,		(DRIVER_VERSION_NUMBER >> 8) & 0xff,		DRIVER_VERSION_NUMBER & 0xff);	return 0;}static void __exit gspca_exit(void){	info("main deregistered");}module_init(gspca_init);module_exit(gspca_exit);#ifdef GSPCA_DEBUGmodule_param_named(debug, gspca_debug, int, 0644);MODULE_PARM_DESC(debug,		"Debug (bit) 0x01:error 0x02:probe 0x04:config"		" 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout"		" 0x0100: v4l2");#endif

⌨️ 快捷键说明

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