blob: 6407e61c370e8455e738c0394a1339f007223211 [file] [log] [blame]
/* -*- linux-c -*- */
/*
* Driver for USB Scanners (linux-2.4)
*
* Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
* Copyright (C) 2002, 2003 Henning Meier-Geinitz
*
* Portions may be copyright Brad Keryan and Michael Gee.
*
* Previously maintained by Brian Beattie
*
* Current maintainer: Henning Meier-Geinitz <henning@meier-geinitz.de>
*
* 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.
*
* Originally based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
*
* History
*
* 0.1 8/31/1999
*
* Developed/tested using linux-2.3.15 with minor ohci.c changes to
* support short packes during bulk xfer mode. Some testing was
* done with ohci-hcd but the performace was low. Very limited
* testing was performed with uhci but I was unable to get it to
* work. Initial relase to the linux-usb development effort.
*
*
* 0.2 10/16/1999
*
* - Device can't be opened unless a scanner is plugged into the USB.
* - Finally settled on a reasonable value for the I/O buffer's.
* - Cleaned up write_scanner()
* - Disabled read/write stats
* - A little more code cleanup
*
*
* 0.3 10/18/1999
*
* - Device registration changed to reflect new device
* allocation/registration for linux-2.3.22+.
* - Adopted David Brownell's <david-b@pacbell.net> technique for
* assigning bulk endpoints.
* - Removed unnessesary #include's
* - Scanner model now reported via syslog INFO after being detected
* *and* configured.
* - Added user specified vendor:product USB ID's which can be passed
* as module parameters.
*
*
* 0.3.1
*
* - Applied patches for linux-2.3.25.
* - Error number reporting changed to reflect negative return codes.
*
*
* 0.3.2
*
* - Applied patches for linux-2.3.26 to scanner_init().
* - Debug read/write stats now report values as signed decimal.
*
*
* 0.3.3
*
* - Updated the bulk_msg() calls to usb usb_bulk_msg().
* - Added a small delay in the write_scanner() method to aid in
* avoiding NULL data reads on HP scanners. We'll see how this works.
* - Return values from usb_bulk_msg() now ignore positive values for
* use with the ohci driver.
* - Added conditional debugging instead of commenting/uncommenting
* all over the place.
* - kfree()'d the pointer after using usb_string() as documented in
* linux-usb-api.txt.
* - Added usb_set_configuration(). It got lost in version 0.3 -- ack!
* - Added the HP 5200C USB Vendor/Product ID's.
*
*
* 0.3.4 1/23/2000
*
* - Added Greg K-H's <greg@kroah.com> patch for better handling of
* Product/Vendor detection.
* - The driver now autoconfigures its endpoints including interrupt
* endpoints if one is detected. The concept was originally based
* upon David Brownell's method.
* - Added some Seiko/Epson ID's. Thanks to Karl Heinz
* Kremer <khk@khk.net>.
* - Added some preliminary ioctl() calls for the PV8630 which is used
* by the HP4200. The ioctl()'s still have to be registered. Thanks
* to Adrian Perez Jorge <adrianpj@easynews.com>.
* - Moved/migrated stuff to scanner.h
* - Removed the usb_set_configuration() since this is handled by
* the usb_new_device() routine in usb.c.
* - Added the HP 3300C. Thanks to Bruce Tenison.
* - Changed user specified vendor/product id so that root hub doesn't
* get falsely attached to. Thanks to Greg K-H.
* - Added some Mustek ID's. Thanks to Gernot Hoyler
* <Dr.Hoyler@t-online.de>.
* - Modified the usb_string() reporting. See kfree() comment above.
* - Added Umax Astra 2000U. Thanks to Doug Alcorn <doug@lathi.net>.
* - Updated the printk()'s to use the info/warn/dbg macros.
* - Updated usb_bulk_msg() argument types to fix gcc warnings.
*
*
* 0.4 2/4/2000
*
* - Removed usb_string() from probe_scanner since the core now does a
* good job of reporting what was connnected.
* - Finally, simultaneous multiple device attachment!
* - Fixed some potential memory freeing issues should memory allocation
* fail in probe_scanner();
* - Some fixes to disconnect_scanner().
* - Added interrupt endpoint support.
* - Added Agfa SnapScan Touch. Thanks to Jan Van den Bergh
* <jan.vandenbergh@cs.kuleuven.ac.be>.
* - Added Umax 1220U ID's. Thanks to Maciek Klimkowski
* <mac@nexus.carleton.ca>.
* - Fixed bug in write_scanner(). The buffer was not being properly
* updated for writes larger than OBUF_SIZE. Thanks to Henrik
* Johansson <henrikjo@post.utfors.se> for identifying it.
* - Added Microtek X6 ID's. Thanks to Oliver Neukum
* <Oliver.Neukum@lrz.uni-muenchen.de>.
*
*
* 0.4.1 2/15/2000
*
* - Fixed 'count' bug in read_scanner(). Thanks to Henrik
* Johansson <henrikjo@post.utfors.se> for identifying it. Amazing
* it has worked this long.
* - Fixed '>=' bug in both read/write_scanner methods.
* - Cleaned up both read/write_scanner() methods so that they are
* a little more readable.
* - Added a lot of Microtek ID's. Thanks to Adrian Perez Jorge.
* - Adopted the __initcall().
* - Added #include <linux/init.h> to scanner.h for __initcall().
* - Added one liner in irq_scanner() to keep gcc from complaining
* about an unused variable (data) if debugging was disabled
* in scanner.c.
* - Increased the timeout parameter in read_scanner() to 120 Secs.
*
*
* 0.4.2 3/23/2000
*
* - Added Umax 1236U ID. Thanks to Philipp Baer <ph_baer@npw.net>.
* - Added Primax, ReadyScan, Visioneer, Colorado, and Genius ID's.
* Thanks to Adrian Perez Jorge <adrianpj@easynews.com>.
* - Fixed error number reported for non-existant devices. Thanks to
* Spyridon Papadimitriou <Spyridon_Papadimitriou@gs91.sp.cs.cmu.edu>.
* - Added Acer Prisascan 620U ID's. Thanks to Joao <joey@knoware.nl>.
* - Replaced __initcall() with module_init()/module_exit(). Updates
* from patch-2.3.48.
* - Replaced file_operations structure with new syntax. Updates
* from patch-2.3.49.
* - Changed #include "usb.h" to #include <linux/usb.h>
* - Added #define SCN_IOCTL to exclude development areas
* since 2.4.x is about to be released. This mainly affects the
* ioctl() stuff. See scanner.h for more details.
* - Changed the return value for signal_pending() from -ERESTARTSYS to
* -EINTR.
*
*
* 0.4.3 4/30/2000
*
* - Added Umax Astra 2200 ID. Thanks to Flynn Marquardt
* <flynn@isr.uni-stuttgart.de>.
* - Added iVina 1200U ID. Thanks to Dyson Lin <dyson@avision.com.tw>.
* - Added access time update for the device file courtesy of Paul
* Mackerras <paulus@samba.org>. This allows a user space daemon
* to turn the lamp off for a Umax 1220U scanner after a prescribed
* time.
* - Fixed HP S20 ID's. Thanks to Ruud Linders <rlinders@xs4all.nl>.
* - Added Acer ScanPrisa 620U ID. Thanks to Oliver
* Schwartz <Oliver.Schwartz@gmx.de> via sane-devel mail list.
* - Fixed bug in read_scanner for copy_to_user() function. The returned
* value should be 'partial' not 'this_read'.
* - Fixed bug in read_scanner. 'count' should be decremented
* by 'this_read' and not by 'partial'. This resulted in twice as many
* calls to read_scanner() for small amounts of data and possibly
* unexpected returns of '0'. Thanks to Karl Heinz
* Kremer <khk@khk.net> and Alain Knaff <Alain.Knaff@ltnb.lu>
* for discovering this.
* - Integrated Randy Dunlap's <randy.dunlap@intel.com> patch for a
* scanner lookup/ident table. Thanks Randy.
* - Documentation updates.
* - Added wait queues to read_scanner().
*
*
* 0.4.3.1
*
* - Fixed HP S20 ID's...again..sigh. Thanks to Ruud
* Linders <rlinders@xs4all.nl>.
*
* 0.4.4
* - Added addtional Mustek ID's (BearPaw 1200, 600 CU, 1200 USB,
* and 1200 UB. Thanks to Henning Meier-Geinitz <henningmg@gmx.de>.
* - Added the Vuego Scan Brisa 340U ID's. Apparently this scanner is
* marketed by Acer Peripherals as a cheap 300 dpi model. Thanks to
* David Gundersen <gundersd@paradise.net.nz>.
* - Added the Epson Expression1600 ID's. Thanks to Karl Heinz
* Kremer <khk@khk.net>.
*
* 0.4.5 2/28/2001
* - Added Mustek ID's (BearPaw 2400, 1200 CU Plus, BearPaw 1200F).
* Thanks to Henning Meier-Geinitz <henningmg@gmx.de>.
* - Added read_timeout module parameter to override RD_NAK_TIMEOUT
* when read()'ing from devices.
* - Stalled pipes are now checked and cleared with
* usb_clear_halt() for the read_scanner() function. This should
* address the "funky result: -32" error messages.
* - Removed Microtek scanner ID's. Microtek scanners are now
* supported via the drivers/usb/microtek.c driver.
* - Added scanner specific read timeout's.
* - Return status errors are NEGATIVE!!! This should address the
* "funky result: -110" error messages.
* - Replaced USB_ST_TIMEOUT with ETIMEDOUT.
* - rd_nak was still defined in MODULE_PARM. It's been updated with
* read_timeout. Thanks to Mark W. Webb <markwebb@adelphia.net> for
* reporting this bug.
* - Added Epson Perfection 1640SU and 1640SU Photo. Thanks to
* Jean-Luc <f5ibh@db0bm.ampr.org> and Manuel
* Pelayo <Manuel.Pelayo@sesips.org>. Reported to work fine by Manuel.
*
* 0.4.6 9/27/2001
* - Added IOCTL's to report back scanner USB ID's. Thanks to
* Karl Heinz <khk@lynx.phpwebhosting.com>
* - Added Umax Astra 2100U ID's. Thanks to Ron
* Wellsted <ron@wellsted.org.uk>.
* and Manuel Pelayo <Manuel.Pelayo@sesips.org>.
* - Added HP 3400 ID's. Thanks to Harald Hannelius <harald@iki.fi>
* and Bertrik Sikken <bertrik@zonnet.nl>. Reported to work at
* htpp://home.zonnet.nl/bertrik/hp3300c/hp3300c.htm.
* - Added Minolta Dimage Scan Dual II ID's. Thanks to Jose Paulo
* Moitinho de Almeida <moitinho@civil.ist.utl.pt>
* - Confirmed addition for SnapScan E20. Thanks to Steffen Hübner
* <hueb_s@gmx.de>.
* - Added Lifetec LT9385 ID's. Thanks to Van Bruwaene Kris
* <krvbr@yahoo.co.uk>
* - Added Agfa SnapScan e26 ID's. Reported to work with SANE
* 1.0.5. Thanks to Falk Sauer <falk@mgnkatze.franken.de>.
* - Added HP 4300 ID's. Thanks to Stefan Schlosser
* <castla@grmmbl.org>.
* - Added Relisis Episode ID's. Thanks to Manfred
* Morgner <odb-devel@gmx.net>.
* - Added many Acer ID's. Thanks to Oliver
* Schwartz <Oliver.Schwartz@gmx.de>.
* - Added Snapscan e40 ID's. Thanks to Oliver
* Schwartz <Oliver.Schwartz@gmx.de>.
* - Thanks to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
* for helping with races.
* - Added Epson Perfection 1650 ID's. Thanks to Karl Heinz
* Kremer <khk@khk.net>.
* - Added Epson Perfection 2450 ID's (aka GT-9700 for the Japanese
* market). Thanks to Karl Heinz Kremer <khk@khk.net>.
* - Added Mustek 600 USB ID's. Thanks to Marcus
* Alanen <maalanen@ra.abo.fi>.
* - Added Acer ScanPrisa 1240UT ID's. Thanks to Morgan
* Collins <sirmorcant@morcant.org>.
* - Incorporated devfs patches!! Thanks to Tom Rini
* <trini@kernel.crashing.org>, Pavel Roskin <proski@gnu.org>,
* Greg KH <greg@kroah.com>, Yves Duret <yduret@mandrakesoft.com>,
* Flavio Stanchina <flavio.stanchina@tin.it>.
* - Removed Minolta ScanImage II. This scanner uses USB SCSI. Thanks
* to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de> for pointing
* this out.
* - Added additional SMP locking. Thanks to David Brownell and
* Oliver Neukum for their help.
* - Added version reporting - reports for both module load and modinfo
* - Started path to hopefully straighten/clean out ioctl()'s.
* - Users are now notified to consult the Documentation/usb/scanner.txt
* for common error messages rather than the maintainer.
*
* 0.4.7 11/28/2001
* - Fixed typo in Documentation/scanner.txt. Thanks to
* Karel <karel.vervaeke@pandora.be> for pointing it out.
* - Added ID's for a Memorex 6136u. Thanks to Álvaro Gaspar de
* Valenzuela" <agaspard@utsi.edu>.
* - Added ID's for Agfa e25. Thanks to Heinrich
* Rust <Heinrich.Rust@gmx.de>. Also reported to work with
* Linux and SANE (?).
* - Added Canon FB620U, D646U, and 1220U ID's. Thanks to Paul
* Rensing <Paul_Rensing@StanfordAlumni.org>. For more info
* on Linux support for these models, contact
* salvestrini@users.sourceforge.net.
* - Added Plustek OpticPro UT12, OpticPro U24, KYE/Genius
* ColorPage-HR6 V2 ID's in addition to many "Unknown" models
* under those vendors. Thanks to
* Jaeger, Gerhard" <g.jaeger@earthling.net>. These scanner are
* apparently based upon the LM983x IC's.
* - Applied Frank's patch that addressed some locking and module
* referencing counts. Thanks to both
* Frank Zago <fzago@greshamstorage.com> and
* Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing.
*
* 0.4.8 5/30/2002
* - Added Mustek BearPaw 2400 TA. Thanks to Sergey
* Vlasov <vsu@mivlgu.murom.ru>.
* - Added Mustek 1200UB Plus and Mustek BearPaw 1200 CU ID's. These use
* the Grandtech GT-6801 chip. Thanks to Henning
* Meier-Geinitz <henning@meier-geinitz.de>.
* - Increased Epson timeout to 60 secs as requested from
* Karl Heinz Kremer <khk@khk.net>.
* - Changed maintainership from David E. Nelson to Brian
* Beattie <beattie@beattie-home.net>.
*
* 0.4.9 12/19/2002
* - Added vendor/product ids for Nikon, Mustek, Plustek, Genius, Epson,
* Canon, Umax, Hewlett-Packard, Benq, Agfa, Minolta scanners.
* Thanks to Dieter Faulbaum <faulbaum@mail.bessy.de>, Stian Jordet
* <liste@jordet.nu>, "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>,
* "Jaeger, Gerhard" <gerhard@gjaeger.de>, Ira Childress
* <ichildress@mn.rr.com>, Till Kamppeter <till.kamppeter@gmx.net>,
* Ed Hamrick <EdHamrick@aol.com>, Oliver Schwartz
* <Oliver.Schwartz@gmx.de> and everyone else who sent ids.
* - Some Benq, Genius and Plustek ids are identified now.
* - Don't clutter syslog with "Unable to access minor data" messages.
* - Accept scanners with only one bulk (in) endpoint (thanks to Sergey
* Vlasov <vsu@mivlgu.murom.ru>).
* - Accept devices with more than one interface. Only use interfaces that
* look like belonging to scanners.
* - Use altsetting[0], not altsetting[ifnum].
* - Add locking to ioctl_scanner(). Thanks to Oliver Neukum
* <oliver@neukum.name>.
*
* 0.4.10 01/07/2003
* - Added vendor/product ids for Artec, Canon, Compaq, Epson, HP, Microtek
* and Visioneer scanners. Thanks to William Lam <wklam@triad.rr.com>,
* Till Kamppeter <till.kamppeter@gmx.net> and others for all the ids.
* - Cleaned up list of vendor/product ids.
* - Print ids and device number when a device was detected.
* - Don't print errors when the device is busy.
* - Added vendor/product ids for Visioneer scanners.
* - Print information about user-supplied ids only once at startup instead
* of everytime any USB device is plugged in.
* - Removed PV8630 ioctls. Use the standard ioctls instead.
* - Made endpoint detection more generic. Basically, only one bulk-in
* endpoint is required, everything else is optional.
* - Move the scanner ioctls to usb_scanner_ioctl.h to allow access by archs
* that need it (by Greg KH).
* - New maintainer: Henning Meier-Geinitz.
* - Print ids and device number when a device was detected.
* - Don't print errors when the device is busy.
*
* 0.4.11 2003-02-25
* - Added vendor/product ids for Artec, Avision, Brother, Canon, Compaq,
* Fujitsu, Hewlett-Packard, Lexmark, LG Electronics, Medion, Microtek,
* Primax, Prolink, Plustek, SYSCAN, Trust and UMAX scanners.
*
* 0.4.12 2003-04-16
* - Fixed endpoint detection. The endpoints were numbered from 1 to n but
* that assumption is not correct in all cases.
*
*
* 0.4.13 2003-06-14
* - Added vendor/product ids for Genius, Hewlett-Packard, Microtek,
* Mustek, Pacific Image Electronics, Plustek, and Visioneer scanners.
* Fixed names of some other scanners.
*
* 0.4.14 2003-07-15
* - Added vendor/product ids for Avision, Canon, HP, Microtek and Relisys
* scanners.
* - When checking if all minors are used don't read beyond p_scn_table
* (Sergey Vlasov).
* - Kfree the scn structure only after disconnect AND close have occured and
* check for scn->present. This avoids crashing when someone writes (reads) to
* the device while it's already disconnected but still open. Patch from
* Sergey Vlasov.
* - Clean up irq urb when not enough memory is available (Sergey Vlasov).
*
* 0.4.15 2003-10-03
* - Added vendor/product ids for Canon, HP, Microtek, Mustek, Siemens, UMAX, and
* Visioneer scanners.
* - Added test for USB_CLASS_CDC_DATA which is used by some fingerprint scanners
* - Use static declarations for usb_scanner_init/usb_scanner_exit
* (Daniele Bellucci).
*
* 0.4.16 2003-11-04
* - Added vendor/product ids for Epson, Genius, Microtek, Plustek, Reflecta, and
* Visioneer scanners. Removed ids for HP PSC devices as these are supported by
* the hpoj userspace driver.
*
* TODO
* - Performance
* - Select/poll methods
* - More testing
* - More general usage ioctl's
*
*
* Thanks to:
*
* - All the folks on the linux-usb list who put up with me. :) This
* has been a great learning experience for me.
* - To Linus Torvalds for this great OS.
* - The GNU folks.
* - The folks that forwarded Vendor:Product ID's to me.
* - Johannes Erdfelt for the loaning of a USB analyzer for tracking an
* issue with HP-4100 and uhci.
* - Adolfo Montero for his assistance.
* - All the folks who chimed in with reports and suggestions.
* - All the developers that are working on USB SANE backends or other
* applications to use USB scanners.
* - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie
* and Henning Meier-Geinitz to be the new USB Scanner maintainer.
*
* Performance:
*
* System: Pentium 120, 80 MB RAM, OHCI, Linux 2.3.23, HP 4100C USB Scanner
* 300 dpi scan of the entire bed
* 24 Bit Color ~ 70 secs - 3.6 Mbit/sec
* 8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */
/*
* For documentation, see Documentation/usb/scanner.txt.
* Website: http://www.meier-geinitz.de/kernel/
* Please contact the maintainer if your scanner is not detected by this
* driver automatically.
*/
/*
* Scanner definitions, macros, module info,
* debug/ioctl/data_dump enable, and other constants.
*/
#include "scanner.h"
static void purge_scanner(struct scn_usb_data *scn);
static void
irq_scanner(struct urb *urb)
{
/*
* For the meantime, this is just a placeholder until I figure out what
* all I want to do with it -- or somebody else for that matter.
*/
struct scn_usb_data *scn;
unsigned char *data;
scn = urb->context;
data = &scn->button;
data += 0; /* Keep gcc from complaining about unused var */
if (urb->status) {
return;
}
dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
return;
}
static int
open_scanner(struct inode * inode, struct file * file)
{
struct scn_usb_data *scn;
struct usb_device *dev;
kdev_t scn_minor;
int err=0;
down(&scn_mutex);
scn_minor = USB_SCN_MINOR(inode);
dbg("open_scanner: scn_minor:%d", scn_minor);
if (!p_scn_table[scn_minor]) {
up(&scn_mutex);
dbg("open_scanner(%d): Unable to access minor data", scn_minor);
return -ENODEV;
}
scn = p_scn_table[scn_minor];
dev = scn->scn_dev;
down(&(scn->sem)); /* Now protect the scn_usb_data structure */
up(&scn_mutex); /* Now handled by the above */
if (!dev) {
err("open_scanner(%d): Scanner device not present", scn_minor);
err = -ENODEV;
goto out_error;
}
if (!scn->present) {
err("open_scanner(%d): Scanner is not present", scn_minor);
err = -ENODEV;
goto out_error;
}
if (scn->isopen) {
dbg("open_scanner(%d): Scanner device is already open", scn_minor);
err = -EBUSY;
goto out_error;
}
init_waitqueue_head(&scn->rd_wait_q);
scn->isopen = 1;
file->private_data = scn; /* Used by the read and write methods */
out_error:
up(&(scn->sem)); /* Wake up any possible contending processes */
return err;
}
static int
close_scanner(struct inode * inode, struct file * file)
{
struct scn_usb_data *scn = file->private_data;
down(&(scn->sem));
scn->isopen = 0;
file->private_data = NULL;
if (!scn->present) {
/* The device was unplugged while open - need to clean up */
up(&(scn->sem));
purge_scanner(scn);
return 0;
}
up(&(scn->sem));
return 0;
}
static ssize_t
write_scanner(struct file * file, const char * buffer,
size_t count, loff_t *ppos)
{
struct scn_usb_data *scn;
struct usb_device *dev;
ssize_t bytes_written = 0; /* Overall count of bytes written */
ssize_t ret = 0;
kdev_t scn_minor;
int this_write; /* Number of bytes to write */
int partial; /* Number of bytes successfully written */
int result = 0;
char *obuf;
scn = file->private_data;
down(&(scn->sem));
if (!scn->present) {
/* The device was unplugged while open */
up(&(scn->sem));
return -ENODEV;
}
if (!scn->bulk_out_ep) {
/* This scanner does not have a bulk-out endpoint */
up(&(scn->sem));
return -EINVAL;
}
scn_minor = scn->scn_minor;
obuf = scn->obuf;
dev = scn->scn_dev;
file->f_dentry->d_inode->i_atime = CURRENT_TIME;
while (count > 0) {
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
this_write = (count >= OBUF_SIZE) ? OBUF_SIZE : count;
if (copy_from_user(scn->obuf, buffer, this_write)) {
ret = -EFAULT;
break;
}
result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
if (result == -ETIMEDOUT) { /* NAK -- shouldn't happen */
warn("write_scanner: NAK received.");
ret = result;
break;
} else if (result < 0) { /* We should not get any I/O errors */
warn("write_scanner(%d): funky result: %d. Consult Documentataion/usb/scanner.txt.", scn_minor, result);
ret = -EIO;
break;
}
#ifdef WR_DATA_DUMP
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", obuf[cnt]);
}
printk("\n");
}
#endif
if (partial != this_write) { /* Unable to write all contents of obuf */
ret = -EIO;
break;
}
if (partial) { /* Data written */
buffer += partial;
count -= partial;
bytes_written += partial;
} else { /* No data written */
ret = 0;
break;
}
}
up(&(scn->sem));
mdelay(5); /* This seems to help with SANE queries */
return ret ? ret : bytes_written;
}
static ssize_t
read_scanner(struct file * file, char * buffer,
size_t count, loff_t *ppos)
{
struct scn_usb_data *scn;
struct usb_device *dev;
ssize_t bytes_read; /* Overall count of bytes_read */
ssize_t ret;
kdev_t scn_minor;
int partial; /* Number of bytes successfully read */
int this_read; /* Max number of bytes to read */
int result;
int rd_expire = RD_EXPIRE;
char *ibuf;
scn = file->private_data;
down(&(scn->sem));
if (!scn->present) {
/* The device was unplugged while open */
up(&(scn->sem));
return -ENODEV;
}
scn_minor = scn->scn_minor;
ibuf = scn->ibuf;
dev = scn->scn_dev;
bytes_read = 0;
ret = 0;
file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the
atime of
the device
node */
while (count > 0) {
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, scn->rd_nak_timeout);
dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count);
/*
* Scanners are sometimes inheriently slow since they are mechanical
* in nature. USB bulk reads tend to timeout while the scanner is
* positioning, resetting, warming up the lamp, etc if the timeout is
* set too low. A very long timeout parameter for bulk reads was used
* to overcome this limitation, but this sometimes resulted in folks
* having to wait for the timeout to expire after pressing Ctrl-C from
* an application. The user was sometimes left with the impression
* that something had hung or crashed when in fact the USB read was
* just waiting on data. So, the below code retains the same long
* timeout period, but splits it up into smaller parts so that
* Ctrl-C's are acted upon in a reasonable amount of time.
*/
if (result == -ETIMEDOUT) { /* NAK */
if (!partial) { /* No data */
if (--rd_expire <= 0) { /* Give it up */
warn("read_scanner(%d): excessive NAK's received", scn_minor);
ret = result;
break;
} else { /* Keep trying to read data */
interruptible_sleep_on_timeout(&scn->rd_wait_q, scn->rd_nak_timeout);
continue;
}
} else { /* Timeout w/ some data */
goto data_recvd;
}
}
if (result == -EPIPE) { /* No hope */
if(usb_clear_halt(dev, scn->bulk_in_ep)) {
err("read_scanner(%d): Failure to clear endpoint halt condition (%Zd).", scn_minor, ret);
}
ret = result;
break;
} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
warn("read_scanner(%d): funky result:%d. Consult Documentation/usb/scanner.txt.", scn_minor, (int)result);
ret = -EIO;
break;
}
data_recvd:
#ifdef RD_DATA_DUMP
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", ibuf[cnt]);
}
printk("\n");
}
#endif
if (partial) { /* Data returned */
if (copy_to_user(buffer, ibuf, partial)) {
ret = -EFAULT;
break;
}
count -= this_read; /* Compensate for short reads */
bytes_read += partial; /* Keep tally of what actually was read */
buffer += partial;
} else {
ret = 0;
break;
}
}
up(&(scn->sem));
return ret ? ret : bytes_read;
}
static int
ioctl_scanner(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct scn_usb_data *scn;
struct usb_device *dev;
int retval = -ENOTTY;
scn = file->private_data;
down(&(scn->sem));
if (!scn->present) {
/* The device was unplugged while open */
up(&(scn->sem));
return -ENODEV;
}
dev = scn->scn_dev;
switch (cmd)
{
case SCANNER_IOCTL_VENDOR :
retval = (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
break;
case SCANNER_IOCTL_PRODUCT :
retval = (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
break;
case SCANNER_IOCTL_CTRLMSG:
{
struct ctrlmsg_ioctl {
struct usb_ctrlrequest req;
void *data;
} cmsg;
int pipe, nb, ret;
unsigned char buf[64];
retval = 0;
if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) {
retval = -EFAULT;
break;
}
nb = cmsg.req.wLength;
if (nb > sizeof(buf)) {
retval = -EINVAL;
break;
}
if ((cmsg.req.bRequestType & 0x80) == 0) {
pipe = usb_sndctrlpipe(dev, 0);
if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) {
retval = -EFAULT;
break;
}
} else {
pipe = usb_rcvctrlpipe(dev, 0);
}
ret = usb_control_msg(dev, pipe, cmsg.req.bRequest,
cmsg.req.bRequestType,
cmsg.req.wValue,
cmsg.req.wIndex,
buf, nb, HZ);
if (ret < 0) {
err("ioctl_scanner: control_msg returned %d\n", ret);
retval = -EIO;
break;
}
if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
retval = -EFAULT;
break;
}
default:
break;
}
up(&(scn->sem));
return retval;
}
static struct
file_operations usb_scanner_fops = {
owner: THIS_MODULE,
read: read_scanner,
write: write_scanner,
ioctl: ioctl_scanner,
open: open_scanner,
release: close_scanner,
};
static void *
probe_scanner(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
struct scn_usb_data *scn;
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
int ep_cnt;
int ix;
kdev_t scn_minor;
char valid_device = 0;
char have_bulk_in, have_bulk_out, have_intr;
char name[10];
dbg("probe_scanner: USB dev address:%p", dev);
dbg("probe_scanner: ifnum:%u", ifnum);
/*
* 1. Check Vendor/Product
* 2. Determine/Assign Bulk Endpoints
* 3. Determine/Assign Intr Endpoint
*/
/*
* There doesn't seem to be an imaging class defined in the USB
* Spec. (yet). If there is, HP isn't following it and it doesn't
* look like anybody else is either. Therefore, we have to test the
* Vendor and Product ID's to see what we have. Also, other scanners
* may be able to use this driver by specifying both vendor and
* product ID's as options to the scanner module in conf.modules.
*
* NOTE: Just because a product is supported here does not mean that
* applications exist that support the product. It's in the hopes
* that this will allow developers a means to produce applications
* that will support USB products.
*
* Until we detect a device which is pleasing, we silently punt.
*/
for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct usb_device_id); ix++) {
if ((dev->descriptor.idVendor == scanner_device_ids [ix].idVendor) &&
(dev->descriptor.idProduct == scanner_device_ids [ix].idProduct)) {
valid_device = 1;
break;
}
}
if (dev->descriptor.idVendor == vendor && /* User specified */
dev->descriptor.idProduct == product) { /* User specified */
valid_device = 1;
}
if (!valid_device)
return NULL; /* We didn't find anything pleasing */
/*
* After this point we can be a little noisy about what we are trying to
* configure.
*/
if (dev->descriptor.bNumConfigurations != 1) {
info("probe_scanner: Only one device configuration is supported.");
return NULL;
}
interface = dev->config[0].interface[ifnum].altsetting;
if (interface[0].bInterfaceClass != USB_CLASS_VENDOR_SPEC &&
interface[0].bInterfaceClass != USB_CLASS_PER_INTERFACE &&
interface[0].bInterfaceClass != USB_CLASS_CDC_DATA &&
interface[0].bInterfaceClass != SCN_CLASS_SCANJET) {
dbg("probe_scanner: This interface doesn't look like a scanner (class=0x%x).", interface[0].bInterfaceClass);
return NULL;
}
endpoint = interface[0].endpoint;
/*
* Start checking for bulk and interrupt endpoints. We are only using the first
* one of each type of endpoint. If we have an interrupt endpoint go ahead and
* setup the handler. FIXME: This is a future enhancement...
*/
dbg("probe_scanner: Number of Endpoints:%d", (int) interface->bNumEndpoints);
ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;
while (ep_cnt < interface->bNumEndpoints) {
if (IS_EP_BULK_IN(endpoint[ep_cnt])) {
ep_cnt++;
if (have_bulk_in) {
info ("probe_scanner: ignoring additional bulk_in_ep:%d", ep_cnt);
continue;
}
have_bulk_in = endpoint[ep_cnt - 1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
continue;
}
if (IS_EP_BULK_OUT(endpoint[ep_cnt])) {
ep_cnt++;
if (have_bulk_out) {
info ("probe_scanner: ignoring additional bulk_out_ep:%d", ep_cnt);
continue;
}
have_bulk_out = endpoint[ep_cnt - 1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
continue;
}
if (IS_EP_INTR(endpoint[ep_cnt])) {
ep_cnt++;
if (have_intr) {
info ("probe_scanner: ignoring additional intr_ep:%d", ep_cnt);
continue;
}
have_intr = endpoint[ep_cnt - 1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
dbg("probe_scanner: intr_ep:%d", have_intr);
continue;
}
info("probe_scanner: Undetected endpoint -- consult Documentation/usb/scanner.txt.");
return NULL; /* Shouldn't ever get here unless we have something weird */
}
/*
* Perform a quick check to make sure that everything worked as it
* should have.
*/
if (!have_bulk_in) {
err("probe_scanner: One bulk-in endpoint required.");
return NULL;
}
/*
* Determine a minor number and initialize the structure associated
* with it. The problem with this is that we are counting on the fact
* that the user will sequentially add device nodes for the scanner
* devices. */
down(&scn_mutex);
for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
if (!p_scn_table[scn_minor])
break;
}
/* Check to make sure that the last slot isn't already taken */
if (scn_minor >= SCN_MAX_MNR) {
err("probe_scanner: No more minor devices remaining.");
up(&scn_mutex);
return NULL;
}
dbg("probe_scanner: Allocated minor:%d", scn_minor);
if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
err("probe_scanner: Out of memory.");
up(&scn_mutex);
return NULL;
}
memset (scn, 0, sizeof(struct scn_usb_data));
init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
/* Ok, if we detected an interrupt EP, setup a handler for it */
if (have_intr) {
dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
FILL_INT_URB(&scn->scn_irq, dev,
usb_rcvintpipe(dev, have_intr),
&scn->button, 1, irq_scanner, scn,
// endpoint[(int)have_intr].bInterval);
250);
if (usb_submit_urb(&scn->scn_irq)) {
err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
kfree(scn);
up(&scn_mutex);
return NULL;
}
}
/* Ok, now initialize all the relevant values */
if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);
if (have_intr)
usb_unlink_urb(&scn->scn_irq);
kfree(scn);
up(&scn_mutex);
return NULL;
}
dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf);
if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);
if (have_intr)
usb_unlink_urb(&scn->scn_irq);
kfree(scn->obuf);
kfree(scn);
up(&scn_mutex);
return NULL;
}
dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
case 0x04b8: /* Seiko/Epson */
scn->rd_nak_timeout = HZ * 60;
break;
case 0x055f: /* Mustek */
case 0x0400: /* Another Mustek */
scn->rd_nak_timeout = HZ * 1;
default:
scn->rd_nak_timeout = RD_NAK_TIMEOUT;
}
if (read_timeout > 0) { /* User specified read timeout overrides everything */
info("probe_scanner: User specified USB read timeout - %d", read_timeout);
scn->rd_nak_timeout = read_timeout;
}
scn->bulk_in_ep = have_bulk_in;
scn->bulk_out_ep = have_bulk_out;
scn->intr_ep = have_intr;
scn->present = 1;
scn->scn_dev = dev;
scn->scn_minor = scn_minor;
scn->isopen = 0;
sprintf(name, "scanner%d", scn->scn_minor);
scn->devfs = devfs_register(usb_devfs_handle, name,
DEVFS_FL_DEFAULT, USB_MAJOR,
SCN_BASE_MNR + scn->scn_minor,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
if (scn->devfs == NULL)
dbg("scanner%d: device node registration failed", scn_minor);
info ("USB scanner device (0x%04x/0x%04x) now attached to %s",
dev->descriptor.idVendor, dev->descriptor.idProduct, name);
p_scn_table[scn_minor] = scn;
up(&scn_mutex);
return scn;
}
static void
purge_scanner(struct scn_usb_data *scn)
{
kfree(scn->ibuf);
kfree(scn->obuf);
kfree(scn);
}
static void
disconnect_scanner(struct usb_device *dev, void *ptr)
{
struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
down (&scn_mutex);
down (&(scn->sem));
if(scn->intr_ep) {
dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
usb_unlink_urb(&scn->scn_irq);
}
usb_driver_release_interface(&scanner_driver,
&scn->scn_dev->actconfig->interface[scn->ifnum]);
dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
devfs_unregister(scn->devfs);
p_scn_table[scn->scn_minor] = NULL;
if (scn->isopen) {
/* The device is still open - cleanup must be delayed */
scn->present = 0;
up(&(scn->sem));
up(&scn_mutex);
return;
}
up (&(scn->sem));
up (&scn_mutex);
purge_scanner(scn);
}
static struct
usb_driver scanner_driver = {
name: "usbscanner",
probe: probe_scanner,
disconnect: disconnect_scanner,
fops: &usb_scanner_fops,
minor: SCN_BASE_MNR,
id_table: NULL, /* This would be scanner_device_ids, but we
need to check every USB device, in case
we match a user defined vendor/product ID. */
};
static void __exit
usb_scanner_exit(void)
{
usb_deregister(&scanner_driver);
}
static int __init
usb_scanner_init (void)
{
if (usb_register(&scanner_driver) < 0)
return -1;
info(DRIVER_VERSION ":" DRIVER_DESC);
if (vendor != -1 && product != -1)
info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
return 0;
}
module_init(usb_scanner_init);
module_exit(usb_scanner_exit);