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

📄 stk-webcam.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * stk-webcam.c : Driver for Syntek 1125 USB webcam controller * * Copyright (C) 2006 Nicolas VIVIEN * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com> * * Some parts are inspired from cafe_ccic.c * Copyright 2006-2007 Jonathan Corbet * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/usb.h>#include <linux/mm.h>#include <linux/vmalloc.h>#include "compat.h"#include <linux/videodev2.h>#include <media/v4l2-common.h>#include <media/v4l2-ioctl.h>#include "stk-webcam.h"static int hflip = 1;module_param(hflip, bool, 0444);MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");static int vflip = 1;module_param(vflip, bool, 0444);MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");static int debug;module_param(debug, int, 0444);MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0");MODULE_LICENSE("GPL");MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN");MODULE_DESCRIPTION("Syntek DC1125 webcam driver");/* Some cameras have audio interfaces, we aren't interested in those */static struct usb_device_id stkwebcam_table[] = {	{ USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) },	{ USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) },	{ }};MODULE_DEVICE_TABLE(usb, stkwebcam_table);/* * Basic stuff */int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value){	struct usb_device *udev = dev->udev;	int ret;	ret =  usb_control_msg(udev, usb_sndctrlpipe(udev, 0),			0x01,			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,			value,			index,			NULL,			0,			500);	if (ret < 0)		return ret;	else		return 0;}int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value){	struct usb_device *udev = dev->udev;	int ret;	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),			0x00,			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,			0x00,			index,			(u8 *) value,			sizeof(u8),			500);	if (ret < 0)		return ret;	else		return 0;}static int stk_start_stream(struct stk_camera *dev){	int value;	int i, ret;	int value_116, value_117;	if (!is_present(dev))		return -ENODEV;	if (!is_memallocd(dev) || !is_initialised(dev)) {		STK_ERROR("FIXME: Buffers are not allocated\n");		return -EFAULT;	}	ret = usb_set_interface(dev->udev, 0, 5);	if (ret < 0)		STK_ERROR("usb_set_interface failed !\n");	if (stk_sensor_wakeup(dev))		STK_ERROR("error awaking the sensor\n");	stk_camera_read_reg(dev, 0x0116, &value_116);	stk_camera_read_reg(dev, 0x0117, &value_117);	stk_camera_write_reg(dev, 0x0116, 0x0000);	stk_camera_write_reg(dev, 0x0117, 0x0000);	stk_camera_read_reg(dev, 0x0100, &value);	stk_camera_write_reg(dev, 0x0100, value | 0x80);	stk_camera_write_reg(dev, 0x0116, value_116);	stk_camera_write_reg(dev, 0x0117, value_117);	for (i = 0; i < MAX_ISO_BUFS; i++) {		if (dev->isobufs[i].urb) {			ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL);			atomic_inc(&dev->urbs_used);			if (ret)				return ret;		}	}	set_streaming(dev);	return 0;}static int stk_stop_stream(struct stk_camera *dev){	int value;	int i;	if (is_present(dev)) {		stk_camera_read_reg(dev, 0x0100, &value);		stk_camera_write_reg(dev, 0x0100, value & ~0x80);		if (dev->isobufs != NULL) {			for (i = 0; i < MAX_ISO_BUFS; i++) {				if (dev->isobufs[i].urb)					usb_kill_urb(dev->isobufs[i].urb);			}		}		unset_streaming(dev);		if (usb_set_interface(dev->udev, 0, 0))			STK_ERROR("usb_set_interface failed !\n");		if (stk_sensor_sleep(dev))			STK_ERROR("error suspending the sensor\n");	}	return 0;}/* * This seems to be the shortest init sequence we * must do in order to find the sensor * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor * is also reset. Maybe powers down it? * Rest of values don't make a difference */static struct regval stk1125_initvals[] = {	/*TODO: What means this sequence? */	{0x0000, 0x24},	{0x0100, 0x21},	{0x0002, 0x68},	{0x0003, 0x80},	{0x0005, 0x00},	{0x0007, 0x03},	{0x000d, 0x00},	{0x000f, 0x02},	{0x0300, 0x12},	{0x0350, 0x41},	{0x0351, 0x00},	{0x0352, 0x00},	{0x0353, 0x00},	{0x0018, 0x10},	{0x0019, 0x00},	{0x001b, 0x0e},	{0x001c, 0x46},	{0x0300, 0x80},	{0x001a, 0x04},	{0x0110, 0x00},	{0x0111, 0x00},	{0x0112, 0x00},	{0x0113, 0x00},	{0xffff, 0xff},};static int stk_initialise(struct stk_camera *dev){	struct regval *rv;	int ret;	if (!is_present(dev))		return -ENODEV;	if (is_initialised(dev))		return 0;	rv = stk1125_initvals;	while (rv->reg != 0xffff) {		ret = stk_camera_write_reg(dev, rv->reg, rv->val);		if (ret)			return ret;		rv++;	}	if (stk_sensor_init(dev) == 0) {		set_initialised(dev);		return 0;	} else		return -1;}#ifdef CONFIG_VIDEO_V4L1_COMPAT/* sysfs functions *//*FIXME cleanup this */static ssize_t show_brightness(struct device *class,			struct device_attribute *attr, char *buf){	struct video_device *vdev = to_video_device(class);	struct stk_camera *dev = vdev_to_camera(vdev);	return sprintf(buf, "%X\n", dev->vsettings.brightness);}static ssize_t store_brightness(struct device *class,		struct device_attribute *attr, const char *buf, size_t count){	char *endp;	unsigned long value;	int ret;	struct video_device *vdev = to_video_device(class);	struct stk_camera *dev = vdev_to_camera(vdev);	value = simple_strtoul(buf, &endp, 16);	dev->vsettings.brightness = (int) value;	ret = stk_sensor_set_brightness(dev, value >> 8);	if (ret)		return ret;	else		return count;}static ssize_t show_hflip(struct device *class,		struct device_attribute *attr, char *buf){	struct video_device *vdev = to_video_device(class);	struct stk_camera *dev = vdev_to_camera(vdev);	return sprintf(buf, "%d\n", dev->vsettings.hflip);}static ssize_t store_hflip(struct device *class,		struct device_attribute *attr, const char *buf, size_t count){	struct video_device *vdev = to_video_device(class);	struct stk_camera *dev = vdev_to_camera(vdev);	if (strncmp(buf, "1", 1) == 0)		dev->vsettings.hflip = 1;	else if (strncmp(buf, "0", 1) == 0)		dev->vsettings.hflip = 0;	else		return -EINVAL;	return strlen(buf);}static ssize_t show_vflip(struct device *class,		struct device_attribute *attr, char *buf){	struct video_device *vdev = to_video_device(class);	struct stk_camera *dev = vdev_to_camera(vdev);	return sprintf(buf, "%d\n", dev->vsettings.vflip);}static ssize_t store_vflip(struct device *class,		struct device_attribute *attr, const char *buf, size_t count){	struct video_device *vdev = to_video_device(class);	struct stk_camera *dev = vdev_to_camera(vdev);	if (strncmp(buf, "1", 1) == 0)		dev->vsettings.vflip = 1;	else if (strncmp(buf, "0", 1) == 0)		dev->vsettings.vflip = 0;	else		return -EINVAL;	return strlen(buf);}static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO,			show_brightness, store_brightness);static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip);static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip);static int stk_create_sysfs_files(struct video_device *vdev){	int ret;	ret = device_create_file(&vdev->dev, &dev_attr_brightness);	ret += device_create_file(&vdev->dev, &dev_attr_hflip);	ret += device_create_file(&vdev->dev, &dev_attr_vflip);	if (ret)		STK_WARNING("Could not create sysfs files\n");	return ret;}static void stk_remove_sysfs_files(struct video_device *vdev){	device_remove_file(&vdev->dev, &dev_attr_brightness);	device_remove_file(&vdev->dev, &dev_attr_hflip);	device_remove_file(&vdev->dev, &dev_attr_vflip);}#else#define stk_create_sysfs_files(a)#define stk_remove_sysfs_files(a)#endif/* *********************************************** *//* * This function is called as an URB transfert is complete (Isochronous pipe). * So, the traitement is done in interrupt time, so it has be fast, not crash, * and not stall. Neat. */static void stk_isoc_handler(struct urb *urb){	int i;	int ret;	int framelen;	unsigned long flags;	unsigned char *fill = NULL;	unsigned char *iso_buf = NULL;	struct stk_camera *dev;	struct stk_sio_buffer *fb;	dev = (struct stk_camera *) urb->context;	if (dev == NULL) {		STK_ERROR("isoc_handler called with NULL device !\n");		return;	}	if (urb->status == -ENOENT || urb->status == -ECONNRESET		|| urb->status == -ESHUTDOWN) {		atomic_dec(&dev->urbs_used);		return;	}	spin_lock_irqsave(&dev->spinlock, flags);	if (urb->status != -EINPROGRESS && urb->status != 0) {		STK_ERROR("isoc_handler: urb->status == %d\n", urb->status);		goto resubmit;	}	if (list_empty(&dev->sio_avail)) {		/*FIXME Stop streaming after a while */		(void) (printk_ratelimit() &&		STK_ERROR("isoc_handler without available buffer!\n"));		goto resubmit;	}	fb = list_first_entry(&dev->sio_avail,			struct stk_sio_buffer, list);	fill = fb->buffer + fb->v4lbuf.bytesused;	for (i = 0; i < urb->number_of_packets; i++) {		if (urb->iso_frame_desc[i].status != 0) {			if (urb->iso_frame_desc[i].status != -EXDEV)				STK_ERROR("Frame %d has error %d\n", i,					urb->iso_frame_desc[i].status);			continue;		}		framelen = urb->iso_frame_desc[i].actual_length;		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;		if (framelen <= 4)			continue; /* no data */		/*		 * we found something informational from there		 * the isoc frames have to type of headers		 * type1: 00 xx 00 00 or 20 xx 00 00		 * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00		 * xx is a sequencer which has never been seen over 0x3f		 * imho data written down looks like bayer, i see similarities		 * after every 640 bytes		 */		if (*iso_buf & 0x80) {			framelen -= 8;			iso_buf += 8;			/* This marks a new frame */			if (fb->v4lbuf.bytesused != 0				&& fb->v4lbuf.bytesused != dev->frame_size) {				(void) (printk_ratelimit() &&				STK_ERROR("frame %d, "					"bytesused=%d, skipping\n",					i, fb->v4lbuf.bytesused));				fb->v4lbuf.bytesused = 0;				fill = fb->buffer;			} else if (fb->v4lbuf.bytesused == dev->frame_size) {				if (list_is_singular(&dev->sio_avail)) {					/* Always reuse the last buffer */					fb->v4lbuf.bytesused = 0;					fill = fb->buffer;				} else {					list_move_tail(dev->sio_avail.next,						&dev->sio_full);					wake_up(&dev->wait_frame);					fb = list_first_entry(&dev->sio_avail,						struct stk_sio_buffer, list);					fb->v4lbuf.bytesused = 0;					fill = fb->buffer;				}			}		} else {			framelen -= 4;			iso_buf += 4;		}		/* Our buffer is full !!! */		if (framelen + fb->v4lbuf.bytesused > dev->frame_size) {			(void) (printk_ratelimit() &&			STK_ERROR("Frame buffer overflow, lost sync\n"));			/*FIXME Do something here? */			continue;		}		spin_unlock_irqrestore(&dev->spinlock, flags);		memcpy(fill, iso_buf, framelen);		spin_lock_irqsave(&dev->spinlock, flags);		fill += framelen;		/* New size of our buffer */		fb->v4lbuf.bytesused += framelen;	}resubmit:	spin_unlock_irqrestore(&dev->spinlock, flags);	urb->dev = dev->udev;	ret = usb_submit_urb(urb, GFP_ATOMIC);	if (ret != 0) {		STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n",			ret);	}}/* -------------------------------------------- */static int stk_prepare_iso(struct stk_camera *dev){	void *kbuf;	int i, j;	struct urb *urb;	struct usb_device *udev;	if (dev == NULL)		return -ENXIO;	udev = dev->udev;	if (dev->isobufs)		STK_ERROR("isobufs already allocated. Bad\n");	else		dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs),					GFP_KERNEL);	if (dev->isobufs == NULL) {		STK_ERROR("Unable to allocate iso buffers\n");		return -ENOMEM;	}

⌨️ 快捷键说明

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