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

📄 dc2xx.c

📁 Usb1.1驱动c语言源代码
💻 C
字号:
/* * Copyright (C) 1999 by David Brownell <david-b@pacbell.net> * * 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 (at your * option) 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., 675 Mass Ave, Cambridge, MA 02139, USA. */  /* * USB driver for Kodak DC-2XX series digital still cameras * * The protocol here is the same as the one going over a serial line, but * it uses USB for speed.  Set up /dev/kodak, get gphoto (www.gphoto.org), * and have fun! * * This should also work for a number of other digital (non-Kodak) cameras, * by adding the vendor and product IDs to the table below. *//* * HISTORY * * 26 August, 1999 -- first release (0.1), works with my DC-240. * 	The DC-280 (2Mpixel) should also work, but isn't tested. *	If you use gphoto, make sure you have the USB updates. *	Lives in a 2.3.14 or so Linux kernel, in drivers/usb. * 31 August, 1999 -- minor update to recognize DC-260 and handle *	its endpoints being in a different order.  Note that as *	of gPhoto 0.36pre, the USB updates are integrated. * 12 Oct, 1999 -- handle DC-280 interface class (0xff not 0x0); *	added timeouts to bulk_msg calls.  Minor updates, docs. * 03 Nov, 1999 -- update for 2.3.25 kernel API changes. * * Thanks to:  the folk who've provided USB product IDs, sent in * patches, and shared their sucesses! */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/miscdevice.h>#include <linux/random.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/malloc.h>#include <linux/module.h>#undef DEBUG#include "usb.h"/* XXX need to get registered minor number, cdev 10/MINOR *//* XXX or: cdev USB_MAJOR(180)/USB_CAMERA_MINOR */#define	USB_CAMERA_MINOR	170/* Application protocol limit is 0x8002; USB has disliked that limit! */#define	MAX_PACKET_SIZE		0x2000		/* e.g. image downloading */#define	MAX_READ_RETRY		5		/* times to retry reads */#define	MAX_WRITE_RETRY		5		/* times to retry writes */#define	RETRY_TIMEOUT		(HZ)		/* sleep between retries *//* table of cameras that work through this driver */static const struct camera {	short		idVendor;	short		idProduct;	/* plus hooks for camera-specific info if needed */} cameras [] = {    { 0x040a, 0x0120 },		// Kodak DC-240    { 0x040a, 0x0130 },		// Kodak DC-280	/* Kodak has several other USB-enabled devices, which (along with	 * models from other vendors) all use the Flashpoint "Digita	 * OS" and its wire protocol.  These use a different application	 * level protocol from the DC-240/280 models.  Note that Digita	 * isn't just for cameras -- Epson has a non-USB Digita printer.	 *///  { 0x040a, 0x0100 },		// Kodak DC-220    { 0x040a, 0x0110 },		// Kodak DC-260    { 0x040a, 0x0111 },		// Kodak DC-265    { 0x040a, 0x0112 },		// Kodak DC-290//  { 0x03f0, 0xffff },		// HP PhotoSmart C500	/* Other USB cameras may well work here too, so long as they	 * just stick to half duplex packet exchanges and bulk messages.	 * Some non-camera devices have also been shown to work.	 */};struct camera_state {	/* these fields valid (dev != 0) iff camera connected */	struct usb_device	*dev;		/* USB device handle */	char			inEP;		/* read endpoint */	char			outEP;		/* write endpoint */	const struct camera	*info;		/* DC-240, etc */	/* valid iff isOpen */	int			isOpen;		/* device opened? */	int			isActive;	/* I/O taking place? */	char			*buf;		/* buffer for I/O */	/* always valid */	wait_queue_head_t	wait;		/* for timed waits */};/* For now, we only support one camera at a time: there's one * application-visible device (e.g. /dev/kodak) and the second * (to Nth) camera detected on the bus is ignored. */static struct camera_state static_camera_state;static ssize_t camera_read (struct file *file,	char *buf, size_t len, loff_t *ppos){	struct camera_state	*camera;	int			retries;	camera = (struct camera_state *) file->private_data;	if (len > MAX_PACKET_SIZE)		return -EINVAL;	if (camera->isActive++)		return -EBUSY;	/* Big reads are common, for image downloading.  Smaller ones	 * are also common (even "directory listing" commands don't	 * send very much data).  We preserve packet boundaries here,	 * they matter in the application protocol.	 */	for (retries = 0; retries < MAX_READ_RETRY; retries++) {		int			count;		int			result;		if (signal_pending (current)) {			camera->isActive = 0;			return -EINTR;		}		if (!camera->dev) {			camera->isActive = 0;			return -ENODEV;		}		result = usb_bulk_msg (camera->dev,			  usb_rcvbulkpipe (camera->dev, camera->inEP),			  camera->buf, len, &count, HZ*10);		dbg("read (%d) - 0x%x %d", len, result, count);		if (!result) {			if (copy_to_user (buf, camera->buf, count))				return -EFAULT;			camera->isActive = 0;			return count;		}		if (result != USB_ST_TIMEOUT)			break;		interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT);		dbg("read (%d) - retry", len);	}	camera->isActive = 0;	return -EIO;}static ssize_t camera_write (struct file *file,	const char *buf, size_t len, loff_t *ppos){	struct camera_state	*camera;	ssize_t			bytes_written = 0;	camera = (struct camera_state *) file->private_data;	if (len > MAX_PACKET_SIZE)		return -EINVAL;	if (camera->isActive++)		return -EBUSY;		/* most writes will be small: simple commands, sometimes with	 * parameters.  putting images (like borders) into the camera	 * would be the main use of big writes.	 */	while (len > 0) {		char		*obuf = camera->buf;		int		maxretry = MAX_WRITE_RETRY;		unsigned long	copy_size, thistime;		/* it's not clear that retrying can do any good ... or that		 * fragmenting application packets into N writes is correct.		 */		thistime = copy_size = len;		if (copy_from_user (obuf, buf, copy_size)) {			bytes_written = -EFAULT;			break;		}		while (thistime) {			int		result;			int		count;			if (signal_pending (current)) {				if (!bytes_written)					bytes_written = -EINTR;				goto done;			}			if (!camera->dev) {				if (!bytes_written)					bytes_written = -ENODEV;				goto done;			}			result = usb_bulk_msg (camera->dev,				 usb_sndbulkpipe (camera->dev, camera->outEP),				 obuf, thistime, &count, HZ*10);			if (result)				dbg("write USB err - %x", result);			if (count) {				obuf += count;				thistime -= count;				maxretry = MAX_WRITE_RETRY;				continue;			} else if (!result)				break;							if (result == USB_ST_TIMEOUT) {	/* NAK - delay a bit */				if (!maxretry--) {					if (!bytes_written)						bytes_written = -ETIME;					goto done;				}                                interruptible_sleep_on_timeout (&camera->wait,					RETRY_TIMEOUT);				continue;			} 			if (!bytes_written)				bytes_written = -EIO;			goto done;		}		bytes_written += copy_size;		len -= copy_size;		buf += copy_size;	}done:	camera->isActive = 0;	dbg("write %d", bytes_written); 	return bytes_written;}static int camera_open (struct inode *inode, struct file *file){	struct camera_state *camera = &static_camera_state;	/* ignore camera->dev so it can be turned on "late" */	if (camera->isOpen++)		return -EBUSY;	if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) {		camera->isOpen = 0;		return -ENOMEM;	}	dbg("open"); 		/* Keep driver from being unloaded while it's in use */	MOD_INC_USE_COUNT;	camera->isActive = 0;	file->private_data = camera;	return 0;}static int camera_release (struct inode *inode, struct file *file){	struct camera_state *camera;	camera = (struct camera_state *) file->private_data;	kfree (camera->buf);	camera->isOpen = 0;	MOD_DEC_USE_COUNT;	dbg("close"); 	return 0;}	/* XXX should define some ioctls to expose camera type	 * to applications ... what USB exposes should suffice.	 * apps should be able to see the camera type.	 */static /* const */ struct file_operations usb_camera_fops = {	NULL,		/* llseek */	camera_read,	camera_write,	NULL, 		/* readdir */	NULL,		/* poll */	NULL,		/* ioctl */	NULL,		/* mmap */	camera_open,	NULL,		/* flush */	camera_release,	NULL,		/* async */	NULL,		/* fasync */	NULL,		/* lock */};static struct miscdevice usb_camera = {	USB_CAMERA_MINOR,	"USB camera (Kodak DC-2xx)",	&usb_camera_fops	// next, prev};static void * camera_probe(struct usb_device *dev, unsigned int ifnum){	int				i;	const struct camera		*camera_info = NULL;	struct usb_interface_descriptor	*interface;	struct usb_endpoint_descriptor	*endpoint;	int				direction, ep;	struct camera_state		*camera = &static_camera_state;	/* Is it a supported camera? */	for (i = 0; i < sizeof (cameras) / sizeof (struct camera); i++) {		if (cameras [i].idVendor != dev->descriptor.idVendor)			continue;		if (cameras [i].idProduct != dev->descriptor.idProduct)			continue;		camera_info = &cameras [i];		break;	}	if (camera_info == NULL)		return NULL;	/* these have one config, one interface */	if (dev->descriptor.bNumConfigurations != 1			|| dev->config[0].bNumInterfaces != 1) {		dbg("Bogus camera config info");		return NULL;	}	/* models differ in how they report themselves */	interface = &dev->actconfig->interface[ifnum].altsetting[0];	if ((interface->bInterfaceClass != USB_CLASS_PER_INTERFACE		&& interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC)			|| interface->bInterfaceSubClass != 0			|| interface->bInterfaceProtocol != 0			|| interface->bNumEndpoints != 2			) {		dbg("Bogus camera interface info");		return NULL;	}	/* can only show one camera at a time through /dev ... */	if (!camera->dev) {		camera->dev = dev;		info("USB Camera is connected");	} else {		info("Ignoring additional USB Camera");		return NULL;	}	/* get input and output endpoints (either order) */	endpoint = interface->endpoint;	camera->outEP = camera->inEP =  -1;	ep = endpoint [0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;	direction = endpoint [0].bEndpointAddress & USB_ENDPOINT_DIR_MASK;	if (direction == USB_DIR_IN)		camera->inEP = ep;	else		camera->outEP = ep;	ep = endpoint [1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;	direction = endpoint [1].bEndpointAddress & USB_ENDPOINT_DIR_MASK;	if (direction == USB_DIR_IN)		camera->inEP = ep;	else		camera->outEP = ep;	if (camera->outEP == -1 || camera->inEP == -1			|| endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK			|| endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK			) {		dbg("Bogus camera endpoints");		camera->dev = NULL;		return NULL;	}	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue)) {		err("Failed usb_set_configuration");		camera->dev = NULL;		return NULL;	}	camera->info = camera_info;	return camera;}static void camera_disconnect(struct usb_device *dev, void *ptr){	struct camera_state	*camera = (struct camera_state *) ptr;	if (camera->dev != dev)		return;	/* Currently not reflecting this up to userland; at one point	 * it got called on bus reconfig, which we clearly don't want.	 * A good consequence is the ability to remove camera for	 * a while without apps needing to do much more than ignore	 * some particular error returns.  On the bad side, if one	 * camera is swapped for another one, we won't be telling.	 */	camera->info = NULL;	camera->dev = NULL;	info("USB Camera disconnected");}static /* const */ struct usb_driver camera_driver = {	"dc2xx",	camera_probe,	camera_disconnect,	{ NULL, NULL },	NULL,	/* &usb_camera_fops, */	0	/* USB_CAMERA_MINOR */};#ifdef MODULEstatic __init#endifint usb_dc2xx_init(void){	struct camera_state *camera = &static_camera_state;	camera->dev = NULL;	camera->isOpen = 0;	camera->isActive = 0;	init_waitqueue_head (&camera->wait);	if (usb_register (&camera_driver) < 0)		return -1;	misc_register (&usb_camera);	return 0;}#ifdef MODULEstatic __exit#endifvoid usb_dc2xx_cleanup(void){	usb_deregister (&camera_driver);	misc_deregister (&usb_camera);}#ifdef MODULEMODULE_AUTHOR("David Brownell, david-b@pacbell.net");MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras");module_init (usb_dc2xx_init);module_exit (usb_dc2xx_cleanup);#endif	/* MODULE */

⌨️ 快捷键说明

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