[sane-devel] Fujitsu USB patches
Ron Cemer
ron at roncemer.com
Mon Feb 17 19:44:32 GMT 2003
I've fixed the patchfile based on your feedback below. I'm using a newer
version of gcc which allows you to declare variables inline with local
scope, instead of at the top of the function. I just moved the setwinB
declaration to the top of the function. And you're right, the
fujitsu.man patch is reversed. I fixed that also.
I'll re-send this patch to the fujitsu maintaner. No response from him yet.
Thanks!
Ron
Henning Meier-Geinitz wrote:
>Hi,
>
>On Thu, Feb 13, 2003 at 03:40:44PM -0800, Ron Cemer wrote:
>
>
>>Here are updated patches that get the Fujitsu fi-4220C scanner working,
>>and add USB support for Fujitsu scanners.
>>
>>It now supports libusb or regular usb scanner devices, as described in
>>the sane-usb man page.
>>
>>It uses SCSI commands over USB, using a non-standard implementation of
>>the USB mass storage protocol.
>>
>>Thanks to Henning for various suggestions to get it in line with the
>>SANE standards! :-)
>>
>>I'm sending this to both the sane-devel mailing list and the current
>>Fujitsu backend maintaner, in hopes that the changes will be implemented
>>as quickly as possible.
>>
>>
>
>If you don't get a response from the maintainer (say in 3 weeks),
>please contact us again. Just in case he isn't active any longer.
>
>
>
>>--- ./backend/fujitsu.c.orig 2002-09-16 05:19:52.000000000 -0700
>>+++ ./backend/fujitsu.c 2003-02-13 15:03:17.000000000 -0800
>>
>>
>
>[...]
>
>
>
>>@@ -4352,18 +4609,26 @@
>> * follows without a header of its own.
>> */
>>
>>+
>>+ scsiblk *setwinB;
>>
>>
>
>gcc complains:
>
>fujitsu.c: In function setWindowParam':
>fujitsu.c:4613: parse error before *'
>fujitsu.c:4615: setwinB' undeclared (first use in this function)
>
>setwinB doesn't seem to be defined anywhere.
>
>
>
>>+++ ./doc/descriptions/fujitsu.desc 2003-02-13 15:04:51.000000000 -0800
>>@@ -37,6 +37,8 @@
>> :interface "SCSI"
>> :model "M4097"
>> :interface "SCSI"
>>+:model "fi-4220C"
>>+:interface "SCSI USB"
>> :model "fi-4340C"
>>-:interface "SCSI"
>>+:interface "SCSI USB"
>>
>>
>
>That's ok if you (or someone else) have tested these models with both
>USB and SCSI and they work.
>
>If you think other models may also work but you can't test (because
>you don't have a scanner), you can use entries like that:
>
>:model "whatever"
>:interface "SCSI"
>:status :untested
>:comment "Looks similar to foo, please test"
>
>
>
>>--- ./doc/sane-fujitsu.man.orig 2003-02-13 15:13:15.000000000 -0800
>>+++ ./doc/sane-fujitsu.man 2002-11-29 12:15:30.000000000 -0800
>>@@ -4,13 +4,13 @@
>> .IX sane-m3096g
>>
>> .SH NAME
>>-sane-fujitsu \- SANE backend for Fujitsu flatbed and ADF scanners
>>+sane-fujitsu \- SANE backend for Fujitsu flatbed scanners
>>
>>
>
>That patch is reversed (the other way round)!
>
>Bye,
> Henning
>_______________________________________________
>Sane-devel mailing list
>Sane-devel at www.mostang.com
>http://www.mostang.com/mailman/listinfo/sane-devel
>
>
>
-------------- next part --------------
--- backend/Makefile.in.orig 2003-01-13 11:49:46.000000000 -0800
+++ backend/Makefile.in 2003-02-12 14:00:17.000000000 -0800
@@ -302,6 +302,7 @@
libsane-fujitsu.la: ../sanei/sanei_config2.lo
libsane-fujitsu.la: ../sanei/sanei_constrain_value.lo
libsane-fujitsu.la: ../sanei/sanei_scsi.lo
+libsane-fujitsu.la: ../sanei/sanei_usb.lo
libsane-gphoto2.la: ../sanei/sanei_constrain_value.lo djpeg.lo
libsane-gt68xx.la: ../sanei/sanei_constrain_value.lo
libsane-gt68xx.la: ../sanei/sanei_usb.lo
--- backend/fujitsu-scsi.h.orig 2002-09-16 05:19:52.000000000 -0700
+++ backend/fujitsu-scsi.h 2003-02-12 14:00:17.000000000 -0800
@@ -230,6 +230,16 @@
static scsiblk set_windowB = { set_windowC, sizeof (set_windowC) };
#define set_SW_xferlen(sb, len) putnbyte(sb + 0x06, len, 3)
+ /* With the fi-series scanners, we have to use a 12-byte command
+ * instead of a 10-byte command when communicating via USB. This
+ * may be a firmware bug. */
+static unsigned char set_usb_windowC[] =
+ { SET_WINDOW, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00 };
+/* opcode, lun, _____4 X reserved____, transfer length, control byte */
+static scsiblk set_usb_windowB = { set_usb_windowC, sizeof (set_usb_windowC) };
+#define set_SW_xferlen(sb, len) putnbyte(sb + 0x06, len, 3)
+
/* ==================================================================== */
static unsigned char object_positionC[] =
@@ -378,6 +388,17 @@
};
+ /* With the fi-series scanners, we have to use a 10-byte header
+ * instead of a 4-byte header when communicating via USB. This
+ * may be a firmware bug. */
+static unsigned char mode_select_usb_headerC[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static scsiblk mode_select_usb_headerB = {
+ mode_select_usb_headerC, sizeof (mode_select_usb_headerC)
+};
+
+
static unsigned char mode_select_parameter_blockC[] = {
0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
--- backend/fujitsu.c.orig 2002-09-16 05:19:52.000000000 -0700
+++ backend/fujitsu.c 2003-02-17 11:34:37.000000000 -0800
@@ -77,6 +77,10 @@
- 3092 support (mgoppold at tbz-pariv.de)
- tested 4097 support
- changed some functions to receive compressed data
+ V 1.4, 13-Feb-2003
+ - fi-4220C support (ron at roncemer.com)
+ - USB support for scanners which send SCSI commands over usb
+ (ron at roncemer.com)
SANE FLOW DIAGRAM
@@ -124,6 +128,7 @@
#include "sane/sanei_backend.h"
#include "sane/sanei_scsi.h"
+#include "sane/sanei_usb.h"
#include "sane/saneopts.h"
#include "sane/sanei_config.h"
@@ -338,6 +343,11 @@
static const SANE_Device **devlist = 0;
/*
+ * used by attachScanner and attachOne
+ */
+static Fujitsu_Connection_Type mostRecentConfigConnectionType = SANE_FUJITSU_SCSI;
+
+/*
* @@ Section 2 - SANE Interface
*/
@@ -364,11 +374,14 @@
size_t len;
FILE *fp;
+ mostRecentConfigConnectionType = SANE_FUJITSU_SCSI;
authorize = authorize; /* get rid of compiler warning */
DBG_INIT ();
DBG (10, "sane_init\n");
+ sanei_usb_init();
+
if (version_code)
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);
fp = sanei_config_open (FUJITSU_CONFIG_FILE);
@@ -393,6 +406,7 @@
while (sanei_config_read (line, PATH_MAX, fp))
{
+ int vendor, product;
/* ignore comments */
if (line[0] == '#')
@@ -457,11 +471,23 @@
lp);
}
}
- else /* must be a device name if it's not an option */
+ else if (sscanf(lp, "usb %i %i", &vendor, &product) == 2)
{
+ mostRecentConfigConnectionType = SANE_FUJITSU_USB;
+ sanei_usb_attach_matching_devices(lp, attachOne);
+ mostRecentConfigConnectionType = SANE_FUJITSU_SCSI;
+ }
+ else /* must be a device name if it's not an option */
+ {
+ if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3])) {
+ lp += 3;
+ lp = sanei_config_skip_whitespace (lp);
+ mostRecentConfigConnectionType = SANE_FUJITSU_USB;
+ }
strncpy (devName, lp, sizeof (devName));
devName[sizeof (devName) - 1] = '\0';
sanei_config_attach_matching_devices (devName, attachOne);
+ mostRecentConfigConnectionType = SANE_FUJITSU_SCSI;
}
}
fclose (fp);
@@ -568,7 +594,10 @@
case MODEL_3093:
case MODEL_4097:
case MODEL_FI:
- setDefaults3096 (scanner);
+ if ( strstr (scanner->productName, "4220") )
+ setDefaults3091 (scanner);
+ else
+ setDefaults3096 (scanner);
break;
case MODEL_SP15:
@@ -1351,7 +1380,10 @@
case MODEL_3097:
case MODEL_4097:
case MODEL_FI:
- return (setMode3096 (scanner, newMode));
+ if ( strstr (scanner->productName, "4220") )
+ return (setMode3091 (scanner, newMode));
+ else
+ return (setMode3096 (scanner, newMode));
case MODEL_SP15:
return (setModeSP15 (scanner, newMode));
}
@@ -1871,23 +1903,35 @@
if (scanner->sfd < 0)
{
/* first call */
- if (sanei_scsi_open (scanner->sane.name, &(scanner->sfd),
- senseHandler, 0) != SANE_STATUS_GOOD)
- {
- DBG (MSG_ERR,
- "sane_start: open of %s failed:\n", scanner->sane.name);
- return SANE_STATUS_INVAL;
- }
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ DBG (10, "sane_start opening USB device\n");
+ if (sanei_usb_open (scanner->sane.name, &(scanner->sfd)) !=
+ SANE_STATUS_GOOD) {
+ DBG (MSG_ERR,
+ "sane_start: open of %s failed:\n", scanner->sane.name);
+ return SANE_STATUS_INVAL;
+ }
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ DBG (10, "sane_start opening SCSI device\n");
+ if (sanei_scsi_open (scanner->sane.name, &(scanner->sfd),
+ scsiSenseHandler, 0) != SANE_STATUS_GOOD) {
+ DBG (MSG_ERR,
+ "sane_start: open of %s failed:\n", scanner->sane.name);
+ return SANE_STATUS_INVAL;
+ }
+ }
}
scanner->object_count = 1;
scanner->eof = SANE_FALSE;
-
-
if ((ret = grabScanner (scanner)))
{
DBG (5, "sane_start: unable to reserve scanner\n");
- sanei_scsi_close (scanner->sfd);
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (scanner->sfd);
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (scanner->sfd);
+ }
scanner->object_count = 0;
scanner->sfd = -1;
return ret;
@@ -1907,7 +1951,11 @@
{
DBG (5, "sane_start: ERROR: failed to start send command\n");
freeScanner (scanner);
- sanei_scsi_close (scanner->sfd);
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (scanner->sfd);
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (scanner->sfd);
+ }
scanner->object_count = 0;
scanner->sfd = -1;
return ret;
@@ -1917,7 +1965,11 @@
{
DBG (5, "sane_start: ERROR: failed to start imprinter command\n");
freeScanner (scanner);
- sanei_scsi_close (scanner->sfd);
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (scanner->sfd);
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (scanner->sfd);
+ }
scanner->object_count = 0;
scanner->sfd = -1;
return ret;
@@ -1929,7 +1981,11 @@
{
DBG (5, "sane_start: WARNING: ADF empty\n");
freeScanner (scanner);
- sanei_scsi_close (scanner->sfd);
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (scanner->sfd);
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (scanner->sfd);
+ }
scanner->object_count = 0;
scanner->sfd = -1;
return ret;
@@ -1942,7 +1998,11 @@
{
DBG (5, "sane_start: ERROR: failed to set window\n");
freeScanner (scanner);
- sanei_scsi_close (scanner->sfd);
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (scanner->sfd);
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (scanner->sfd);
+ }
scanner->object_count = 0;
scanner->sfd = -1;
return ret;
@@ -1965,7 +2025,11 @@
DBG (MSG_ERR, "ERROR: could not create pipe\n");
scanner->object_count = 0;
freeScanner (scanner);
- sanei_scsi_close (scanner->sfd);
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (scanner->sfd);
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (scanner->sfd);
+ }
scanner->sfd = -1;
return SANE_STATUS_IO_ERROR;
}
@@ -1980,7 +2044,11 @@
DBG (MSG_ERR, "ERROR: could not create temporary file.\n");
scanner->object_count = 0;
freeScanner (scanner);
- sanei_scsi_close (scanner->sfd);
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (scanner->sfd);
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (scanner->sfd);
+ }
scanner->sfd = -1;
return SANE_STATUS_IO_ERROR;
}
@@ -1992,7 +2060,11 @@
DBG (MSG_ERR, "ERROR: could not create duplex pipe.\n");
scanner->object_count = 0;
freeScanner (scanner);
- sanei_scsi_close (scanner->sfd);
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (scanner->sfd);
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (scanner->sfd);
+ }
scanner->sfd = -1;
return SANE_STATUS_IO_ERROR;
}
@@ -2294,7 +2366,7 @@
attachScanner (const char *devicename, struct fujitsu **devp)
{
struct fujitsu *dev;
- int sfd;
+ SANE_Int sfd;
DBG (15, "attach_scanner: %s\n", devicename);
@@ -2312,11 +2384,19 @@
}
DBG (15, "attach_scanner: opening %s\n", devicename);
- if (sanei_scsi_open (devicename, &sfd, senseHandler, 0) != 0)
- {
- DBG (5, "attach_scanner: open failed\n");
- return SANE_STATUS_INVAL;
+ if (mostRecentConfigConnectionType == SANE_FUJITSU_USB) {
+ DBG (15, "attachScanner opening USB device\n");
+ if (sanei_usb_open (devicename, &sfd) != SANE_STATUS_GOOD) {
+ DBG (5, "attach_scanner: open failed\n");
+ return SANE_STATUS_INVAL;
+ }
+ } else if (mostRecentConfigConnectionType == SANE_FUJITSU_SCSI) {
+ DBG (15, "attachScanner opening SCSI device\n");
+ if (sanei_scsi_open (devicename, &sfd, scsiSenseHandler, 0) != 0) {
+ DBG (5, "attach_scanner: open failed\n");
+ return SANE_STATUS_INVAL;
}
+ }
if (NULL == (dev = malloc (sizeof (*dev))))
return SANE_STATUS_NO_MEM;
@@ -2327,6 +2407,7 @@
return SANE_STATUS_NO_MEM;
dev->devicename = strdup (devicename);
+ dev->connection = mostRecentConfigConnectionType;
dev->sfd = sfd;
/*
@@ -2335,14 +2416,22 @@
if (identifyScanner (dev) != 0)
{
DBG (5, "attach_scanner: scanner identification failed\n");
- sanei_scsi_close (dev->sfd);
+ if (dev->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (dev->sfd);
+ } else if (dev->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (dev->sfd);
+ }
free (dev->buffer);
free (dev);
return SANE_STATUS_INVAL;
}
/* Why? */
- sanei_scsi_close (dev->sfd);
+ if (dev->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (dev->sfd);
+ } else if (dev->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (dev->sfd);
+ }
dev->sfd = -1;
dev->sane.name = dev->devicename;
@@ -2380,7 +2469,7 @@
* Responsible for producing a meaningful debug message.
*/
static SANE_Status
-senseHandler (int scsi_fd, u_char * sensed_data, void *arg)
+scsiSenseHandler (int scsi_fd, u_char * sensed_data, void *arg)
{
unsigned int ret = SANE_STATUS_IO_ERROR;
unsigned int sense = get_RS_sense_key (sensed_data);
@@ -2615,7 +2704,8 @@
hexdump (MSG_IO, "inquiry", inquiryB.cmd, inquiryB.size);
- do_scsi_cmd (s->sfd, inquiryB.cmd, inquiryB.size, s->buffer, 96, NULL);
+ do_cmd (s->connection, s->sfd, inquiryB.cmd, inquiryB.size,
+ s->buffer, 96, NULL);
}
static SANE_Status
@@ -2631,26 +2721,37 @@
{
int sfd;
- if (sanei_scsi_open (s->devicename, &sfd, senseHandler, 0) != 0)
- {
- DBG (5, "get_hardware_status: open failed\n");
- return SANE_STATUS_INVAL;
- }
-
+ if (s->connection == SANE_FUJITSU_USB) {
+ DBG (10, "get_hardware_status opening USB device\n");
+ if (sanei_usb_open (s->devicename, &sfd) != SANE_STATUS_GOOD) {
+ DBG (5, "get_hardware_status: open failed\n");
+ return SANE_STATUS_INVAL;
+ }
+ } else if (s->connection == SANE_FUJITSU_SCSI) {
+ DBG (10, "get_hardware_status opening SCSI device\n");
+ if (sanei_scsi_open (s->devicename, &sfd, scsiSenseHandler, 0)!=0) {
+ DBG (5, "get_hardware_status: open failed\n");
+ return SANE_STATUS_INVAL;
+ }
+ }
hexdump (MSG_IO, "get_hardware_status",
hw_statusB.cmd, hw_statusB.size);
- ret = do_scsi_cmd (sfd, hw_statusB.cmd, hw_statusB.size,
- s->buffer, 10, NULL);
- sanei_scsi_close (sfd);
+ ret = do_cmd (s->connection, sfd, hw_statusB.cmd, hw_statusB.size,
+ s->buffer, 10, NULL);
+ if (s->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (sfd);
+ } else if (s->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (sfd);
+ }
}
else
{
hexdump (MSG_IO, "get_hardware_status",
hw_statusB.cmd, hw_statusB.size);
- ret = do_scsi_cmd (s->sfd, hw_statusB.cmd, hw_statusB.size,
- s->buffer, 10, NULL);
+ ret = do_cmd (s->connection, s->sfd, hw_statusB.cmd, hw_statusB.size,
+ s->buffer, 10, NULL);
}
if (ret == SANE_STATUS_GOOD)
@@ -2686,8 +2787,8 @@
set_IN_page_code (inquiryB.cmd, 0xf0);
hexdump (MSG_IO, "get_vital_product_data", inquiryB.cmd, inquiryB.size);
- ret = do_scsi_cmd (s->sfd, inquiryB.cmd, inquiryB.size,
- s->buffer, 0x64, NULL);
+ ret = do_cmd (s->connection, s->sfd, inquiryB.cmd, inquiryB.size,
+ s->buffer, 0x64, NULL);
if (ret == SANE_STATUS_GOOD)
{
DBG (MSG_INFO, "standard options\n");
@@ -2780,15 +2881,31 @@
return ret;
}
-
+/**
+ * Sends a command to the device. This calls do_scsi_cmd or do_usb_cmd.
+ */
+static int
+do_cmd (Fujitsu_Connection_Type connection, int fd, unsigned char *cmd,
+ int cmd_len, unsigned char *out, size_t req_out_len,
+ size_t *res_out_len)
+{
+ if (connection == SANE_FUJITSU_SCSI) {
+ return do_scsi_cmd(fd, cmd, cmd_len, out, req_out_len, res_out_len);
+ }
+ if (connection == SANE_FUJITSU_USB) {
+ return do_usb_cmd(fd, cmd, cmd_len, out, req_out_len, res_out_len);
+ }
+ return SANE_STATUS_INVAL;
+}
/**
* Sends a SCSI command to the device. This is just a wrapper around
* sanei_scsi_cmd with some debug printing.
*/
static int
-do_scsi_cmd (int fd, unsigned char *cmd, int cmd_len,
- unsigned char *out, size_t req_out_len, size_t *res_out_len)
+do_scsi_cmd (int fd, unsigned char *cmd,
+ int cmd_len, unsigned char *out, size_t req_out_len,
+ size_t *res_out_len)
{
int ret;
size_t ol = req_out_len;
@@ -2823,6 +2940,118 @@
return ret;
}
+#define USB_CMD_HEADER_BYTES 19
+#define USB_CMD_MIN_BYTES 31
+
+/**
+ * Sends a USB command to the device.
+ */
+static int
+do_usb_cmd (int fd, unsigned char *cmd,
+ int cmd_len, unsigned char *out, size_t req_out_len,
+ size_t *res_out_len)
+{
+ int ret = SANE_STATUS_GOOD;
+ size_t cnt, ol;
+ int op_code = 0;
+ int i, j;
+ int tries = 0;
+ unsigned char buf[1024];
+/* unsigned char sense_bytes[64]; */
+
+retry:
+ hexdump (IO_CMD, "<cmd<", cmd, cmd_len);
+
+ if (cmd_len > 0) op_code = ((int)cmd[0]) & 0xff;
+
+ if ((cmd_len+USB_CMD_HEADER_BYTES) > (int)sizeof(buf)) {
+ /* Command too long. */
+ return SANE_STATUS_INVAL;
+ }
+ buf[0] = (unsigned char)'C';
+ for (i = 1; i < USB_CMD_HEADER_BYTES; i++) buf[i] = (unsigned char)0;
+ memcpy(&buf[USB_CMD_HEADER_BYTES], cmd, cmd_len);
+ for (i = USB_CMD_HEADER_BYTES+cmd_len; i < USB_CMD_MIN_BYTES; i++) {
+ buf[i] = (unsigned char)0;
+ }
+ /* The SCAN command must be at least 32 bytes long. */
+ if ( (op_code == SCAN) && (i < 32) ) {
+ for (; i < 32; i++) buf[i] = (unsigned char)0;
+ }
+
+ for (j = 0; j < i;) {
+ cnt = i-j;
+ /* First URB has to be 31 bytes. */
+ /* All other URBs must be 64 bytes (max) per URB. */
+ if ( (j == 0) && (cnt > 31) ) cnt = 31; else if (cnt > 64) cnt = 64;
+ hexdump (IO_CMD, "*** URB going out:", &buf[j], cnt);
+ DBG (IO_CMD, "try to write %u bytes\n", cnt);
+ ret = sanei_usb_write_bulk(fd, &buf[j], &cnt);
+ DBG (IO_CMD, "wrote %u bytes\n", cnt);
+ if (ret != SANE_STATUS_GOOD) break;
+ j += cnt;
+ }
+ if (ret != SANE_STATUS_GOOD) {
+ DBG (MSG_ERR, "*** Got error %d trying to write\n", ret);
+ }
+
+ ol = 0;
+ if (ret == SANE_STATUS_GOOD) {
+ if ( (out != NULL) && (req_out_len > 0) ) {
+ while (ol < req_out_len) {
+ cnt = (size_t)(req_out_len-ol);
+ DBG (IO_CMD, "try to read %u bytes\n", cnt);
+ ret = sanei_usb_read_bulk(fd, &out[ol], &cnt);
+ DBG (IO_CMD, "read %u bytes\n", cnt);
+ if (cnt > 0) {
+ hexdump (IO_CMD, "*** Data read:", &out[ol], cnt);
+ }
+ if (ret != SANE_STATUS_GOOD) {
+ DBG(MSG_ERR, "*** Got error %d trying to read\n", ret);
+ }
+ if (ret != SANE_STATUS_GOOD) break;
+ ol += cnt;
+ }
+ }
+
+ DBG(MSG_ERR, "*** Try to read CSW\n");
+ cnt = sizeof(buf);
+ sanei_usb_read_bulk(fd, buf, &cnt);
+ hexdump (IO_CMD, "*** Read CSW", buf, cnt);
+ }
+
+ /* Auto-retry failed data reads, in case the scanner is busy. */
+ if ( (op_code == READ) && (tries < 100) && (ol == 0) ) {
+ usleep(100000L);
+ tries++;
+ goto retry;
+ }
+
+ if (res_out_len != NULL)
+ {
+ *res_out_len = ol;
+ }
+
+ if ((req_out_len != 0) && (req_out_len != ol))
+ {
+ DBG (MSG_ERR, "do_usb_cmd: asked %lu bytes, got %lu\n",
+ (u_long) req_out_len, (u_long) ol);
+ }
+
+ if (ret)
+ {
+ DBG (MSG_ERR, "do_usb_cmd: returning 0x%08x\n", ret);
+ }
+
+ DBG (IO_CMD_RES, "do_usb_cmd: returning %lu bytes:\n", (u_long) ol);
+
+ if (out != NULL && ol != 0)
+ {
+ hexdump (IO_CMD_RES, ">rslt>", out, (ol > 0x60) ? 0x60 : ol);
+ }
+
+ return ret;
+}
/**
* Prints a hex dump of the given buffer onto the debug output stream.
@@ -2927,8 +3156,8 @@
#endif
hexdump (MSG_IO, "release_unit", release_unitB.cmd, release_unitB.size);
- ret = do_scsi_cmd (s->sfd, release_unitB.cmd, release_unitB.size,
- NULL, 0, NULL);
+ ret = do_cmd (s->connection, s->sfd, release_unitB.cmd,
+ release_unitB.size, NULL, 0, NULL);
if (ret)
return ret;
@@ -2959,8 +3188,8 @@
wait_scanner (s);
hexdump (MSG_IO, "reserve_unit", reserve_unitB.cmd, reserve_unitB.size);
- ret = do_scsi_cmd (s->sfd, reserve_unitB.cmd, reserve_unitB.size,
- NULL, 0, NULL);
+ ret = do_cmd (s->connection, s->sfd, reserve_unitB.cmd,
+ reserve_unitB.size, NULL, 0, NULL);
if (ret)
return ret;
@@ -2968,7 +3197,7 @@
return 0;
}
-static int fujitsu_wait_scanner(int fd)
+static int fujitsu_wait_scanner(Fujitsu_Connection_Type connection, int fd)
{
int ret = -1;
int cnt = 0;
@@ -2979,8 +3208,8 @@
{
hexdump (MSG_IO, "test_unit_ready", test_unit_readyB.cmd,
test_unit_readyB.size);
- ret = do_scsi_cmd (fd, test_unit_readyB.cmd,
- test_unit_readyB.size, 0, 0, NULL);
+ ret = do_cmd (connection, fd, test_unit_readyB.cmd,
+ test_unit_readyB.size, 0, 0, NULL);
if (ret == SANE_STATUS_DEVICE_BUSY)
{
usleep (500000); /* wait 0.5 seconds */
@@ -3009,7 +3238,7 @@
static int
wait_scanner (struct fujitsu *s)
{
- return fujitsu_wait_scanner(s->sfd);
+ return fujitsu_wait_scanner(s->connection, s->sfd);
}
/**
@@ -3041,7 +3270,8 @@
}
hexdump (MSG_IO, "object_position", s->buffer, object_positionB.size);
- ret = do_scsi_cmd (s->sfd, s->buffer, object_positionB.size, NULL, 0, NULL);
+ ret = do_cmd (s->connection, s->sfd, s->buffer, object_positionB.size,
+ NULL, 0, NULL);
if (ret != SANE_STATUS_GOOD)
return ret;
wait_scanner (s);
@@ -3073,7 +3303,8 @@
set_OP_autofeed (s->buffer, OP_Discharge);
}
hexdump (MSG_IO, "object_position", s->buffer, object_positionB.size);
- ret = do_scsi_cmd (s->sfd, s->buffer, object_positionB.size, NULL, 0, NULL);
+ ret = do_cmd (s->connection, s->sfd, s->buffer, object_positionB.size,
+ NULL, 0, NULL);
wait_scanner (s);
DBG (10, "objectDischarge: ok\n");
return ret;
@@ -3090,8 +3321,8 @@
DBG (10, "doReset\n");
if (scanner->model == MODEL_3092) {
- ret = do_scsi_cmd (scanner->sfd, reset_unitB.cmd, reset_unitB.size,
- NULL, 0, NULL);
+ ret = do_cmd (scanner->connection, scanner->sfd, reset_unitB.cmd,
+ reset_unitB.size, NULL, 0, NULL);
if (ret)
return ret;
}
@@ -3140,7 +3371,11 @@
{
freeScanner (scanner);
DBG (10, "doCancel: close filedescriptor\n");
- sanei_scsi_close (scanner->sfd);
+ if (scanner->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (scanner->sfd);
+ } else if (scanner->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (scanner->sfd);
+ }
scanner->sfd = -1;
}
@@ -3210,7 +3445,7 @@
}
hexdump (MSG_IO, "start_scan", command, cmdsize);
- ret = do_scsi_cmd (s->sfd, command, cmdsize, NULL, 0, NULL);
+ ret = do_cmd (s->connection, s->sfd, command, cmdsize, NULL, 0, NULL);
free (command);
@@ -3259,8 +3494,8 @@
hexdump (MSG_IO, "mode_select", s->buffer,
i_param_size + mode_selectB.size);
- ret = do_scsi_cmd (s->sfd, s->buffer,
- i_param_size + mode_selectB.size, NULL, 0, NULL);
+ ret = do_cmd (s->connection, s->sfd, s->buffer,
+ i_param_size + mode_selectB.size, NULL, 0, NULL);
}
@@ -3286,30 +3521,40 @@
if (s->model == MODEL_FI) /*...and others */
{
+ /* With the fi-series scanners, we have to use a 10-byte header
+ * instead of a 4-byte header when communicating via USB. This
+ * may be a firmware bug. */
+ scsiblk *headerB;
+ int xfer_length_pos_adj;
+ if (s->connection == SANE_FUJITSU_USB) {
+ headerB = &mode_select_usb_headerB;
+ xfer_length_pos_adj = mode_select_headerB.size-mode_select_usb_headerB.size;
+ } else {
+ headerB = &mode_select_headerB;
+ xfer_length_pos_adj = 0;
+ }
memcpy (s->buffer, mode_selectB.cmd, mode_selectB.size);
- memcpy (s->buffer + mode_selectB.size, mode_select_headerB.cmd,
- mode_select_headerB.size);
- memcpy (s->buffer + mode_selectB.size + mode_select_headerB.size,
+ memcpy (s->buffer + mode_selectB.size, headerB->cmd,
+ headerB->size);
+ memcpy (s->buffer + mode_selectB.size + headerB->size,
mode_select_parameter_blockB.cmd,
mode_select_parameter_blockB.size);
-
-
- command = s->buffer + mode_selectB.size + mode_select_headerB.size;
+ command = s->buffer + mode_selectB.size + headerB->size;
i_cmd_size = 6;
set_MSEL_len (command, i_cmd_size);
set_MSEL_pagecode (command, MSEL_sleep);
set_MSEL_sleep_mode(command, s->sleep_time);
- i_param_size = mode_select_headerB.size + i_cmd_size + 2;
- set_MSEL_xfer_length (s->buffer, i_param_size);
+ i_param_size = headerB->size + i_cmd_size + 2;
+ set_MSEL_xfer_length (s->buffer, i_param_size + xfer_length_pos_adj);
hexdump (MSG_IO, "mode_select", s->buffer,
i_param_size + mode_selectB.size);
- ret = do_scsi_cmd (s->sfd, s->buffer,
- i_param_size + mode_selectB.size, NULL, 0, NULL);
+ ret = do_cmd (s->connection, s->sfd, s->buffer,
+ i_param_size + mode_selectB.size, NULL, 0, NULL);
if (!ret)
{
@@ -3429,8 +3674,8 @@
set_R_window_id (readB.cmd, i_window_id);
set_R_xfer_length (readB.cmd, dataToRead);
- status = do_scsi_cmd (s->sfd, readB.cmd, readB.size, myBuffer,
- dataToRead, &data_read);
+ status = do_cmd (s->connection, s->sfd, readB.cmd, readB.size,
+ myBuffer, dataToRead, &data_read);
if (status == SANE_STATUS_EOF)
{
@@ -4105,22 +4350,34 @@
{
int sfd;
- if (sanei_scsi_open (s->devicename, &sfd, senseHandler, 0) != 0)
- {
- DBG (5, "imprinter: open failed\n");
- return SANE_STATUS_INVAL;
- }
+ if (s->connection == SANE_FUJITSU_USB) {
+ DBG (10, "imprinter opening USB device\n");
+ if (sanei_usb_open (s->devicename, &sfd) != SANE_STATUS_GOOD) {
+ DBG (5, "imprinter: open failed\n");
+ return SANE_STATUS_INVAL;
+ }
+ } else if (s->connection == SANE_FUJITSU_SCSI) {
+ DBG (10, "imprinter opening SCSI device\n");
+ if (sanei_scsi_open
+ (s->devicename, &sfd, scsiSenseHandler, 0) != 0) {
+ DBG (5, "imprinter: open failed\n");
+ return SANE_STATUS_INVAL;
+ }
+ }
- fujitsu_wait_scanner(sfd);
- ret = do_scsi_cmd (sfd, s->buffer,
- imprinterB.size + i_size,
- NULL, 0, NULL);
- sanei_scsi_close (sfd);
+ fujitsu_wait_scanner(s->connection, sfd);
+ ret = do_cmd (s->connection, sfd, s->buffer, imprinterB.size + i_size,
+ NULL, 0, NULL);
+ if (s->connection == SANE_FUJITSU_USB) {
+ sanei_usb_close (sfd);
+ } else if (s->connection == SANE_FUJITSU_SCSI) {
+ sanei_scsi_close (sfd);
+ }
}
else
{
- ret = do_scsi_cmd (s->sfd, s->buffer,
- imprinterB.size + i_size,
+ ret = do_cmd (s->connection, s->sfd, s->buffer,
+ imprinterB.size + i_size,
NULL, 0, NULL);
}
@@ -4191,9 +4448,9 @@
hexdump (MSG_IO, "send", s->buffer,
i_strlen + send_imprinterB.size + sendB.size);
- ret = do_scsi_cmd (s->sfd, s->buffer,
- i_strlen + send_imprinterB.size + sendB.size,
- NULL, 0, NULL);
+ ret = do_cmd (s->connection, s->sfd, s->buffer,
+ i_strlen + send_imprinterB.size + sendB.size,
+ NULL, 0, NULL);
}
@@ -4219,6 +4476,7 @@
unsigned char buffer[max_WDB_size];
int ret;
int scsiCommandLength = 0;
+ scsiblk *setwinB;
/* the amout of window data we're going to send. may have to be reduced
* depending on scanner model. */
@@ -4352,18 +4610,24 @@
* follows without a header of its own.
*/
+ if ( (s->model == MODEL_FI) && (s->connection == SANE_FUJITSU_USB) ) {
+ setwinB = &set_usb_windowB;
+ } else {
+ setwinB = &set_windowB;
+ }
+
/* SET WINDOW command and command descriptor block.
* The transfer length will be filled in later using set_SW_xferlen.
*/
- memcpy (s->buffer, set_windowB.cmd, set_windowB.size);
+ memcpy (s->buffer, setwinB->cmd, setwinB->size);
/* header for first set of window data */
- memcpy ((s->buffer + set_windowB.size),
+ memcpy ((s->buffer + setwinB->size),
window_parameter_data_blockB.cmd,
window_parameter_data_blockB.size);
/* set window data size */
- set_WPDB_wdblen ((s->buffer + set_windowB.size), windowDataSize);
+ set_WPDB_wdblen ((s->buffer + setwinB->size), windowDataSize);
if (s->duplex_mode == DUPLEX_BACK)
{
@@ -4375,7 +4639,7 @@
}
/* now copy window data itself */
- memcpy (s->buffer + set_windowB.size + window_parameter_data_blockB.size,
+ memcpy (s->buffer + setwinB->size + window_parameter_data_blockB.size,
buffer, windowDataSize);
/* when in duplex mode, add a second window */
@@ -4394,7 +4658,7 @@
set_WD_paper_length_Y (buffer, 0);
}
hexdump (MSG_IO, "Window set - back", buffer, windowDataSize);
- memcpy (s->buffer + set_windowB.size +
+ memcpy (s->buffer + setwinB->size +
window_parameter_data_blockB.size + windowDataSize, buffer,
windowDataSize);
set_SW_xferlen (s->buffer,
@@ -4402,7 +4666,7 @@
2 * windowDataSize));
scsiCommandLength =
window_parameter_data_blockB.size + 2 * windowDataSize +
- set_windowB.size;
+ setwinB->size;
}
else
{
@@ -4410,10 +4674,11 @@
set_SW_xferlen (s->buffer, (window_parameter_data_blockB.size +
windowDataSize));
scsiCommandLength =
- window_parameter_data_blockB.size + windowDataSize + set_windowB.size;
+ window_parameter_data_blockB.size + windowDataSize + setwinB->size;
}
- ret = do_scsi_cmd (s->sfd, s->buffer, scsiCommandLength, NULL, 0, NULL);
+ ret = do_cmd (s->connection, s->sfd, s->buffer, scsiCommandLength,
+ NULL, 0, NULL);
if (ret)
return ret;
DBG (10, "set_window_param: ok\n");
@@ -6427,7 +6692,7 @@
scanner->val[OPT_TL_X].w = 0;
scanner->val[OPT_TL_Y].w = 0;
/* this size is just big enough to match letter and A4 formats */
- scanner->bottom_right_x = SANE_FIX (215.9);
+ scanner->bottom_right_x = SANE_FIX (215.0);
scanner->bottom_right_y = SANE_FIX (297.0);
scanner->page_width = FIXED_MM_TO_SCANNER_UNIT (scanner->bottom_right_x);
scanner->page_height = FIXED_MM_TO_SCANNER_UNIT (scanner->bottom_right_y);
@@ -6453,6 +6718,8 @@
scanner->opt[OPT_DROPOUT_COLOR].cap = SANE_CAP_INACTIVE;
scanner->dropout_color = MSEL_dropout_DEFAULT;
+ if ( strstr (scanner->productName, "4220" ))
+ scanner->gamma = 0x80;
scanner->sleep_time = 15;
scanner->use_imprinter = SANE_FALSE;
--- backend/fujitsu.h.orig 2002-09-16 05:19:54.000000000 -0700
+++ backend/fujitsu.h 2003-02-12 14:00:17.000000000 -0800
@@ -102,6 +102,13 @@
};
+typedef enum { /* hardware connection to the scanner */
+ SANE_FUJITSU_NODEV, /* default, no HW specified yet */
+ SANE_FUJITSU_SCSI, /* SCSI interface */
+ SANE_FUJITSU_PIO, /* parallel interface */
+ SANE_FUJITSU_USB /* USB interface */
+} Fujitsu_Connection_Type;
+
struct fujitsu
{
struct fujitsu *next;
@@ -121,6 +128,9 @@
int model; /* The scanner model. */
char *devicename; /* The name of the scanner device. */
+
+ Fujitsu_Connection_Type connection; /* hardware interface type */
+
int sfd; /* The scanner device file descriptor. */
int color_raster_offset; /* offset between r and b scan line and */
@@ -466,16 +476,26 @@
static SANE_Status attachScanner (const char *devicename,
struct fujitsu **devp);
-static SANE_Status senseHandler (int scsi_fd, u_char * result, void *arg);
+static SANE_Status scsiSenseHandler (int scsi_fd, u_char * result, void *arg);
static int identifyScanner (struct fujitsu *s);
static void doInquiry (struct fujitsu *s);
+static int
+do_cmd (Fujitsu_Connection_Type connection, int fd, unsigned char *cmd,
+ int cmd_len, unsigned char *out, size_t req_out_len,
+ size_t *res_out_len);
+
static int do_scsi_cmd (int fd, unsigned char *cmd, int cmd_len,
unsigned char *out, size_t req_out_len,
size_t *res_out_len);
+static int
+do_usb_cmd (int fd, unsigned char *cmd,
+ int cmd_len, unsigned char *out, size_t req_out_len,
+ size_t *res_out_len);
+
static void hexdump (int level, char *comment, unsigned char *p, int l);
static SANE_Status init_options (struct fujitsu *scanner);
--- backend/fujitsu.conf.orig 2002-04-17 11:50:36.000000000 -0700
+++ backend/fujitsu.conf 2003-02-13 14:57:00.000000000 -0800
@@ -1,3 +1,8 @@
#option force-model fi-4340Cdi
#/dev/sg1
scsi FUJITSU
+# For Fujitsu scanners connected via USB on a known device:
+# usb /dev/usb/scanner0
+# For Fujitsu scanners connected via USB where vendor/product Id are known
+# (use lsusb to find these):
+# usb 0x04c5 0x1042
--- doc/descriptions/fujitsu.desc.orig 2002-09-23 03:16:54.000000000 -0700
+++ doc/descriptions/fujitsu.desc 2003-02-13 15:04:51.000000000 -0800
@@ -37,6 +37,8 @@
:interface "SCSI"
:model "M4097"
:interface "SCSI"
+:model "fi-4220C"
+:interface "SCSI USB"
:model "fi-4340C"
-:interface "SCSI"
+:interface "SCSI USB"
--- doc/sane-fujitsu.man.orig 2002-11-29 12:15:30.000000000 -0800
+++ doc/sane-fujitsu.man 2003-02-13 15:13:15.000000000 -0800
@@ -4,13 +4,13 @@
.IX sane-m3096g
.SH NAME
-sane-fujitsu \- SANE backend for Fujitsu flatbed scanners
+sane-fujitsu \- SANE backend for Fujitsu flatbed and ADF scanners
.SH DESCRIPTION
The
.B sane-fujitsu
library implements a SANE (Scanner Access Now Easy) backend which
-provides access to Fujitsu flatbed scanners.
+provides access to Fujitsu flatbed and ADF scanners.
At present, the following
scanners are known to work with this backend:
.PP
@@ -27,6 +27,8 @@
.br
FUJITSU M4097
.br
+FUJITSU fi-4220C
+.br
FUJITSU fi-4340C
.br
FUJITSU M3091DCd BF21
@@ -157,6 +159,7 @@
sane(7),
sane\-scsi(5),
sane\-sp15c(5)
+sane\-usb(5),
.br
Fujitsu ScanPartner 15C OEM Manual, Doc. No. 250-0081-0
.br
@@ -172,6 +175,7 @@
3091 driver: Frederik Ramm <frederik at remote.org>
3093GD,fi-4340C, ipc and cmp options: Oliver Schirrmeister <oschirr at abm.de>
3092 patch: Mario Goppold <mgoppold at tbzpariv.tcc-chemnitz.de>
+fi-4220C patch and USB support: Ronald B. Cemer <ron at roncemer.com>
.SH LIMITATIONS
Only tested with Linux 2.4
@@ -180,4 +184,4 @@
but I haven't seen them yet.
I don't know if the ScanPartner 15C still works, because I'm not able
to test it.
-3091/3092 don't support halftone
\ No newline at end of file
+3091/3092 don't support halftone
More information about the sane-devel
mailing list