patch-2.3.26 linux/drivers/usb/dc2xx.c

Next file: linux/drivers/usb/ezusb.c
Previous file: linux/drivers/usb/cpia.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.25/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c
@@ -0,0 +1,497 @@
+/*
+ * 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.
+ */
+
+#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>
+
+#include "usb.h"
+
+
+// #define	CAMERA_DEBUG
+
+
+/* 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 struct camera {
+	short		idVendor;
+	short		idProduct;
+
+	/* should get this name from the USB subsystem */
+	const char	*nameProduct;
+} 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.  This driver should work with such
+	 * devices, which need different application level protocol code
+	 * from the DC-240/280 models.  Note that Digita isn't just for
+	 * cameras -- Epson has a non-USB Digita photo printer.
+	 */
+/*  { 0x040a, 0x0100, "Kodak DC-220" }, */
+    { 0x040a, 0x0110, "Kodak DC-260" },
+/*  { 0x040a, 0x0115, "Kodak DC-265" }, */
+/*  { 0x040a, 0x0140, "Kodak DC-290" }, */
+
+/*  { 0xffff, 0xffff, "Minolta Dimage EX 1500" }, */
+/*  { 0x03f0, 0xffff, "HP PhotoSmart C500" }, */
+
+	/* Other USB cameras may well work here too, so long as they
+	 * just stick to half duplex packet exchanges.
+	 */
+};
+
+
+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 */
+	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++) {
+		unsigned long		count;
+		int			result;
+
+		if (signal_pending (current)) {
+			camera->isActive = 0;
+			return -EINTR;
+		}
+		if (!camera->dev) {
+			camera->isActive = 0;
+			return -ENODEV;
+		}
+
+		result = camera->dev->bus->op->bulk_msg (camera->dev,
+			  usb_rcvbulkpipe (camera->dev, camera->inEP),
+			  camera->buf, len, &count, HZ*10);
+#ifdef	CAMERA_DEBUG
+		printk ("camera.r (%d) - 0x%x %ld\n", len, result, count);
+#endif
+		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);
+#ifdef	CAMERA_DEBUG
+		printk ("camera.r (%d) - retry\n", len);
+#endif
+	}
+	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.
+		 * consider those mechanisms mostly untested legacy code
+		 */
+		thistime = copy_size = len;
+		if (copy_from_user (obuf, buf, copy_size)) {
+			bytes_written = -EFAULT;
+			break;
+		}
+		while (thistime) {
+			int		result;
+			unsigned long	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 = camera->dev->bus->op->bulk_msg (camera->dev,
+				 usb_sndbulkpipe (camera->dev, camera->outEP),
+				 obuf, thistime, &count, HZ*10);
+#ifdef	CAMERA_DEBUG
+			if (result)
+				printk ("camera.w USB err - %x\n", result);
+#endif
+			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;
+#ifdef	CAMERA_DEBUG
+	printk ("camera.w %d\n", bytes_written); 
+#endif
+	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;
+	}
+#ifdef	CAMERA_DEBUG
+	printk ("camera.open\n"); 
+#endif
+	
+	/* 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;
+#ifdef	CAMERA_DEBUG
+	printk ("camera.close\n"); 
+#endif
+
+	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 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,		/* check_media_change */
+	NULL,		/* revalidate */
+	NULL,		/* lock */
+};
+
+static struct miscdevice usb_camera = {
+	USB_CAMERA_MINOR,
+	"USB camera (Kodak DC-2xx)",
+	&usb_camera_fops
+};
+
+
+
+static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	int				i;
+	struct camera			*camera_info = NULL;
+	struct usb_interface_descriptor	*interface;
+	struct usb_endpoint_descriptor	*endpoint;
+
+	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) {
+		printk (KERN_INFO "Bogus camera config info\n");
+		return NULL;
+	}
+
+	/* the interface class bit is odd -- the dc240 and dc260 return
+	 * a zero there, and at least some dc280s report 0xff
+	 */
+	// interface = &dev->config[0].interface[0].altsetting[0];
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	if ((interface->bInterfaceClass != 0
+				&& interface->bInterfaceClass != 0xff)
+			|| interface->bInterfaceSubClass != 0
+			|| interface->bInterfaceProtocol != 0
+			|| interface->bNumEndpoints != 2
+			) {
+		printk (KERN_INFO "Bogus camera interface info\n");
+		return NULL;
+	}
+
+	/* can only show one camera at a time through /dev ... */
+	if (!camera->dev) {
+		camera->dev = dev;
+		printk(KERN_INFO "USB Camera (%s) is connected\n",
+				camera_info->nameProduct);
+	} else {
+		printk(KERN_INFO "Ignoring additional USB Camera (%s)\n",
+				camera_info->nameProduct);
+		return NULL;
+	}
+
+// XXX there are now masks for these constants ... see printer.c
+
+	/* get input and output endpoints (either order) */
+	endpoint = interface->endpoint;
+	camera->outEP = camera->inEP =  -1;
+	if ((endpoint [0].bEndpointAddress & 0x80) == 0x80)
+		camera->inEP = endpoint [0].bEndpointAddress & 0x7f;
+	else
+		camera->outEP = endpoint [0].bEndpointAddress;
+
+	if ((endpoint [1].bEndpointAddress & 0x80) == 0x80)
+		camera->inEP = endpoint [1].bEndpointAddress & 0x7f;
+	else
+		camera->outEP = endpoint [1].bEndpointAddress;
+	if (camera->outEP == -1 || camera->inEP == -1
+			|| endpoint [0].bmAttributes != 0x02
+			|| endpoint [1].bmAttributes != 0x02
+			) {
+		printk (KERN_INFO "Bogus camera endpoints\n");
+		camera->dev = NULL;
+		return NULL;
+	}
+
+
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue)) {
+		printk (KERN_INFO "Failed usb_set_configuration: camera\n");
+		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;
+	struct camera		*info = camera->info;
+
+	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;
+
+	printk (KERN_INFO "USB Camera (%s) disconnected\n", info->nameProduct);
+}
+
+static struct usb_driver camera_driver = {
+	"dc2xx",
+	camera_probe,
+	camera_disconnect,
+	{ NULL, NULL },
+
+	NULL,	/* &usb_camera_fops, */
+	0	/* USB_CAMERA_MINOR */
+};
+
+
+#ifdef MODULE
+static __init
+#endif
+int 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 MODULE
+static __exit
+#endif
+void usb_dc2xx_cleanup(void)
+{
+	usb_deregister (&camera_driver);
+	misc_deregister (&usb_camera);
+}
+
+
+#ifdef MODULE
+
+MODULE_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 */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)