kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			414 wiersze
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			414 wiersze
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
| /* sane - Scanner Access Now Easy.
 | |
|    Copyright (C) 1998 F.W. Dillema (dillema@acm.org)
 | |
| 
 | |
|    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. */
 | |
| 
 | |
| /*
 | |
| 	$Id$
 | |
| 	This file implements the low-level scsi-commands.
 | |
| */
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /* SCSI commands that the Ricoh scanners understand: */
 | |
| #define RICOH_SCSI_TEST_UNIT_READY	0x00
 | |
| #define RICOH_SCSI_SET_WINDOW	        0x24
 | |
| #define RICOH_SCSI_GET_WINDOW	        0x25
 | |
| #define RICOH_SCSI_READ_SCANNED_DATA	0x28
 | |
| #define RICOH_SCSI_INQUIRY		0x12
 | |
| #define RICOH_SCSI_MODE_SELECT		0x15
 | |
| #define RICOH_SCSI_START_SCAN		0x1b
 | |
| #define RICOH_SCSI_MODE_SENSE		0x1a
 | |
| #define RICOH_SCSI_GET_BUFFER_STATUS	0x34
 | |
| #define RICOH_SCSI_OBJECT_POSITION      0x31
 | |
| 
 | |
| /* How long do we wait for scanner to have data for us */
 | |
| #define MAX_WAITING_TIME       15
 | |
| 
 | |
| 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;
 | |
| };
 | |
| 
 | |
| 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] = RICOH_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] = RICOH_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 = RICOH_SCSI_MODE_SELECT;
 | |
|   select_cmd.cmd.byte2 |= SMS_PF;
 | |
|   select_cmd.cmd.len = sizeof(select_cmd.smh) + sizeof(select_cmd.mp);
 | |
|   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 = RICOH_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 = RICOH_SCSI_START_SCAN;
 | |
|   cmd.len = wl_size;
 | |
|   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 ricoh_window_data *rwd)
 | |
| {
 | |
| 
 | |
|   static struct {
 | |
|     struct scsi_window_cmd cmd;
 | |
|     struct ricoh_window_data rwd;
 | |
|   } win;
 | |
| 
 | |
|   SANE_Status status;
 | |
|   DBG (11, ">> set_window\n");
 | |
| 
 | |
|   memset (&win, 0, sizeof (win));
 | |
|   win.cmd.opcode = RICOH_SCSI_SET_WINDOW;
 | |
|   _lto3b(sizeof(*rwd), win.cmd.len);
 | |
|   memcpy (&win.rwd, rwd, sizeof(*rwd));
 | |
|   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 ricoh_window_data *rwd)
 | |
| {
 | |
| 
 | |
|   static struct scsi_window_cmd cmd;
 | |
|   static size_t rwd_size;
 | |
|   SANE_Status status;
 | |
| 
 | |
|   rwd_size = sizeof(*rwd);
 | |
|   DBG (11, ">> get_window datalen = %lu\n", (unsigned long) rwd_size);
 | |
| 
 | |
|   memset (&cmd, 0, sizeof (cmd));
 | |
|   cmd.opcode = RICOH_SCSI_GET_WINDOW;
 | |
| #if 0
 | |
|   cmd.byte2 |= (SANE_Byte)0x01; /* set Single bit to get one window desc. */
 | |
| #endif
 | |
|   _lto3b(rwd_size, cmd.len);
 | |
|   status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), rwd, &rwd_size);
 | |
| 
 | |
|   DBG (11, "<< get_window, datalen = %lu\n", (unsigned long) rwd_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 = RICOH_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)
 | |
| {
 | |
|   static SANE_Byte cmd[10];
 | |
|   SANE_Status status;
 | |
|   DBG (11, ">> object_position\n");
 | |
| 
 | |
|   memset (cmd, 0, sizeof (cmd));
 | |
|   cmd[0] = RICOH_SCSI_OBJECT_POSITION;
 | |
|   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 = RICOH_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
 | |
| ricoh_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, "ricoh_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
 | |
| ricoh_wait_ready (Ricoh_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, "ricoh_wait_ready: timed out after %lu seconds\n",
 | |
|                   (u_long) (now - start));
 | |
|               return SANE_STATUS_INVAL;
 | |
|             }
 | |
|           break;
 | |
| 
 | |
|         case SANE_STATUS_GOOD:
 | |
| 	  DBG(11, "ricoh_wait_ready: %d bytes ready\n", _3btol(dbs.filled));
 | |
| 	  return status;
 | |
| 	  break;
 | |
| 	}
 | |
|       usleep (1000000);      /* retry after 100ms */
 | |
|     }
 | |
|   return SANE_STATUS_INVAL;
 | |
| }
 |