📄 dc2xx.c
字号:
/* * Copyright (C) 1999-2000 by David Brownell <dbrownell@users.sourceforge.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. They'll need * to be the sort using USB just as a fast bulk data channel. *//* * 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. * 08 Jan, 2000 .. multiple camera support * 12 Aug, 2000 .. add some real locking, remove an Oops * 10 Oct, 2000 .. usb_device_id table created. * 01 Nov, 2000 .. usb_device_id support added by Adam J. Richter * 08 Apr, 2001 .. Identify version on module load. gb * * Thanks to: the folk who've provided USB product IDs, sent in * patches, and shared their successes! */#include <linux/config.h>#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/slab.h>#include <linux/module.h>#include <linux/devfs_fs_kernel.h>#ifdef CONFIG_USB_DEBUG #define DEBUG#else #undef DEBUG#endif#include <linux/usb.h>/* /dev/usb dir. */extern devfs_handle_t usb_devfs_handle; /* * Version Information */#define DRIVER_VERSION "v1.0.0"#define DRIVER_AUTHOR "David Brownell, <dbrownell@users.sourceforge.net>"#define DRIVER_DESC "USB Camera Driver for Kodak DC-2xx series cameras"/* current USB framework handles max of 16 USB devices per driver */#define MAX_CAMERAS 16/* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */#define USB_CAMERA_MINOR_BASE 80// XXX remove packet size limit, now that bulk transfers seem fixed/* 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 usb_device_id camera_table [] = { /* These have the same application level protocol */ { USB_DEVICE(0x040a, 0x0120) }, // Kodak DC-240 { USB_DEVICE(0x040a, 0x0130) }, // Kodak DC-280 { USB_DEVICE(0x040a, 0x0131) }, // Kodak DC-5000 { USB_DEVICE(0x040a, 0x0132) }, // Kodak DC-3400 /* These have a different application level protocol which * is part of the Flashpoint "DigitaOS". That supports some * non-camera devices, and some non-Kodak cameras. * Use this driver to get USB and "OpenDis" to talk. */ { USB_DEVICE(0x040a, 0x0100) }, // Kodak DC-220 { USB_DEVICE(0x040a, 0x0110) }, // Kodak DC-260 { USB_DEVICE(0x040a, 0x0111) }, // Kodak DC-265 { USB_DEVICE(0x040a, 0x0112) }, // Kodak DC-290 { USB_DEVICE(0xf003, 0x6002) }, // HP PhotoSmart C500 { USB_DEVICE(0x03f0, 0x4102) }, // HP PhotoSmart C618 { USB_DEVICE(0x0a17, 0x1001) }, // Pentax EI-200 /* Other USB devices may well work here too, so long as they * just stick to half duplex bulk packet exchanges. That * means, among other things, no iso or interrupt endpoints. */ { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, camera_table);struct camera_state { struct usb_device *dev; /* USB device handle */ int inEP; /* read endpoint */ int outEP; /* write endpoint */ const struct usb_device_id *info; /* DC-240, etc */ int subminor; /* which minor dev #? */ struct semaphore sem; /* locks this struct */ /* this is non-null iff the device is open */ char *buf; /* buffer for I/O */ devfs_handle_t devfs; /* devfs device */ /* always valid */ wait_queue_head_t wait; /* for timed waits */};/* Support multiple cameras, possibly of different types. */static struct camera_state *minor_data [MAX_CAMERAS];/* make this an rwlock if contention becomes an issue */static DECLARE_MUTEX (state_table_mutex);static ssize_t camera_read (struct file *file, char *buf, size_t len, loff_t *ppos){ struct camera_state *camera; int retries; int retval = 0; if (len > MAX_PACKET_SIZE) return -EINVAL; camera = (struct camera_state *) file->private_data; down (&camera->sem); if (!camera->dev) { up (&camera->sem); return -ENODEV; } /* 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; if (signal_pending (current)) { retval = -EINTR; break; } retval = usb_bulk_msg (camera->dev, usb_rcvbulkpipe (camera->dev, camera->inEP), camera->buf, len, &count, HZ*10); dbg ("read (%Zd) - 0x%x %d", len, retval, count); if (!retval) { if (copy_to_user (buf, camera->buf, count)) retval = -EFAULT; else retval = count; break; } if (retval != USB_ST_TIMEOUT) break; interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT); dbg ("read (%Zd) - retry", len); } up (&camera->sem); return retval;}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; if (len > MAX_PACKET_SIZE) return -EINVAL; camera = (struct camera_state *) file->private_data; down (&camera->sem); if (!camera->dev) { up (&camera->sem); return -ENODEV; } /* 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; } result = usb_bulk_msg (camera->dev, usb_sndbulkpipe (camera->dev, camera->outEP), obuf, thistime, &count, HZ*10); if (result) dbg ("write USB err - %d", 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: up (&camera->sem); dbg ("wrote %Zd", bytes_written); return bytes_written;}static int camera_open (struct inode *inode, struct file *file){ struct camera_state *camera = NULL; int subminor; int value = 0; down (&state_table_mutex); subminor = MINOR (inode->i_rdev) - USB_CAMERA_MINOR_BASE; if (subminor < 0 || subminor >= MAX_CAMERAS || !(camera = minor_data [subminor])) { up (&state_table_mutex); return -ENODEV; } down (&camera->sem); up (&state_table_mutex); if (camera->buf) { value = -EBUSY; goto done; } if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) { value = -ENOMEM; goto done; } dbg ("open #%d", subminor); file->private_data = camera;done: up (&camera->sem); return value;}static int camera_release (struct inode *inode, struct file *file){ struct camera_state *camera; int subminor; camera = (struct camera_state *) file->private_data; down (&state_table_mutex); down (&camera->sem); if (camera->buf) { kfree (camera->buf); camera->buf = 0; } subminor = camera->subminor; /* If camera was unplugged with open file ... */ if (!camera->dev) { minor_data [subminor] = NULL; kfree (camera); } else up (&camera->sem); up (&state_table_mutex); dbg ("close #%d", subminor); 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 = { /* Uses GCC initializer extension; simpler to maintain */ owner: THIS_MODULE, read: camera_read, write: camera_write, open: camera_open, release: camera_release,};static void *camera_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *camera_info){ int i; struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; int direction, ep; char name[8]; struct camera_state *camera = 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; } /* select "subminor" number (part of a minor number) */ down (&state_table_mutex); for (i = 0; i < MAX_CAMERAS; i++) { if (!minor_data [i]) break; } if (i >= MAX_CAMERAS) { info ("Ignoring additional USB Camera"); goto bye; } /* allocate & init camera state */ camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL); if (!camera) { err ("no memory!"); goto bye; } init_MUTEX (&camera->sem); camera->info = camera_info; camera->subminor = i; camera->buf = NULL; init_waitqueue_head (&camera->wait); /* 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 endpoints"); goto error; } info ("USB Camera #%d connected, major/minor %d/%d", camera->subminor, USB_MAJOR, USB_CAMERA_MINOR_BASE + camera->subminor); camera->dev = dev; usb_inc_dev_use (dev); /* If we have devfs, register the device */ sprintf(name, "dc2xx%d", camera->subminor); camera->devfs = devfs_register(usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, USB_CAMERA_MINOR_BASE + camera->subminor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &usb_camera_fops, NULL); goto bye;error: minor_data [camera->subminor] = NULL; kfree (camera); camera = NULL;bye: up (&state_table_mutex); return camera;}static void camera_disconnect(struct usb_device *dev, void *ptr){ struct camera_state *camera = (struct camera_state *) ptr; int subminor = camera->subminor; down (&state_table_mutex); down (&camera->sem); devfs_unregister(camera->devfs); /* If camera's not opened, we can clean up right away. * Else apps see a disconnect on next I/O; the release cleans. */ if (!camera->buf) { minor_data [subminor] = NULL; kfree (camera); camera = NULL; } else camera->dev = NULL; info ("USB Camera #%d disconnected", subminor); usb_dec_dev_use (dev); if (camera != NULL) up (&camera->sem); up (&state_table_mutex);}static /* const */ struct usb_driver camera_driver = { name: "dc2xx", id_table: camera_table, probe: camera_probe, disconnect: camera_disconnect, fops: &usb_camera_fops, minor: USB_CAMERA_MINOR_BASE};int __init usb_dc2xx_init(void){ if (usb_register (&camera_driver) < 0) return -1; info(DRIVER_VERSION ":" DRIVER_DESC); return 0;}void __exit usb_dc2xx_cleanup(void){ usb_deregister (&camera_driver);}module_init (usb_dc2xx_init);module_exit (usb_dc2xx_cleanup);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -