Copyright (C) 1999, 2000 David E. Nelson <dnelson@jump.net>

April 26, 2000

CHANGES

- Amended for linux-2.4.12
- Updated devfs support
- Amended for linux-2.3.99-pre6-3
- Appended hp_scan.c to end of this README
- Removed most references to HP
- Updated uhci/ohci host controller info
- Updated support for multiple scanner support
- Updated supported scanners list
- Updated usbdevfs info
- Spellcheck

OVERVIEW

This README addresses issues regarding how to configure the kernel
to access a USB scanner.  Although the driver was originally conceived
for USB HP scanners, it's general enough so that it can be used with
other scanners.  Also, one can now pass the USB Vendor and Product
ID's using module parameters for unknown scanners.  Refer to the
document scanner-hp-sane.txt for guidance on how to configure SANE to
use a USB HP Scanner.


ADDITIONAL INFORMATION

http://www.linux-usb.org/


REQUIREMENTS

A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
(Compaq and others) hardware port should work.  At the time of this
writing, there are two UHCI drivers and one OHCI.

A Linux kernel with USB support enabled or a backported version to
linux-2.2.x.  See http://www.linux-usb.org for more information on
accomplishing this.

'lspci' which is only needed to determine the type of USB hardware
available/installed in your machine.

CONFIGURATION

Using `lspci -v`, determine the type of USB hardware available/installed.

  If you see something like:

    USB Controller: ......
    Flags: .....
    I/O ports at ....

  Then you have a UHCI based controller.

  If you see something like:

     USB Controller: .....
     Flags: ....
     Memory at .....

  Then you have a OHCI based controller.

Using `make menuconfig` or your preferred method for configuring the
kernel, select 'Support for USB', 'OHCI/UHCI' depending on your
hardware (determined from the steps above), 'USB Scanner support', and
'Preliminary USB device filesystem'.  Compile and install the modules
(you may need to execute `depmod -a` to update the module
dependencies). If any of the USB sections were compiled into the
kernel, a reboot is necessary. NOTE: Updating the boot disk with
'lilo' may also be required. Testing was performed only as modules,
YMMV.

Beginning with version 0.4 of the driver, up to 16 scanners can be
connected/used simultaneously.  For devfs support, see next section.
If you intend to use more than one scanner at a time w/o devfs support:

   Add a device for the USB scanner:
	`mknod /dev/usbscanner0 c 180 48`
	`mknod /dev/usbscanner1 c 180 49`
                      . 
                      .
	`mknod /dev/usbscanner15 180 63`


If you foresee using only one scanner it is best to:
	`mknod /dev/usbscanner0 c 180 48`
	`ln -s /dev/usbscanner0 /dev/usbscanner`


Set appropriate permissions for /dev/usbscanner[0-15] (don't forget
about group and world permissions).  Both read and write permissions
are required for proper operation. For example:
	`chmod 666 /dev/usbscanner0`

Load the appropriate modules (if compiled as modules):

  OHCI:
    modprobe usb-ohci
    modprobe scanner

  UHCI:
    modprobe usb-uhci
    modprobe scanner

DEVFS

The later versions of the Linux kernel (2.4.8'ish) included a dynamic
device filesystem call 'devfs'.  With devfs, there is no need to
create the device files as explained above; instead, they are
dynamically created for you.  For USB Scanner, the device is created
in /dev/usb/scannerX where X can range from 0 to 15 depending on the
number of scanners connected to the system.

To see if you have devfs, issue the command `cat /proc/filesytems`.
If devfs is listed you should be ready to go.  You sould also have a
process running called 'devfsd'.  In order to make sure, issue the
command `ps aux | grep '[d]evfsd'`.

If you would like to maintain /dev/usbscanner0 in order to maintain
compatibility with applications, then add the following to
/etc/devfsd.conf:

REGISTER ^usb/scanner0$ CFUNCTION GLOBAL symlink usb/scanner0 usbscanner0
UNREGISTER ^usb/scanner0$ CFUNCTION GLOBAL unlink usbscanner0

Then reset the scanner (reseat the USB connector or power cycle). This
will create the necessary symlinks in /dev to /dev/usb.

CONCLUSION

That's it.  SANE should now be able to access the device.  

There is a small test program (hp_scan.c -- appended below) that can
be used to test the scanner device if it's an HP scanner that supports
SCL (Scanner Control Language).  Known HP scanner that support SCL are
the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not*
supported since it does not understand SCL; it's also strongly
suspected that the 3300 and the PhotoSmart S20 are not SCL compliant.
Hp_scan.c's purpose is to test the driver without having to
retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
the output into a file called 'out.dat' in the current directory.  The
data in the file is raw data so it's not very useful for imaging.

MESSAGES

usb_control/bulk_msg: timeout -- On occasions this message will appear
in '/var/adm/messages', on the console, or both depending on how
your system is configured.  This is a side effect that scanners are
sometimes very slow at warming up and/or initializing.  In most cases,
however, only several of these messages should appear and is generally
considered to be normal.  

excessive NAK's received -- This message should be considered abnormal
and generally indicates that the USB system is unable to communicate
with the scanner for some particular reason.

probe_scanner: Undetected endpoint -- The USB Scanner driver is fairly
general when it comes to communicating to scanners.  Unfortunately,
some vendors have designed their scanners in one way or another that
this driver doesn't account for.

probe_scanner: Endpoint determination failed -- This means that the
driver is unable to detect a supported configuration for means to
communicate with the scanner.  See also 'probe_scanner: Undetected
endpoint'.

funky result -- Most of the time the data flow between the computer
and the scanner goes smoothly.  However, due to whatever reason,
whether it be solar flares or stray neutrons, sometimes the
communications don't work as expected.  The driver tries to handle
most types of errors but not all.  When this message is seen,
something weird happened.  Please contact the maintaner listed at the
top of this file.

SUPPORTED SCANNERS

NOTE: Just because a product is listed 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 the listed USB products.

At the time of this writing, the following scanners were supported by
scanner.c:

 Acer
	 Prisa Acerscan 620U & 640U (!)
	 Prisa AcerScan 620U (!)
 Agfa
	 SnapScan 1212U
	 Another SnapScan 1212U (?)
	 SnapScan Touch
 Colorado -- See Primax/Colorado below
 Epson -- See Seiko/Epson below
 Genius
         ColorPage-Vivid Pro
 Hewlett Packard
	 3300C
	 4100C
	 4200C
	 PhotoSmart S20
	 5200C
	 6200C
	 6300C
 Microtek
	 ScanMaker X6 - X6U
	 Phantom 336CX - C3
	 Phantom 336CX - C3 #2
	 Phantom C6
	 ScanMaker V6USL
	 ScanMaker V6USL #2
	 ScanMaker V6UL - SpicyU
 Mustek
	 1200 CU
 Primax/Colorado
	 G2-300 #1
	 G2-600 #1
	 G2E-300 #1
	 ReadyScan 636i
	 G2-300 #2
	 G2-600 #2
	 G2E-300 #2
	 G2E-600
	 Colorado USB 9600
	 Colorado USB 19200
	 Colorado 600u
	 Colorado 1200u
 Seiko/Epson Corp.
	 Perfection 636U and 636Photo
	 Perfection 610
	 Perfection 1200U and 1200Photo
 Umax
	 Astra 1220U
	 Astra 1236U
	 Astra 2000U
	 Astra 2200U
 Visioneer
	 OneTouch 5300
	 OneTouch 7600 duplicate ID (!)
	 6100


MODULE PARAMETERS

If you have a device that you wish to experiment with or try using
this driver with, but the Vendor and Product ID's are not coded in,
don't despair.  If the driver was compiled as a module, you can pass
options to the driver.  Simply add 

  options scanner vendor=0x#### product=0x****

to the /etc/modules.conf file replacing the #'s and the *'s with the
correct ID's.  The ID's can be retrieved from the messages file or
using `cat /proc/bus/usb/devices`. Note that USB /proc support must be
enabled during kernel configuration.  If the 'scanner' module is
already loaded into memory, it must be reloaded for the module
parameters to take effect.  In essence, `rmmod scanner; modprobe
scanner` must be performed.

**NOTE**: In later kernels (2.3.38+), a new filesystem was introduced,
usbdevfs.  To mount the filesystem, issue the command (as root):

  mount -t usbdevfs /proc/bus/usb /proc/bus/usb

An alternative and more permanent method would be to add

  none  /proc/bus/usb  usbdevfs  defaults  0  0

to /etc/fstab.  This will mount usbdevfs at each reboot.  You can then
issue `cat /proc/bus/usb/devices` to extract USB device information.


BUGS

Just look at the list of fixes in the source files.  So, if you
encounter any problems feel free to drop me an email.

David /\/elson
dnelson@jump.net
http://www.jump.net/~dnelson

--------------- snip -- hp_scan.c -- snip ---------------
/*

This is a really crude attempt at writing a short test program.  It's
mostly only to be used to test connectivity with USB HP scanners that
understand SCL.  Currently, the supported models are 4100C, 5200C,
6200C, and the 6300C.  Note that the 4200C is *NOT* acceptable.

Copyright (C) David E. Nelson <dnelson@jump.net>, 1999

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.

*/

#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <unistd.h>
#include <fcntl.h>

/*
   Gray Output produces about a 8945400 byte file.
   Color Output produces a 26836200 byte file. 
   
   To compile: gcc -o hp_scan hp_scan.c
*/

// #define COLOR /* Undef to scan GrayScale */

int send_cmd(int, const char *, int);
int read_cmd(int, char *, int);

int
main(void) {

	ssize_t cnt = 0, total_cnt = 0;

	FILE *fpout;

	int fp;
	int data_size = 32768;

	char *data;

	static char reset_cmd[] = {'\x1b','E'};

#ifdef COLOR
	static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */
	static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */
#else
	static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */
	static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */
#endif

	static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'};
	static char start_scan_cmd[] = {'\x1b','*','f','0','S'};
	
	if(!(data=malloc(data_size))) {
		perror("malloc failed");
		exit (1);
	}
	
	if((fp=open("/dev/usbscanner", O_RDWR)) < 0) {
		perror("Unable to open scanner device");
		exit (1);
	}

	if((fpout=fopen("out.dat", "w+")) == NULL) {
		perror("Unable to open ouput file");
		exit(1);
	}

	send_cmd(fp, reset_cmd, sizeof(reset_cmd));
	send_cmd(fp, data_type_cmd, sizeof(data_type_cmd));
	send_cmd(fp, data_width_cmd, sizeof(data_width_cmd));
	send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd));

	while ((cnt = read(fp, data, data_size)) > 0) {
		printf("Read: %u\n", cnt); 
		if(fwrite(data, sizeof(char), cnt, fpout) < 0) {
			perror("Write to output file failed");
			exit (1);
		}
		total_cnt += cnt;
	}
	if (cnt < 0) {
		perror("Read from scanner failed");
		exit (1);
	}

	printf("\nRead %lu bytes.\n", total_cnt);

	send_cmd(fp, reset_cmd, sizeof(reset_cmd));

	close(fp);
	fclose(fpout);
	return (0);
}

int
send_cmd(int fp, const char * cmd, int length) {

	int result;
	int x;

	if((result = write(fp, cmd, length)) != length) {
		printf ("Write warning: %d bytes requested, %d written\n");
	} else if (result < 0) {
		perror ("send_cmd failure");
		exit (1);
	}
	return (result);
}
	
int
read_cmd(int fp, char * response, int length) {

	return read(fp, response, length);

}
