[sane-devel] Fujitsu USB patches
Ron Cemer
ron at roncemer.com
Thu Feb 13 23:40:44 GMT 2003
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.
Code formatting may not be exactly as you would expect, so please feel
free to use indent to correct it if you like.
Thanks!
Ron Cemer
-------------- 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-13 15:03:17.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);
}
@@ -4352,18 +4609,26 @@
* follows without a header of its own.
*/
+
+ scsiblk *setwinB;
+ 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 +4640,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 +4659,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 +4667,7 @@
2 * windowDataSize));
scsiCommandLength =
window_parameter_data_blockB.size + 2 * windowDataSize +
- set_windowB.size;
+ setwinB->size;
}
else
{
@@ -4410,10 +4675,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 +6693,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 +6719,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 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
.SH DESCRIPTION
The
.B sane-fujitsu
library implements a SANE (Scanner Access Now Easy) backend which
-provides access to Fujitsu flatbed and ADF scanners.
+provides access to Fujitsu flatbed scanners.
At present, the following
scanners are known to work with this backend:
.PP
@@ -27,8 +27,6 @@
.br
FUJITSU M4097
.br
-FUJITSU fi-4220C
-.br
FUJITSU fi-4340C
.br
FUJITSU M3091DCd BF21
@@ -159,7 +157,6 @@
sane(7),
sane\-scsi(5),
sane\-sp15c(5)
-sane\-usb(5),
.br
Fujitsu ScanPartner 15C OEM Manual, Doc. No. 250-0081-0
.br
@@ -175,7 +172,6 @@
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
@@ -184,4 +180,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
+3091/3092 don't support halftone
\ No newline at end of file
More information about the sane-devel
mailing list