diff --git a/AUTHORS b/AUTHORS index 89b850092..369d4dfb4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -36,6 +36,7 @@ Backends: hp: Peter Kirchgessner (*) Geoffrey Dairiki hpsj5s: Max Vorobiev (*) + ibm: mf, Henning Meier-Geinitz (*) leo: Frank Zago (*) ma1509: Henning Meier-Geinitz (*) matsushita: Frank Zago (*) @@ -152,6 +153,7 @@ Matthew Duggan Matthew Marjanovic Max Vorobiev Meino Christian Cramer +mf Michael Herder Michael K. Johnson Michel Roelofs diff --git a/ChangeLog b/ChangeLog index e379e530c..a84e590cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2003-04-15 Henning Meier-Geinitz + + * AUTHORS backend/Makefile.in backend/dll.conf backend/ibm-scsi.c + backend/ibm.c backend/ibm.conf backend/ibm.h doc/Makefile.in + doc/sane.man doc/sane-ibm.man doc/.cvsignore + doc/descriptions/ibm.desc: Added IBM backend for the + IBM 2456, the Ricoh IS-420 and maybe the IS-410 and IS-430 from + mf . Added manual page, fixed some + warnings, Added detection for IS-410 and IS-430. + 2003-04-14 Henning Meier-Geinitz * tools/sane-desc.c: Fixed some HTML bugs. diff --git a/backend/Makefile.in b/backend/Makefile.in index caab1498e..ad70ae359 100644 --- a/backend/Makefile.in +++ b/backend/Makefile.in @@ -66,7 +66,7 @@ PRELOADABLE_BACKENDS = abaton agfafocus apple artec as6e avision bh canon \ microtek2 mustek mustek_pp mustek_usb nec @NET@ pie @PINT@ plustek \ @PNM@ @QCAM@ ricoh s9036 sceptre sharp @SM3600@ @SNAPSCAN@ \ sp15c st400 tamarack test teco1 teco2 teco3 umax umax_pp umax1220u \ - @V4L@ artec_eplus48u ma1509 + @V4L@ artec_eplus48u ma1509 ibm ifneq (@SELECTED_BACKENDS@,) PRELOADABLE_BACKENDS = @SELECTED_BACKENDS@ endif @@ -111,6 +111,7 @@ DISTFILES = abaton.c abaton.conf abaton.h agfafocus.c agfafocus.conf \ hp-device.c hp-device.h hp.h hp-handle.c hp-handle.h hp-hpmem.c hp-option.c \ hp-option.h hp.README hp-scl.c hp-scl.h hp-scsi.h hp.TODO \ hpsj5s.c hpsj5s.conf hpsj5s.h \ + ibm.c ibm.conf ibm.h ibm-scsi.c \ jinclude.h \ leo.c leo.h leo.conf \ lm9830.h \ @@ -314,6 +315,9 @@ libsane-hp.la: ../sanei/sanei_scsi.lo libsane-hp.la: ../sanei/sanei_usb.lo libsane-hp.la: $(addsuffix .lo,$(EXTRA_hp)) libsane-hp.la: ../sanei/sanei_pio.lo +libsane-ibm.la: ../sanei/sanei_scsi.lo +libsane-ibm.la: ../sanei/sanei_config2.lo +libsane-ibm.la: ../sanei/sanei_constrain_value.lo libsane-leo.la: ../sanei/sanei_config2.lo libsane-leo.la: ../sanei/sanei_constrain_value.lo libsane-leo.la: ../sanei/sanei_scsi.lo diff --git a/backend/dll.conf b/backend/dll.conf index 5cc188f87..acc6e119f 100644 --- a/backend/dll.conf +++ b/backend/dll.conf @@ -23,6 +23,7 @@ fujitsu gt68xx hp hpsj5s +ibm leo ma1509 matsushita diff --git a/backend/ibm-scsi.c b/backend/ibm-scsi.c new file mode 100644 index 000000000..819f04bd4 --- /dev/null +++ b/backend/ibm-scsi.c @@ -0,0 +1,433 @@ +/* sane - Scanner Access Now Easy. + + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +/* +*/ + +#include + + +/* SCSI commands that the Ibm scanners understand: */ +#define IBM_SCSI_TEST_UNIT_READY 0x00 +#define IBM_SCSI_SET_WINDOW 0x24 +#define IBM_SCSI_GET_WINDOW 0x25 +#define IBM_SCSI_READ_SCANNED_DATA 0x28 +#define IBM_SCSI_INQUIRY 0x12 +#define IBM_SCSI_MODE_SELECT 0x15 +#define IBM_SCSI_START_SCAN 0x1b +#define IBM_SCSI_MODE_SENSE 0x1a +#define IBM_SCSI_GET_BUFFER_STATUS 0x34 +#define IBM_SCSI_OBJECT_POSITION 0x31 + +/* How long do we wait for scanner to have data for us */ +#define MAX_WAITING_TIME 15 + +/* for object_position command */ +#define OBJECT_POSITION_UNLOAD 0 +#define OBJECT_POSITION_LOAD 1 + +struct scsi_window_cmd { + SANE_Byte opcode; + SANE_Byte byte2; + SANE_Byte reserved[4]; + SANE_Byte len[3]; + SANE_Byte control; +}; + +struct scsi_mode_select_cmd { + SANE_Byte opcode; + SANE_Byte byte2; +#define SMS_SP 0x01 +#define SMS_PF 0x10 + SANE_Byte page_code; /* for mode_sense, reserved for mode_select */ + SANE_Byte unused[1]; + SANE_Byte len; + SANE_Byte control; +}; + +struct scsi_mode_header { + SANE_Byte data_length; /* Sense data length */ + SANE_Byte medium_type; + SANE_Byte dev_spec; + SANE_Byte blk_desc_len; +}; + +/* next struct introduced by mf */ +struct scsi_object_position_cmd { + SANE_Byte opcode; + SANE_Byte position_func; + SANE_Byte count[3]; + SANE_Byte res[3]; + SANE_Byte control; + SANE_Byte res2; +}; + +struct scsi_get_buffer_status_cmd { + SANE_Byte opcode; + SANE_Byte byte2; + SANE_Byte res[5]; + SANE_Byte len[2]; + SANE_Byte control; +}; + +struct scsi_status_desc { + SANE_Byte window_id; + SANE_Byte byte2; + SANE_Byte available[3]; + SANE_Byte filled[3]; +}; + +struct scsi_status_data { + SANE_Byte len[3]; + SANE_Byte byte4; + struct scsi_status_desc desc; +}; + +struct scsi_start_scan_cmd { + SANE_Byte opcode; + SANE_Byte byte2; + SANE_Byte unused[2]; + SANE_Byte len; + SANE_Byte control; +}; + +struct scsi_read_scanner_cmd { + SANE_Byte opcode; + SANE_Byte byte2; + SANE_Byte data_type; + SANE_Byte byte3; + SANE_Byte data_type_qualifier[2]; + SANE_Byte len[3]; + SANE_Byte control; +}; + +static SANE_Status +test_unit_ready (int fd) +{ + static SANE_Byte cmd[6]; + SANE_Status status; + DBG (11, ">> test_unit_ready\n"); + + cmd[0] = IBM_SCSI_TEST_UNIT_READY; + memset (cmd, 0, sizeof (cmd)); + status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), 0, 0); + + DBG (11, "<< test_unit_ready\n"); + return (status); +} + +static SANE_Status +inquiry (int fd, void *buf, size_t * buf_size) +{ + static SANE_Byte cmd[6]; + SANE_Status status; + DBG (11, ">> inquiry\n"); + + memset (cmd, 0, sizeof (cmd)); + cmd[0] = IBM_SCSI_INQUIRY; + cmd[4] = *buf_size; + status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), buf, buf_size); + + DBG (11, "<< inquiry\n"); + return (status); +} + +static SANE_Status +mode_select (int fd, struct mode_pages *mp) +{ + static struct { + struct scsi_mode_select_cmd cmd; + struct scsi_mode_header smh; + struct mode_pages mp; + } select_cmd; + SANE_Status status; + DBG (11, ">> mode_select\n"); + + memset (&select_cmd, 0, sizeof (select_cmd)); + select_cmd.cmd.opcode = IBM_SCSI_MODE_SELECT; + select_cmd.cmd.byte2 |= SMS_PF; + select_cmd.cmd.len = sizeof(select_cmd.smh) + sizeof(select_cmd.mp); +/* next line by mf */ +/* select_cmd.cmd.page_code= 20; */ + memcpy (&select_cmd.mp, mp, sizeof(*mp)); + status = sanei_scsi_cmd (fd, &select_cmd, sizeof (select_cmd), 0, 0); + + DBG (11, "<< mode_select\n"); + return (status); +} + +#if 0 +static SANE_Status +mode_sense (int fd, struct mode_pages *mp, SANE_Byte page_code) +{ + static struct scsi_mode_select_cmd cmd; /* no type, we can reuse it for sensing */ + static struct { + struct scsi_mode_header smh; + struct mode_pages mp; + } select_data; + static size_t select_size = sizeof(select_data); + SANE_Status status; + DBG (11, ">> mode_sense\n"); + + memset (&cmd, 0, sizeof (cmd)); + cmd.opcode = IBM_SCSI_MODE_SENSE; + cmd.page_code = page_code; + cmd.len = sizeof(select_data); + status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), &select_data, &select_size); + memcpy (mp, &select_data.mp, sizeof(*mp)); + + DBG (11, "<< mode_sense\n"); + return (status); +} +#endif + +static SANE_Status +trigger_scan (int fd) +{ + static struct scsi_start_scan_cmd cmd; + static char window_id_list[1] = { '\0' }; /* scan start data out */ + static size_t wl_size = 1; + SANE_Status status; + DBG (11, ">> trigger scan\n"); + + memset (&cmd, 0, sizeof (cmd)); + cmd.opcode = IBM_SCSI_START_SCAN; + cmd.len = wl_size; +/* next line by mf */ +/* cmd.unused[0] = 1; */ + if (wl_size) + status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), &window_id_list, &wl_size); + else + status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), 0, 0); + + DBG (11, "<< trigger scan\n"); + return (status); +} + +static SANE_Status +set_window (int fd, struct ibm_window_data *iwd) +{ + + static struct { + struct scsi_window_cmd cmd; + struct ibm_window_data iwd; + } win; + + SANE_Status status; + DBG (11, ">> set_window\n"); + + memset (&win, 0, sizeof (win)); + win.cmd.opcode = IBM_SCSI_SET_WINDOW; + _lto3b(sizeof(*iwd), win.cmd.len); + memcpy (&win.iwd, iwd, sizeof(*iwd)); + status = sanei_scsi_cmd (fd, &win, sizeof (win), 0, 0); + + DBG (11, "<< set_window\n"); + return (status); +} + +static SANE_Status +get_window (int fd, struct ibm_window_data *iwd) +{ + + static struct scsi_window_cmd cmd; + static size_t iwd_size; + SANE_Status status; + + iwd_size = sizeof(*iwd); + DBG (11, ">> get_window datalen = %lu\n", (unsigned long) iwd_size); + + memset (&cmd, 0, sizeof (cmd)); + cmd.opcode = IBM_SCSI_GET_WINDOW; +#if 1 /* it was if 0 */ + cmd.byte2 |= (SANE_Byte)0x01; /* set Single bit to get one window desc. */ +#endif + _lto3b(iwd_size, cmd.len); + status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), iwd, &iwd_size); + + DBG (11, "<< get_window, datalen = %lu\n", (unsigned long) iwd_size); + return (status); +} + +static SANE_Status +read_data (int fd, void *buf, size_t * buf_size) +{ + static struct scsi_read_scanner_cmd cmd; + SANE_Status status; + DBG (11, ">> read_data %lu\n", (unsigned long) *buf_size); + + memset (&cmd, 0, sizeof (cmd)); + cmd.opcode = IBM_SCSI_READ_SCANNED_DATA; + _lto3b(*buf_size, cmd.len); + status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), buf, buf_size); + + DBG (11, "<< read_data %lu\n", (unsigned long) *buf_size); + return (status); +} + +static SANE_Status +object_position (int fd, int load) +{ + static struct scsi_object_position_cmd cmd; + SANE_Status status; + DBG (11, ">> object_position\n"); + + memset (&cmd, 0, sizeof (cmd)); + cmd.opcode = IBM_SCSI_OBJECT_POSITION; + if (load) + cmd.position_func = OBJECT_POSITION_LOAD; + else + cmd.position_func = OBJECT_POSITION_UNLOAD; + _lto3b(1, cmd.count); + status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), 0, 0); + + DBG (11, "<< object_position\n"); + return (status); +} + +static SANE_Status +get_data_status (int fd, struct scsi_status_desc *dbs) +{ + static struct scsi_get_buffer_status_cmd cmd; + static struct scsi_status_data ssd; + size_t ssd_size = sizeof(ssd); + SANE_Status status; + DBG (11, ">> get_data_status %lu\n", (unsigned long) ssd_size); + + memset (&cmd, 0, sizeof (cmd)); + cmd.opcode = IBM_SCSI_GET_BUFFER_STATUS; + _lto2b(ssd_size, cmd.len); + status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), &ssd, &ssd_size); + + memcpy (dbs, &ssd.desc, sizeof(*dbs)); + if (status == SANE_STATUS_GOOD && + ((unsigned int) _3btol(ssd.len) <= sizeof(*dbs) || _3btol(ssd.desc.filled) == 0)) { + DBG (11, "get_data_status: busy\n"); + status = SANE_STATUS_DEVICE_BUSY; + } + + DBG (11, "<< get_data_status %lu\n", (unsigned long) ssd_size); + return (status); +} + +#if 0 +static SANE_Status +ibm_wait_ready_tur (int fd) +{ + struct timeval now, start; + SANE_Status status; + + gettimeofday (&start, 0); + + while (1) + { + DBG(3, "scsi_wait_ready: sending TEST_UNIT_READY\n"); + + status = sanei_scsi_cmd (fd, test_unit_ready, sizeof (test_unit_ready), + 0, 0); + switch (status) + { + default: + /* Ignore errors while waiting for scanner to become ready. + Some SCSI drivers return EIO while the scanner is + returning to the home position. */ + DBG(1, "scsi_wait_ready: test unit ready failed (%s)\n", + sane_strstatus (status)); + /* fall through */ + case SANE_STATUS_DEVICE_BUSY: + gettimeofday (&now, 0); + if (now.tv_sec - start.tv_sec >= MAX_WAITING_TIME) + { + DBG(1, "ibm_wait_ready: timed out after %lu seconds\n", + (u_long) (now.tv_sec - start.tv_sec)); + return SANE_STATUS_INVAL; + } + usleep (100000); /* retry after 100ms */ + break; + + case SANE_STATUS_GOOD: + return status; + } + } + return SANE_STATUS_INVAL; +} +#endif + +static SANE_Status +ibm_wait_ready (Ibm_Scanner * s) +{ + struct scsi_status_desc dbs; + time_t now, start; + SANE_Status status; + + start = time(NULL); + + while (1) + { + status = get_data_status (s->fd, &dbs); + + switch (status) + { + default: + /* Ignore errors while waiting for scanner to become ready. + Some SCSI drivers return EIO while the scanner is + returning to the home position. */ + DBG(1, "scsi_wait_ready: get datat status failed (%s)\n", + sane_strstatus (status)); + /* fall through */ + case SANE_STATUS_DEVICE_BUSY: + now = time(NULL); + if (now - start >= MAX_WAITING_TIME) + { + DBG(1, "ibm_wait_ready: timed out after %lu seconds\n", + (u_long) (now - start)); + return SANE_STATUS_INVAL; + } + break; + + case SANE_STATUS_GOOD: + DBG(11, "ibm_wait_ready: %d bytes ready\n", _3btol(dbs.filled)); + return status; + break; + } + usleep (1000000); /* retry after 100ms */ + } + return SANE_STATUS_INVAL; +} diff --git a/backend/ibm.c b/backend/ibm.c new file mode 100644 index 000000000..b3444a256 --- /dev/null +++ b/backend/ibm.c @@ -0,0 +1,1172 @@ +/* sane - Scanner Access Now Easy. + + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. +*/ + +/* + This file implements a SANE backend for the Ibm 2456 flatbed scanner, + written by mf . It derives from the backend for + Ricoh flatbed scanners written by Feico W. Dillema. +*/ + +#define BUILD 3 + +#include "../include/sane/config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "../include/sane/sane.h" +#include "../include/sane/saneopts.h" +#include "../include/sane/sanei_scsi.h" +#include "ibm.h" + +#define BACKEND_NAME ibm +#include "../include/sane/sanei_backend.h" + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +#include "../include/sane/sanei_config.h" +#define IBM_CONFIG_FILE "ibm.conf" + +#define MM_PER_INCH 25.4 +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +static int num_devices = 0; +static Ibm_Device *first_dev = NULL; +static Ibm_Scanner *first_handle = NULL; +/* static int is50 = 0; */ + +#include "ibm-scsi.c" + +static size_t +max_string_size (const SANE_String_Const strings[]) +{ + size_t size, max_size = 0; + int i; + DBG (11, ">> max_string_size\n"); + + for (i = 0; strings[i]; ++i) + { + size = strlen (strings[i]) + 1; + if (size > max_size) + max_size = size; + } + + DBG (11, "<< max_string_size\n"); + return max_size; +} + +static SANE_Status +attach (const char *devnam, Ibm_Device ** devp) +{ + SANE_Status status; + Ibm_Device *dev; + + int fd; + struct inquiry_data ibuf; + struct measurements_units_page mup; + struct ibm_window_data wbuf; + size_t buf_size; + char *str; + DBG (11, ">> attach\n"); + + for (dev = first_dev; dev; dev = dev->next) + { + if (strcmp (dev->sane.name, devnam) == 0) + { + if (devp) + *devp = dev; + return (SANE_STATUS_GOOD); + } + } + + DBG (3, "attach: opening %s\n", devnam); + status = sanei_scsi_open (devnam, &fd, NULL, NULL); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attach: open failed: %s\n", sane_strstatus (status)); + return (status); + } + + DBG (3, "attach: sending INQUIRY\n"); + memset (&ibuf, 0, sizeof (ibuf)); + buf_size = sizeof(ibuf); +/* next line by mf */ + ibuf.byte2 = 2; + status = inquiry (fd, &ibuf, &buf_size); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attach: inquiry failed: %s\n", sane_strstatus (status)); + sanei_scsi_close (fd); + return (status); + } + + if (ibuf.devtype != 6) + { + DBG (1, "attach: device \"%s\" is not a scanner\n", devnam); + sanei_scsi_close (fd); + return (SANE_STATUS_INVAL); + } + + if (!( + (strncmp (ibuf.vendor, "IBM", 3) ==0 + && strncmp (ibuf.product, "2456", 4) == 0) + || (strncmp (ibuf.vendor, "RICOH", 5) == 0 + && strncmp (ibuf.product, "IS420", 5) == 0) + || (strncmp (ibuf.vendor, "RICOH", 5) == 0 + && strncmp (ibuf.product, "IS410", 5) == 0) + || (strncmp (ibuf.vendor, "RICOH", 5) == 0 + && strncmp (ibuf.product, "IS430", 5) == 0) + )) + { + DBG (1, "attach: device \"%s\" doesn't look like a scanner I know\n", + devnam); + sanei_scsi_close (fd); + return (SANE_STATUS_INVAL); + } + + DBG (3, "attach: sending TEST_UNIT_READY\n"); + status = test_unit_ready (fd); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attach: test unit ready failed (%s)\n", + sane_strstatus (status)); + sanei_scsi_close (fd); + return (status); + } + + DBG (3, "attach: sending OBJECT POSITION\n"); + status = object_position (fd, OBJECT_POSITION_UNLOAD); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attach: OBJECT POSTITION failed\n"); + sanei_scsi_close (fd); + return (SANE_STATUS_INVAL); + } + + memset (&mup, 0, sizeof (mup)); + mup.page_code = MEASUREMENTS_PAGE; + mup.parameter_length = 0x06; + mup.bmu = INCHES; + mup.mud[0] = (DEFAULT_MUD >> 8) & 0xff; + mup.mud[1] = (DEFAULT_MUD & 0xff); + +#if 0 + DBG (3, "attach: sending MODE SELECT\n"); + status = mode_select (fd, (struct mode_pages *) &mup); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attach: MODE_SELECT failed\n"); + sanei_scsi_close (fd); + return (SANE_STATUS_INVAL); + } +#endif + +#if 0 + DBG (3, "attach: sending MODE SENSE\n"); + memset (&mup, 0, sizeof (mup)); + status = mode_sense (fd, (struct mode_pages *) &mup, PC_CURRENT | MEASUREMENTS_PAGE); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attach: MODE_SENSE failed\n"); + sanei_scsi_close (fd); + return (SANE_STATUS_INVAL); + } +#endif + + DBG (3, "attach: sending GET WINDOW\n"); + memset (&wbuf, 0, sizeof (wbuf)); + status = get_window (fd, &wbuf); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attach: GET_WINDOW failed %d\n", status); + sanei_scsi_close (fd); + DBG (11, "<< attach\n"); + return (SANE_STATUS_INVAL); + } + + sanei_scsi_close (fd); + + dev = malloc (sizeof (*dev)); + if (!dev) + return (SANE_STATUS_NO_MEM); + memset (dev, 0, sizeof (*dev)); + + dev->sane.name = strdup (devnam); + dev->sane.vendor = "IBM"; + str = malloc (16 + 1); + memset (str, 0, sizeof (str)); + strncpy (str, ibuf.product, sizeof(ibuf.product)); + strncpy (str + sizeof(ibuf.revision), ibuf.revision, sizeof(ibuf.revision)); + str[sizeof(ibuf.product) + sizeof(ibuf.revision)] = '\0'; + dev->sane.model = str; + dev->sane.type = "flatbed scanner"; + + DBG (5, "dev->sane.name = %s\n", dev->sane.name); + DBG (5, "dev->sane.vendor = %s\n", dev->sane.vendor); + DBG (5, "dev->sane.model = %s\n", dev->sane.model); + DBG (5, "dev->sane.type = %s\n", dev->sane.type); + + dev->info.xres_default = _2btol(wbuf.x_res); + dev->info.yres_default = _2btol(wbuf.y_res); + dev->info.image_mode_default = wbuf.image_comp; + + /* if you throw the MRIF bit the brighness control reverses too */ + /* so I reverse the reversal in software for symmetry's sake */ + /* I should make this into an option */ + + if (wbuf.image_comp == IBM_GRAYSCALE || wbuf.image_comp == IBM_DITHERED_MONOCHROME) + { + dev->info.brightness_default = 256 - wbuf.brightness; +/* + if (is50) + dev->info.contrast_default = wbuf.contrast; + else +*/ + dev->info.contrast_default = 256 - wbuf.contrast; + } + else /* wbuf.image_comp == IBM_BINARY_MONOCHROME */ + { + dev->info.brightness_default = wbuf.brightness; + dev->info.contrast_default = wbuf.contrast; + } + +/* da rivedere + dev->info.adf_default = wbuf.adf_state; +*/ + dev->info.adf_default = ADF_UNUSED; + dev->info.adf_default = IBM_PAPER_USER_DEFINED; + +#if 1 + dev->info.bmu = mup.bmu; + dev->info.mud = _2btol(mup.mud); + if (dev->info.mud == 0) { + /* The Ricoh says it uses points as default Basic Measurement Unit */ + /* but gives a Measurement Unit Divisor of zero */ + /* So, we set it to the default (SCSI-standard) of 1200 */ + /* with BMU in inches, i.e. 1200 points equal 1 inch */ + dev->info.bmu = INCHES; + dev->info.mud = DEFAULT_MUD; + } +#else + dev->info.bmu = INCHES; + dev->info.mud = DEFAULT_MUD; +#endif + + DBG (5, "xres_default=%d\n", dev->info.xres_default); + DBG (5, "xres_range.max=%d\n", dev->info.xres_range.max); + DBG (5, "xres_range.min=%d\n", dev->info.xres_range.min); + + DBG (5, "yres_default=%d\n", dev->info.yres_default); + DBG (5, "yres_range.max=%d\n", dev->info.yres_range.max); + DBG (5, "yres_range.min=%d\n", dev->info.yres_range.min); + + DBG (5, "x_range.max=%d\n", dev->info.x_range.max); + DBG (5, "y_range.max=%d\n", dev->info.y_range.max); + + DBG (5, "image_mode=%d\n", dev->info.image_mode_default); + + DBG (5, "brightness=%d\n", dev->info.brightness_default); + DBG (5, "contrast=%d\n", dev->info.contrast_default); + + DBG (5, "adf_state=%d\n", dev->info.adf_default); + + DBG (5, "bmu=%d\n", dev->info.bmu); + DBG (5, "mud=%d\n", dev->info.mud); + + ++num_devices; + dev->next = first_dev; + first_dev = dev; + + if (devp) + *devp = dev; + + DBG (11, "<< attach\n"); + return (SANE_STATUS_GOOD); +} + +static SANE_Status +attach_one(const char *devnam) +{ + attach (devnam, NULL); + return SANE_STATUS_GOOD; +} + +static SANE_Status +init_options (Ibm_Scanner * s) +{ + int i; + DBG (11, ">> init_options\n"); + + memset (s->opt, 0, sizeof (s->opt)); + memset (s->val, 0, sizeof (s->val)); + + for (i = 0; i < NUM_OPTIONS; ++i) + { + s->opt[i].size = sizeof (SANE_Word); + s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + } + + s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; + s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; + + /* "Mode" group: */ + s->opt[OPT_MODE_GROUP].title = "Scan Mode"; + s->opt[OPT_MODE_GROUP].desc = ""; + s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_MODE_GROUP].cap = 0; + s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* scan mode */ + s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; + s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; + s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; + s->opt[OPT_MODE].type = SANE_TYPE_STRING; + s->opt[OPT_MODE].size = max_string_size (mode_list); + s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + s->opt[OPT_MODE].constraint.string_list = mode_list; + s->val[OPT_MODE].s = strdup (mode_list[s->hw->info.image_mode_default]); + + /* x resolution */ + s->opt[OPT_X_RESOLUTION].name = "X" SANE_NAME_SCAN_RESOLUTION; + s->opt[OPT_X_RESOLUTION].title = "X " SANE_TITLE_SCAN_RESOLUTION; + s->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; + s->opt[OPT_X_RESOLUTION].type = SANE_TYPE_INT; + s->opt[OPT_X_RESOLUTION].unit = SANE_UNIT_DPI; + s->opt[OPT_X_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_X_RESOLUTION].constraint.range = &ibm2456_res_range; + s->val[OPT_X_RESOLUTION].w = s->hw->info.xres_default; +/* + if (is50) + s->opt[OPT_X_RESOLUTION].constraint.range = &is50_res_range; + else +*/ + s->opt[OPT_X_RESOLUTION].constraint.range = &ibm2456_res_range; + + /* y resolution */ + s->opt[OPT_Y_RESOLUTION].name = "Y" SANE_NAME_SCAN_RESOLUTION; + s->opt[OPT_Y_RESOLUTION].title = "Y " SANE_TITLE_SCAN_RESOLUTION; + s->opt[OPT_Y_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; + s->opt[OPT_Y_RESOLUTION].type = SANE_TYPE_INT; + s->opt[OPT_Y_RESOLUTION].unit = SANE_UNIT_DPI; + s->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; + s->val[OPT_Y_RESOLUTION].w = s->hw->info.yres_default; + s->opt[OPT_Y_RESOLUTION].constraint.range = &ibm2456_res_range; + + /* adf */ + s->opt[OPT_ADF].name = "adf"; + s->opt[OPT_ADF].title = "Use ADF"; + s->opt[OPT_ADF].desc = "Uses the automatic document feeder."; + s->opt[OPT_ADF].type = SANE_TYPE_BOOL; + s->opt[OPT_ADF].unit = SANE_UNIT_NONE; + s->opt[OPT_ADF].constraint_type = SANE_CONSTRAINT_NONE; + s->val[OPT_ADF].b = s->hw->info.adf_default; + + /* "Geometry" group: */ + s->opt[OPT_GEOMETRY_GROUP].title = "Geometry"; + s->opt[OPT_GEOMETRY_GROUP].desc = ""; + s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* paper */ + s->opt[OPT_PAPER].name = "paper"; + s->opt[OPT_PAPER].title = "Paper format"; + s->opt[OPT_PAPER].desc = "Sets the paper format."; + s->opt[OPT_PAPER].type = SANE_TYPE_STRING; + s->opt[OPT_PAPER].size = max_string_size (paper_list); + s->opt[OPT_PAPER].constraint_type = SANE_CONSTRAINT_STRING_LIST; + s->opt[OPT_PAPER].constraint.string_list = paper_list; + s->val[OPT_PAPER].s = strdup (paper_list[s->hw->info.paper_default]); + + /* top-left x */ + s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; + s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; + s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; + s->opt[OPT_TL_X].type = SANE_TYPE_INT; + s->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL; + s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_TL_X].constraint.range = &default_x_range; + s->val[OPT_TL_X].w = 0; + + /* top-left y */ + s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; + s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; + s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; + s->opt[OPT_TL_Y].type = SANE_TYPE_INT; + s->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL; + s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_TL_Y].constraint.range = &default_y_range; + s->val[OPT_TL_Y].w = 0; + + /* bottom-right x */ + s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; + s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; + s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; + s->opt[OPT_BR_X].type = SANE_TYPE_INT; + s->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL; + s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_BR_X].constraint.range = &default_x_range; + s->val[OPT_BR_X].w = default_x_range.max; + + /* bottom-right y */ + s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; + s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; + s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; + s->opt[OPT_BR_Y].type = SANE_TYPE_INT; + s->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL; + s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_BR_Y].constraint.range = &default_y_range; + s->val[OPT_BR_Y].w = default_y_range.max; + + /* "Enhancement" group: */ + s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement"; + s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; + s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; + s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* brightness */ + s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; + s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; + s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; + s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; + s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; + s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_BRIGHTNESS].constraint.range = &u8_range; + s->val[OPT_BRIGHTNESS].w = s->hw->info.brightness_default; + + /* contrast */ + s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; + s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; + s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; + s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; + s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE; + s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_CONTRAST].constraint.range = &u8_range; + s->val[OPT_CONTRAST].w = s->hw->info.contrast_default; + + DBG (11, "<< init_options\n"); + return SANE_STATUS_GOOD; +} + +static SANE_Status +do_cancel (Ibm_Scanner * s) +{ + SANE_Status status; + DBG (11, ">> do_cancel\n"); + + DBG (3, "cancel: sending OBJECT POSITION\n"); + status = object_position (s->fd, OBJECT_POSITION_UNLOAD); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "cancel: OBJECT POSTITION failed\n"); + } + + s->scanning = SANE_FALSE; + + if (s->fd >= 0) + { + sanei_scsi_close (s->fd); + s->fd = -1; + } + + DBG (11, "<< do_cancel\n"); + return (SANE_STATUS_CANCELLED); +} + +SANE_Status +sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) +{ + char devnam[PATH_MAX] = "/dev/scanner"; + FILE *fp; + + DBG_INIT (); + DBG (11, ">> sane_init (authorize = %p)\n", authorize); + +#if defined PACKAGE && defined VERSION + DBG (2, "sane_init: ibm backend version %d.%d-%d (" + PACKAGE " " VERSION ")\n", V_MAJOR, V_MINOR, BUILD); +#endif + + if (version_code) + *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0); + + fp = sanei_config_open(IBM_CONFIG_FILE); + if (fp) + { + char line[PATH_MAX], *lp; + size_t len; + + /* read config file */ + while (sanei_config_read (line, sizeof (line), fp)) + { + if (line[0] == '#') /* ignore line comments */ + continue; + len = strlen (line); + + if (!len) + continue; /* ignore empty lines */ + + /* skip white space: */ + for (lp = line; isspace(*lp); ++lp); + strcpy (devnam, lp); + } + fclose (fp); + } + sanei_config_attach_matching_devices (devnam, attach_one); + DBG (11, "<< sane_init\n"); + return SANE_STATUS_GOOD; +} + +void +sane_exit (void) +{ + Ibm_Device *dev, *next; + DBG (11, ">> sane_exit\n"); + + for (dev = first_dev; dev; dev = next) + { + next = dev->next; + free ((void *) dev->sane.name); + free ((void *) dev->sane.model); + free (dev); + } + + DBG (11, "<< sane_exit\n"); +} + +SANE_Status +sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) +{ + static const SANE_Device **devlist = 0; + Ibm_Device *dev; + int i; + DBG (11, ">> sane_get_devices (local_only = %d)\n", local_only); + + if (devlist) + free (devlist); + devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); + if (!devlist) + return (SANE_STATUS_NO_MEM); + + i = 0; + for (dev = first_dev; dev; dev = dev->next) + devlist[i++] = &dev->sane; + devlist[i++] = 0; + + *device_list = devlist; + + DBG (11, "<< sane_get_devices\n"); + return SANE_STATUS_GOOD; +} + +SANE_Status +sane_open (SANE_String_Const devnam, SANE_Handle * handle) +{ + SANE_Status status; + Ibm_Device *dev; + Ibm_Scanner *s; + DBG (11, ">> sane_open\n"); + + if (devnam[0] == '\0') + { + for (dev = first_dev; dev; dev = dev->next) + { + if (strcmp (dev->sane.name, devnam) == 0) + break; + } + + if (!dev) + { + status = attach (devnam, &dev); + if (status != SANE_STATUS_GOOD) + return (status); + } + } + else + { + dev = first_dev; + } + + if (!dev) + return (SANE_STATUS_INVAL); + + s = malloc (sizeof (*s)); + if (!s) + return SANE_STATUS_NO_MEM; + memset (s, 0, sizeof (*s)); + + s->fd = -1; + s->hw = dev; + + init_options (s); + + s->next = first_handle; + first_handle = s; + + *handle = s; + + DBG (11, "<< sane_open\n"); + return SANE_STATUS_GOOD; +} + +void +sane_close (SANE_Handle handle) +{ + Ibm_Scanner *s = (Ibm_Scanner *) handle; + DBG (11, ">> sane_close\n"); + + if (s->fd != -1) + sanei_scsi_close (s->fd); + free (s); + + DBG (11, ">> sane_close\n"); +} + +const SANE_Option_Descriptor * +sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) +{ + Ibm_Scanner *s = handle; + DBG (11, ">> sane_get_option_descriptor\n"); + + if ((unsigned) option >= NUM_OPTIONS) + return (0); + + DBG (11, "<< sane_get_option_descriptor\n"); + return (s->opt + option); +} + +SANE_Status +sane_control_option (SANE_Handle handle, SANE_Int option, + SANE_Action action, void *val, SANE_Int * info) +{ + Ibm_Scanner *s = handle; + SANE_Status status; + SANE_Word cap; + DBG (11, ">> sane_control_option\n"); + + if (info) + *info = 0; + + if (s->scanning) + return (SANE_STATUS_DEVICE_BUSY); + if (option >= NUM_OPTIONS) + return (SANE_STATUS_INVAL); + + cap = s->opt[option].cap; + if (!SANE_OPTION_IS_ACTIVE (cap)) + return (SANE_STATUS_INVAL); + + if (action == SANE_ACTION_GET_VALUE) + { + DBG (11, "sane_control_option get_value\n"); + switch (option) + { + /* word options: */ + case OPT_X_RESOLUTION: + case OPT_Y_RESOLUTION: + case OPT_TL_X: + case OPT_TL_Y: + case OPT_BR_X: + case OPT_BR_Y: + case OPT_NUM_OPTS: + case OPT_BRIGHTNESS: + case OPT_CONTRAST: + *(SANE_Word *) val = s->val[option].w; + return (SANE_STATUS_GOOD); + + /* bool options: */ + case OPT_ADF: + *(SANE_Bool *) val = s->val[option].b; + return (SANE_STATUS_GOOD); + + /* string options: */ + case OPT_MODE: + case OPT_PAPER: + strcpy (val, s->val[option].s); + return (SANE_STATUS_GOOD); + } + } + else { + DBG (11, "sane_control_option set_value\n"); + if (action == SANE_ACTION_SET_VALUE) + { + if (!SANE_OPTION_IS_SETTABLE (cap)) + return (SANE_STATUS_INVAL); + + status = sanei_constrain_value (s->opt + option, val, info); + if (status != SANE_STATUS_GOOD) + return status; + + switch (option) + { + /* (mostly) side-effect-free word options: */ + case OPT_X_RESOLUTION: + case OPT_Y_RESOLUTION: + if (info && s->val[option].w != *(SANE_Word *) val) + *info |= SANE_INFO_RELOAD_PARAMS; + s->val[option].w = *(SANE_Word *) val; + return (SANE_STATUS_GOOD); + + case OPT_TL_X: + case OPT_TL_Y: + case OPT_BR_X: + case OPT_BR_Y: + if (info && s->val[option].w != *(SANE_Word *) val) + *info |= SANE_INFO_RELOAD_PARAMS; + s->val[option].w = *(SANE_Word *) val; + /* resets the paper format to user defined */ + if (strcmp(s->val[OPT_PAPER].s, paper_list[IBM_PAPER_USER_DEFINED]) != 0) + { + if (info) + *info |= SANE_INFO_RELOAD_OPTIONS; + if (s->val[OPT_PAPER].s) + free (s->val[OPT_PAPER].s); + s->val[OPT_PAPER].s = strdup (paper_list[IBM_PAPER_USER_DEFINED]); + } + return (SANE_STATUS_GOOD); + + case OPT_NUM_OPTS: + case OPT_BRIGHTNESS: + case OPT_CONTRAST: + s->val[option].w = *(SANE_Word *) val; + return (SANE_STATUS_GOOD); + + case OPT_MODE: + if (info && strcmp (s->val[option].s, (SANE_String) val)) + *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; + if (s->val[option].s) + free (s->val[option].s); + s->val[option].s = strdup (val); + return (SANE_STATUS_GOOD); + + case OPT_ADF: + s->val[option].b = *(SANE_Bool *) val; + if (*(SANE_Bool *) val) + s->adf_state = ADF_ARMED; + else + s->adf_state = ADF_UNUSED; + return (SANE_STATUS_GOOD); + + case OPT_PAPER: + if (info && strcmp (s->val[option].s, (SANE_String) val)) + *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; + if (s->val[option].s) + free (s->val[option].s); + s->val[option].s = strdup (val); + if (strcmp (s->val[OPT_PAPER].s, "User") != 0) + { + s->val[OPT_TL_X].w = 0; + s->val[OPT_TL_Y].w = 0; + if (strcmp (s->val[OPT_PAPER].s, "A3") == 0) + { + s->val[OPT_BR_X].w = PAPER_A3_W; + s->val[OPT_BR_Y].w = PAPER_A3_H; + } + else if (strcmp (s->val[OPT_PAPER].s, "A4") == 0) + { + s->val[OPT_BR_X].w = PAPER_A4_W; + s->val[OPT_BR_Y].w = PAPER_A4_H; + } + else if (strcmp (s->val[OPT_PAPER].s, "A4R") == 0) + { + s->val[OPT_BR_X].w = PAPER_A4R_W; + s->val[OPT_BR_Y].w = PAPER_A4R_H; + } + else if (strcmp (s->val[OPT_PAPER].s, "A5") == 0) + { + s->val[OPT_BR_X].w = PAPER_A5_W; + s->val[OPT_BR_Y].w = PAPER_A5_H; + } + else if (strcmp (s->val[OPT_PAPER].s, "A5R") == 0) + { + s->val[OPT_BR_X].w = PAPER_A5R_W; + s->val[OPT_BR_Y].w = PAPER_A5R_H; + } + else if (strcmp (s->val[OPT_PAPER].s, "A6") == 0) + { + s->val[OPT_BR_X].w = PAPER_A6_W; + s->val[OPT_BR_Y].w = PAPER_A6_H; + } + else if (strcmp (s->val[OPT_PAPER].s, "B4") == 0) + { + s->val[OPT_BR_X].w = PAPER_B4_W; + s->val[OPT_BR_Y].w = PAPER_B4_H; + } + else if (strcmp (s->val[OPT_PAPER].s, "Legal") == 0) + { + s->val[OPT_BR_X].w = PAPER_LEGAL_W; + s->val[OPT_BR_Y].w = PAPER_LEGAL_H; + } + else if (strcmp (s->val[OPT_PAPER].s, "Letter") == 0) + { + s->val[OPT_BR_X].w = PAPER_LETTER_W; + s->val[OPT_BR_Y].w = PAPER_LETTER_H; + } + } + return (SANE_STATUS_GOOD); + } + + } + } + + DBG (11, "<< sane_control_option\n"); + return (SANE_STATUS_INVAL); +} + +SANE_Status +sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) +{ + Ibm_Scanner *s = handle; + DBG (11, ">> sane_get_parameters\n"); + + if (!s->scanning) + { + int width, length, xres, yres; + const char *mode; + + memset (&s->params, 0, sizeof (s->params)); + + width = s->val[OPT_BR_X].w - s->val[OPT_TL_X].w; + length = s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w; + xres = s->val[OPT_X_RESOLUTION].w; + yres = s->val[OPT_Y_RESOLUTION].w; + + /* make best-effort guess at what parameters will look like once + scanning starts. */ + if (xres > 0 && yres > 0 && width > 0 && length > 0) + { + s->params.pixels_per_line = width * xres / s->hw->info.mud; + s->params.lines = length * yres / s->hw->info.mud; + } + + mode = s->val[OPT_MODE].s; + if ((strcmp (mode, "Lineart") == 0) || + (strcmp (mode, "Halftone")) == 0) + { + s->params.format = SANE_FRAME_GRAY; + s->params.bytes_per_line = s->params.pixels_per_line / 8; + /* the Ibm truncates to the byte boundary, so: chop! */ + s->params.pixels_per_line = s->params.bytes_per_line * 8; + s->params.depth = 1; + } + else /* if (strcmp (mode, "Gray") == 0) */ + { + s->params.format = SANE_FRAME_GRAY; + s->params.bytes_per_line = s->params.pixels_per_line; + s->params.depth = 8; + } + s->params.last_frame = SANE_TRUE; + } + else + DBG (5, "sane_get_parameters: scanning, so can't get params\n"); + + if (params) + *params = s->params; + + DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, " + "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line, + s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_Y_RESOLUTION].w); + + DBG (11, "<< sane_get_parameters\n"); + return (SANE_STATUS_GOOD); +} + + +SANE_Status +sane_start (SANE_Handle handle) +{ + char *mode_str; + Ibm_Scanner *s = handle; + SANE_Status status; + struct ibm_window_data wbuf; + struct measurements_units_page mup; + + DBG (11, ">> sane_start\n"); + + /* First make sure we have a current parameter set. Some of the + parameters will be overwritten below, but that's OK. */ + status = sane_get_parameters (s, 0); + if (status != SANE_STATUS_GOOD) + return status; + + status = sanei_scsi_open (s->hw->sane.name, &s->fd, 0, 0); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "open of %s failed: %s\n", + s->hw->sane.name, sane_strstatus (status)); + return (status); + } + + mode_str = s->val[OPT_MODE].s; + s->xres = s->val[OPT_X_RESOLUTION].w; + s->yres = s->val[OPT_Y_RESOLUTION].w; + s->ulx = s->val[OPT_TL_X].w; + s->uly = s->val[OPT_TL_Y].w; + s->width = s->val[OPT_BR_X].w - s->val[OPT_TL_X].w; + s->length = s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w; + s->brightness = s->val[OPT_BRIGHTNESS].w; + s->contrast = s->val[OPT_CONTRAST].w; + s->bpp = s->params.depth; + if (strcmp (mode_str, "Lineart") == 0) + { + s->image_composition = IBM_BINARY_MONOCHROME; + } + else if (strcmp (mode_str, "Halftone") == 0) + { + s->image_composition = IBM_DITHERED_MONOCHROME; + } + else if (strcmp (mode_str, "Gray") == 0) + { + s->image_composition = IBM_GRAYSCALE; + } + + memset (&wbuf, 0, sizeof (wbuf)); +/* next line commented out by mf */ +/* _lto2b(sizeof(wbuf) - 8, wbuf.len); */ +/* next line by mf */ + _lto2b(IBM_WINDOW_DATA_SIZE, wbuf.len); /* size=320 */ + _lto2b(s->xres, wbuf.x_res); + _lto2b(s->yres, wbuf.y_res); + _lto4b(s->ulx, wbuf.x_org); + _lto4b(s->uly, wbuf.y_org); + _lto4b(s->width, wbuf.width); + _lto4b(s->length, wbuf.length); + + wbuf.image_comp = s->image_composition; + /* if you throw the MRIF bit the brighness control reverses too */ + /* so I reverse the reversal in software for symmetry's sake */ + if (wbuf.image_comp == IBM_GRAYSCALE || wbuf.image_comp == IBM_DITHERED_MONOCHROME) + { + if (wbuf.image_comp == IBM_GRAYSCALE) + wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x80; /* it was 0x90 */ + if (wbuf.image_comp == IBM_DITHERED_MONOCHROME) + wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x10; + wbuf.brightness = 256 - (SANE_Byte) s->brightness; +/* + if (is50) + wbuf.contrast = (SANE_Byte) s->contrast; + else +*/ + wbuf.contrast = 256 - (SANE_Byte) s->contrast; + } + else /* wbuf.image_comp == IBM_BINARY_MONOCHROME */ + { + wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x00; + wbuf.brightness = (SANE_Byte) s->brightness; + wbuf.contrast = (SANE_Byte) s->contrast; + } + + wbuf.threshold = 0; + wbuf.bits_per_pixel = s->bpp; + + wbuf.halftone_code = 2; /* diithering */ + wbuf.halftone_id = 0x0A; /* 8x8 Bayer pattenr */ + wbuf.pad_type = 3; + wbuf.bit_ordering[0] = 0; + wbuf.bit_ordering[1] = 7; /* modified by mf (it was 3) */ + + DBG (5, "xres=%d\n", _2btol(wbuf.x_res)); + DBG (5, "yres=%d\n", _2btol(wbuf.y_res)); + DBG (5, "ulx=%d\n", _4btol(wbuf.x_org)); + DBG (5, "uly=%d\n", _4btol(wbuf.y_org)); + DBG (5, "width=%d\n", _4btol(wbuf.width)); + DBG (5, "length=%d\n", _4btol(wbuf.length)); + DBG (5, "image_comp=%d\n", wbuf.image_comp); + + DBG (11, "sane_start: sending SET WINDOW\n"); + status = set_window (s->fd, &wbuf); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "SET WINDOW failed: %s\n", sane_strstatus (status)); + return (status); + } + + DBG (11, "sane_start: sending GET WINDOW\n"); + memset (&wbuf, 0, sizeof (wbuf)); + status = get_window (s->fd, &wbuf); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status)); + return (status); + } + DBG (5, "xres=%d\n", _2btol(wbuf.x_res)); + DBG (5, "yres=%d\n", _2btol(wbuf.y_res)); + DBG (5, "ulx=%d\n", _4btol(wbuf.x_org)); + DBG (5, "uly=%d\n", _4btol(wbuf.y_org)); + DBG (5, "width=%d\n", _4btol(wbuf.width)); + DBG (5, "length=%d\n", _4btol(wbuf.length)); + DBG (5, "image_comp=%d\n", wbuf.image_comp); + + DBG (11, "sane_start: sending MODE SELECT\n"); + memset (&mup, 0, sizeof (mup)); + mup.page_code = MEASUREMENTS_PAGE; + mup.parameter_length = 0x06; + mup.bmu = INCHES; + mup.mud[0] = (DEFAULT_MUD >> 8) & 0xff; + mup.mud[1] = (DEFAULT_MUD & 0xff); +/* next lines by mf */ + mup.adf_page_code = 0x26; + mup.adf_parameter_length = 6; + if (s->adf_state == ADF_ARMED) + mup.adf_control = 1; + else + mup.adf_control = 0; +/* end lines by mf */ + + status = mode_select (s->fd, (struct mode_pages *) &mup); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attach: MODE_SELECT failed\n"); + return (SANE_STATUS_INVAL); + } + + status = trigger_scan (s->fd); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "start of scan failed: %s\n", sane_strstatus (status)); + /* next line introduced not to freeze xscanimage */ + do_cancel(s); + return status; + } + + /* Wait for scanner to become ready to transmit data */ + status = ibm_wait_ready (s); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "GET DATA STATUS failed: %s\n", sane_strstatus (status)); + return (status); + } + + s->bytes_to_read = s->params.bytes_per_line * s->params.lines; + + DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, " + "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line, + s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_Y_RESOLUTION].w); + + s->scanning = SANE_TRUE; + + DBG (11, "<< sane_start\n"); + return (SANE_STATUS_GOOD); +} + +SANE_Status +sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, + SANE_Int * len) +{ + Ibm_Scanner *s = handle; + SANE_Status status; + size_t nread; + DBG (11, ">> sane_read\n"); + + *len = 0; + + DBG (11, "sane_read: bytes left to read: %ld\n", (u_long) s->bytes_to_read); + + if (s->bytes_to_read == 0) + { + do_cancel (s); + return (SANE_STATUS_EOF); + } + + if (!s->scanning) { + DBG (11, "sane_read: scanning is false!\n"); + return (do_cancel (s)); + } + + nread = max_len; + if (nread > s->bytes_to_read) + nread = s->bytes_to_read; + + DBG (11, "sane_read: read %ld bytes\n", (u_long) nread); + status = read_data (s->fd, buf, &nread); + if (status != SANE_STATUS_GOOD) + { + DBG (11, "sane_read: read error\n"); + do_cancel (s); + return (SANE_STATUS_IO_ERROR); + } + *len = nread; + s->bytes_to_read -= nread; + + DBG (11, "<< sane_read\n"); + return (SANE_STATUS_GOOD); +} + +void +sane_cancel (SANE_Handle handle) +{ + Ibm_Scanner *s = handle; + DBG (11, ">> sane_cancel\n"); + + s->scanning = SANE_FALSE; + + DBG (11, "<< sane_cancel\n"); +} + +SANE_Status +sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) +{ + DBG (5, ">> sane_set_io_mode (handle = %p, non_blocking = %d)\n", + handle, non_blocking); + DBG (5, "<< sane_set_io_mode\n"); + + return SANE_STATUS_UNSUPPORTED; +} + +SANE_Status +sane_get_select_fd (SANE_Handle handle, SANE_Int * fd) +{ + DBG (5, ">> sane_get_select_fd (handle = %p, fd = %p)\n", + handle, fd); + DBG (5, "<< sane_get_select_fd\n"); + + return SANE_STATUS_UNSUPPORTED; +} diff --git a/backend/ibm.conf b/backend/ibm.conf new file mode 100644 index 000000000..e9d4d21f0 --- /dev/null +++ b/backend/ibm.conf @@ -0,0 +1,3 @@ +scsi IBM 2456 +scsi RICOH +/dev/scanner diff --git a/backend/ibm.h b/backend/ibm.h new file mode 100644 index 000000000..0c3ea7dec --- /dev/null +++ b/backend/ibm.h @@ -0,0 +1,393 @@ +/* sane - Scanner Access Now Easy. + + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + + + +#ifndef ibm_h +#define ibm_h 1 + +#include + +#include + +/* defines for scan_image_mode field */ +#define IBM_BINARY_MONOCHROME 0 +#define IBM_DITHERED_MONOCHROME 1 +#define IBM_GRAYSCALE 2 + +/* defines for paper field */ +#define IBM_PAPER_USER_DEFINED 0 +#define IBM_PAPER_A3 1 +#define IBM_PAPER_A4 2 +#define IBM_PAPER_A4L 3 +#define IBM_PAPER_A5 4 +#define IBM_PAPER_A5L 5 +#define IBM_PAPER_A6 6 +#define IBM_PAPER_B4 7 +#define IBM_PAPER_B5 8 +#define IBM_PAPER_LEGAL 9 +#define IBM_PAPER_LETTER 10 + +/* sizes for mode parameter's base_measurement_unit */ +#define INCHES 0 +#define MILLIMETERS 1 +#define POINTS 2 +#define DEFAULT_MUD 1200 +#define MEASUREMENTS_PAGE (SANE_Byte)(0x03) + +/* Mode Page Control */ +#define PC_CURRENT 0x00 +#define PC_CHANGE 0x40 +#define PC_DEFAULT 0x80 +#define PC_SAVED 0xc0 + +static const SANE_String_Const mode_list[] = + { + "Lineart", "Halftone", "Gray", + 0 + }; + +static const SANE_String_Const paper_list[] = + { + "User", + "A3", + "A4", "A4R", + "A5", "A5R", + "A6", + "B4", "B5", + "Legal", "Letter", + 0 + }; + +#define PAPER_A3_W 14032 +#define PAPER_A3_H 19842 +#define PAPER_A4_W 9921 +#define PAPER_A4_H 14032 +#define PAPER_A4R_W 14032 +#define PAPER_A4R_H 9921 +#define PAPER_A5_W 7016 +#define PAPER_A5_H 9921 +#define PAPER_A5R_W 9921 +#define PAPER_A5R_H 7016 +#define PAPER_A6_W 4960 +#define PAPER_A6_H 7016 +#define PAPER_B4_W 11811 +#define PAPER_B4_H 16677 +#define PAPER_B5_W 8598 +#define PAPER_B5_H 12142 +#define PAPER_LEGAL_W 10200 +#define PAPER_LEGAL_H 16800 +#define PAPER_LETTER_W 10200 +#define PAPER_LETTER_H 13200 + +static const SANE_Range u8_range = + { + 0, /* minimum */ + 255, /* maximum */ + 0 /* quantization */ + }; + +static const SANE_Range ibm2456_res_range = + { + 100, /* minimum */ + 600, /* maximum */ + 0 /* quantization */ + }; + +static const SANE_Range default_x_range = + { + 0, /* minimum */ +/* (SANE_Word) ( * DEFAULT_MUD), maximum */ + 14032, /* maximum (found empirically for Gray mode) */ + /* in Lineart mode it works till 14062 */ + 2 /* quantization */ + }; + +static const SANE_Range default_y_range = + { + 0, /* minimum */ +/* (SANE_Word) (14 * DEFAULT_MUD), maximum */ + 20410, /* maximum (found empirically) */ + 2 /* quantization */ + }; + + + +static inline void +_lto2b(SANE_Int val, SANE_Byte *bytes) + +{ + + bytes[0] = (val >> 8) & 0xff; + bytes[1] = val & 0xff; +} + +static inline void +_lto3b(SANE_Int val, SANE_Byte *bytes) + +{ + + bytes[0] = (val >> 16) & 0xff; + bytes[1] = (val >> 8) & 0xff; + bytes[2] = val & 0xff; +} + +static inline void +_lto4b(SANE_Int val, SANE_Byte *bytes) +{ + + bytes[0] = (val >> 24) & 0xff; + bytes[1] = (val >> 16) & 0xff; + bytes[2] = (val >> 8) & 0xff; + bytes[3] = val & 0xff; +} + +static inline SANE_Int +_2btol(SANE_Byte *bytes) +{ + SANE_Int rv; + + rv = (bytes[0] << 8) | + bytes[1]; + return (rv); +} + +static inline SANE_Int +_3btol(SANE_Byte *bytes) +{ + SANE_Int rv; + + rv = (bytes[0] << 16) | + (bytes[1] << 8) | + bytes[2]; + return (rv); +} + +static inline SANE_Int +_4btol(SANE_Byte *bytes) +{ + SANE_Int rv; + + rv = (bytes[0] << 24) | + (bytes[1] << 16) | + (bytes[2] << 8) | + bytes[3]; + return (rv); +} + +typedef enum + { + OPT_NUM_OPTS = 0, + + OPT_MODE_GROUP, + OPT_MODE, + OPT_X_RESOLUTION, + OPT_Y_RESOLUTION, + OPT_ADF, + + OPT_GEOMETRY_GROUP, + OPT_PAPER, /* predefined formats */ + OPT_TL_X, /* top-left x */ + OPT_TL_Y, /* top-left y */ + OPT_BR_X, /* bottom-right x */ + OPT_BR_Y, /* bottom-right y */ + + OPT_ENHANCEMENT_GROUP, + OPT_BRIGHTNESS, + OPT_CONTRAST, + + /* must come last: */ + NUM_OPTIONS + } +Ibm_Option; + +typedef union + { + SANE_Bool b; + SANE_Word w; + SANE_Word *wa; /* word array */ + SANE_String s; + } +Option_Value; + +typedef struct Ibm_Info + { + SANE_Range xres_range; + SANE_Range yres_range; + SANE_Range x_range; + SANE_Range y_range; + SANE_Range brightness_range; + SANE_Range contrast_range; + + SANE_Int xres_default; + SANE_Int yres_default; + SANE_Int image_mode_default; + SANE_Int paper_default; + SANE_Int brightness_default; + SANE_Int contrast_default; + SANE_Int adf_default; + + SANE_Int bmu; + SANE_Int mud; + } +Ibm_Info; + +typedef struct Ibm_Device + { + struct Ibm_Device *next; + SANE_Device sane; + Ibm_Info info; + } +Ibm_Device; + +typedef struct Ibm_Scanner + { + /* all the state needed to define a scan request: */ + struct Ibm_Scanner *next; + int fd; /* SCSI filedescriptor */ + + SANE_Option_Descriptor opt[NUM_OPTIONS]; + Option_Value val[NUM_OPTIONS]; + SANE_Parameters params; + /* scanner dependent/low-level state: */ + Ibm_Device *hw; + + SANE_Int xres; + SANE_Int yres; + SANE_Int ulx; + SANE_Int uly; + SANE_Int width; + SANE_Int length; + SANE_Int brightness; + SANE_Int contrast; + SANE_Int image_composition; + SANE_Int bpp; + SANE_Bool reverse; +/* next lines by mf */ + SANE_Int adf_state; +#define ADF_UNUSED 0 /* scan from flatbed, not ADF */ +#define ADF_ARMED 1 /* scan from ADF, everything's set up */ +#define ADF_CLEANUP 2 /* eject paper from ADF on close */ +/* end lines by mf */ + size_t bytes_to_read; + int scanning; + } +Ibm_Scanner; + +struct inquiry_data { + SANE_Byte devtype; + SANE_Byte byte2; + SANE_Byte byte3; + SANE_Byte byte4; + SANE_Byte byte5; + SANE_Byte res1[2]; + SANE_Byte flags; + SANE_Byte vendor[8]; + SANE_Byte product[8]; + SANE_Byte revision[4]; + SANE_Byte byte[60]; +}; + +#define IBM_WINDOW_DATA_SIZE 320 +struct ibm_window_data { + /* header */ + SANE_Byte reserved[6]; + SANE_Byte len[2]; + /* data */ + SANE_Byte window_id; /* must be zero */ + SANE_Byte reserved0; + SANE_Byte x_res[2]; + SANE_Byte y_res[2]; + SANE_Byte x_org[4]; + SANE_Byte y_org[4]; + SANE_Byte width[4]; + SANE_Byte length[4]; + SANE_Byte brightness; + SANE_Byte threshold; + SANE_Byte contrast; + SANE_Byte image_comp; /* image composition (data type) */ + SANE_Byte bits_per_pixel; + SANE_Byte halftone_code; /* halftone_pattern[0] in ricoh.h */ + SANE_Byte halftone_id; /* halftone_pattern[1] in ricoh.h */ + SANE_Byte pad_type; + SANE_Byte bit_ordering[2]; + SANE_Byte compression_type; + SANE_Byte compression_arg; + SANE_Byte res3[6]; + + /* Vendor Specific parameter byte(s) */ + /* Ricoh specific, follow the scsi2 standard ones */ + SANE_Byte byte1; + SANE_Byte byte2; + SANE_Byte mrif_filtering_gamma_id; + SANE_Byte byte3; + SANE_Byte byte4; + SANE_Byte binary_filter; + SANE_Byte reserved2[18]; + + SANE_Byte reserved3[256]; + +}; + +struct measurements_units_page { + SANE_Byte page_code; /* 0x03 */ + SANE_Byte parameter_length; /* 0x06 */ + SANE_Byte bmu; + SANE_Byte res1; + SANE_Byte mud[2]; + SANE_Byte res2[2]; /* anybody know what `COH' may mean ??? */ +/* next 4 lines by mf */ + SANE_Byte adf_page_code; + SANE_Byte adf_parameter_length; + SANE_Byte adf_control; + SANE_Byte res3[5]; +}; + +struct mode_pages { + SANE_Byte page_code; + SANE_Byte parameter_length; + SANE_Byte rest[14]; /* modified by mf; it was 6; see above */ +#if 0 + SANE_Byte more_pages[243]; /* maximum size 255 bytes (incl header) */ +#endif +}; + + +#endif /* ibm_h */ diff --git a/doc/Makefile.in b/doc/Makefile.in index 812443f62..20aaed207 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -51,7 +51,7 @@ SECT5 = sane-abaton.5 sane-agfafocus.5 sane-apple.5 sane-as6e.5 sane-dll.5 \ sane-mustek_usb.5 sane-sceptre.5 sane-canon_pp.5 sane-canon630u.5 \ sane-teco1.5 sane-teco2.5 sane-teco3.5 sane-test.5 sane-sp15c.5 \ sane-coolscan2.5 sane-hpsj5s.5 sane-gt68xx.5 sane-artec_eplus48u.5 \ - sane-ma1509.5 + sane-ma1509.5 sane-ibm.5 SECT7 = sane.7 MANPAGES = $(SECT1) $(SECT5) $(SECT7) READMES = README AUTHORS COPYING ChangeLog LICENSE NEWS PROBLEMS \ @@ -90,7 +90,7 @@ DISTFILES = Makefile.in backend-writing.txt descriptions.txt \ sane.tex saned.man scanimage.man sane-sceptre.man sane-canon_pp.man \ sane-teco1.man sane-teco2.man sane-teco3.man sane-test.man sane-sp15c.man \ sane-hpsj5s.man gamma4scanimage.man sane-gt68xx.man sane-artec_eplus48u.man \ - sane-ma1509.man + sane-ma1509.man sane-ibm.man .PHONY: all clean depend dist distclean html html-man install \ install-mostang sane-html uninstall diff --git a/doc/descriptions/ibm.desc b/doc/descriptions/ibm.desc new file mode 100644 index 000000000..95a89149f --- /dev/null +++ b/doc/descriptions/ibm.desc @@ -0,0 +1,42 @@ +; SANE Backend specification file +; +; It's basically emacs-lisp --- so ";" indicates comment to end of line. +; All syntactic elements are keyword tokens, followed by a string or +; keyword argument, as specified. +; +; ":backend" *must* be specified. +; All other information is optional (but what good is the file without it?). +; + +:backend "ibm" ; name of backend +:url "http://www.meier-geinitz.de/sane/ibm-backend/" +:version "1.0-3" ; version of backend +:status :alpha ; :alpha, :beta, :stable, :new +; +:manpage "sane-ibm" ; name of manpage (if it exists) + +:devicetype :scanner + +:mfg "IBM" ; name a manufacturer +:url "http://www.ibm.com/" + +:model "2456" ; name models for above-specified mfg. +:interface "SCSI" +:status :alpha +;:comment "?" + +:mfg "Ricoh" ; name a manufacturer +:model "IS-410" +:interface "SCSI" +:status :untested +:comment "Untested, please report!" + +:model "IS-420" +:interface "SCSI" +:status :alpha +:comment "Flatbed works." + +:model "IS-430" +:interface "SCSI" +:status :untested +:comment "Untested, please report!" diff --git a/doc/sane-ibm.man b/doc/sane-ibm.man new file mode 100644 index 000000000..eba55a3bb --- /dev/null +++ b/doc/sane-ibm.man @@ -0,0 +1,88 @@ +.TH sane-ibm 5 "14 Apr 2003" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" +.IX sane-ibm +.SH NAME +sane-ibm \- SANE backend for IBM and Ricoh SCSI flatbed scanners +.SH DESCRIPTION +The +.B sane-ibm +library implements a SANE (Scanner Access Now Easy) backend that provides +access to the IBM 2456 and the Ricoh IS-410, IS-420, and IS-430 flatbed +scanners. Support for the IS-410 and IS-430 is untested. Please contact the +sane-devel mailing list if you own such a scanner. +.PP +This backend is alpha-quality. It may have bugs and some scanners haven't been +tested at all. Be careful and pull the plug if the scanner causes unusual +noise. + +.SH "DEVICE NAMES" +This backend expects device names of the form: +.PP +.RS +.I special +.RE +.PP +Where +.I special +is either the path-name for the special device that corresponds to a SCSI +scanner. The program +.I sane-find-scanner +helps to find out the correct device. Under Linux, such a device name could be +.I /dev/sg0 +or +.IR /dev/sga , +for example. See +.BR sane-scsi (5) +for details. + +.SH CONFIGURATION +The contents of the +.I ibm.conf +file is a list of device names that correspond to SCSI +scanners. Empty lines and lines starting with a hash mark (#) are +ignored. See +.BR sane-scsi (5) +on details of what constitutes a valid device name. + +.SH FILES +.TP +.I @CONFIGDIR@/ibm.conf +The backend configuration file (see also description of +.B SANE_CONFIG_DIR +below). +.TP +.I @LIBDIR@/libsane-ibm.a +The static library implementing this backend. +.TP +.I @LIBDIR@/libsane-ibm.so +The shared library implementing this backend (present on systems that +support dynamic loading). +.SH ENVIRONMENT +.TP +.B SANE_CONFIG_DIR +This environment variable specifies the list of directories that may +contain the configuration file. Under UNIX, the directories are +separated by a colon (`:'), under OS/2, they are separated by a +semi-colon (`;'). If this variable is not set, the configuration file +is searched in two default directories: first, the current working +directory (".") and then in @CONFIGDIR@. If the value of the +environment variable ends with the directory separator character, then +the default directories are searched after the explicitly specified +directories. For example, setting +.B SANE_CONFIG_DIR +to "/tmp/config:" would result in directories "tmp/config", ".", and +"@CONFIGDIR@" being searched (in this order). +.TP +.B SANE_DEBUG_IBM +If the library was compiled with debug support enabled, this +environment variable controls the debug level for this backend. Higher +debug levels increase the verbosity of the output. + +.SH "SEE ALSO" +.BR sane (7), +.BR sane\-find\-scanner (1), +.BR sane\-scsi (5), + +.SH AUTHOR +mf +.br +Manual page and some fixes by Henning Meier-Geinitz diff --git a/doc/sane.man b/doc/sane.man index b1a442938..4d6393344 100644 --- a/doc/sane.man +++ b/doc/sane.man @@ -1,4 +1,4 @@ -.TH sane 7 "13 Apr 2003" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" +.TH sane 7 "14 Apr 2003" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy" .IX sane .SH NAME @@ -260,6 +260,11 @@ The SANE backend for the Hewlett-Packard ScanJet 5S scanner. See .BR sane\-hpsj5s (5) for details. .TP +.B ibm +The SANE backend for some IBM and Ricoh SCSI scanners. See +.BR sane\-ibm (5) +for details. +.TP .B leo This backend supports the Leo S3 and the Across FS-1130, which is a re-badged LEO FS-1130 scanner. See @@ -793,6 +798,7 @@ you can also contact the author of this manual page: .BR sane\-gt68xx (5), .BR sane\-hp (5), .BR sane\-hpsj5s (5), +.BR sane\-ibm (5), .BR sane\-leo (5), .BR sane\-ma1509 (5), .BR sane\-matsushita (5),