1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 1997 Geoffrey T. Dairiki
3141cc406Sopenharmony_ci   This file is part of the SANE package.
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
6141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
7141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
8141cc406Sopenharmony_ci   License, or (at your option) any later version.
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
11141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13141cc406Sopenharmony_ci   General Public License for more details.
14141cc406Sopenharmony_ci
15141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
16141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
19141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
22141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
23141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
24141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
25141cc406Sopenharmony_ci   account of linking the SANE library code into it.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
28141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
29141cc406Sopenharmony_ci   License.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
32141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
33141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
36141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
37141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   This file is part of a SANE backend for HP Scanners supporting
40141cc406Sopenharmony_ci   HP Scanner Control Language (SCL).
41141cc406Sopenharmony_ci*/
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci/*
44141cc406Sopenharmony_ci   Revision 1.15  2008/03/28 14:37:36  kitno-guest
45141cc406Sopenharmony_ci   add usleep to improve usb performance, from jim a t meyering d o t net
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci   Revision 1.14  2004-10-04 18:09:05  kig-guest
48141cc406Sopenharmony_ci   Rename global function hp_init_openfd to sanei_hp_init_openfd
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci   Revision 1.13  2004/03/27 13:52:39  kig-guest
51141cc406Sopenharmony_ci   Keep USB-connection open (was problem with Linux 2.6.x)
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci   Revision 1.12  2003/10/09 19:34:57  kig-guest
54141cc406Sopenharmony_ci   Redo when TEST UNIT READY failed
55141cc406Sopenharmony_ci   Redo when read returns with 0 bytes (non-SCSI only)
56141cc406Sopenharmony_ci*/
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci/*
59141cc406Sopenharmony_ci#define STUBS
60141cc406Sopenharmony_ciextern int sanei_debug_hp;*/
61141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY
62141cc406Sopenharmony_ci#include "../include/sane/config.h"
63141cc406Sopenharmony_ci#include "../include/lalloca.h"		/* Must be first */
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci#ifdef HAVE_UNISTD_H
66141cc406Sopenharmony_ci# include <unistd.h>
67141cc406Sopenharmony_ci#endif
68141cc406Sopenharmony_ci#include <stdlib.h>
69141cc406Sopenharmony_ci#include <ctype.h>
70141cc406Sopenharmony_ci#include <stdio.h>
71141cc406Sopenharmony_ci#include <string.h>
72141cc406Sopenharmony_ci#include <errno.h>
73141cc406Sopenharmony_ci#include "../include/lassert.h"
74141cc406Sopenharmony_ci#include <signal.h>
75141cc406Sopenharmony_ci#include <sys/types.h>
76141cc406Sopenharmony_ci#include <sys/stat.h>
77141cc406Sopenharmony_ci#include <fcntl.h>
78141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
79141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
80141cc406Sopenharmony_ci#include "../include/sane/sanei_pio.h"
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_ci#include "hp.h"
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci#include "hp-option.h"
87141cc406Sopenharmony_ci#include "hp-scsi.h"
88141cc406Sopenharmony_ci#include "hp-scl.h"
89141cc406Sopenharmony_ci#include "hp-device.h"
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci#define HP_SCSI_INQ_LEN		(36)
92141cc406Sopenharmony_ci#define HP_SCSI_CMD_LEN		(6)
93141cc406Sopenharmony_ci#define HP_SCSI_BUFSIZ	(HP_SCSI_MAX_WRITE + HP_SCSI_CMD_LEN)
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_ci#define HP_MAX_OPEN_FD 16
96141cc406Sopenharmony_cistatic struct hp_open_fd_s  /* structure to save info about open file descriptor */
97141cc406Sopenharmony_ci{
98141cc406Sopenharmony_ci    char *devname;
99141cc406Sopenharmony_ci    HpConnect connect;
100141cc406Sopenharmony_ci    int fd;
101141cc406Sopenharmony_ci} asHpOpenFd[HP_MAX_OPEN_FD];
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci
104141cc406Sopenharmony_ci/*
105141cc406Sopenharmony_ci *
106141cc406Sopenharmony_ci */
107141cc406Sopenharmony_cistruct hp_scsi_s
108141cc406Sopenharmony_ci{
109141cc406Sopenharmony_ci    int		fd;
110141cc406Sopenharmony_ci    char      * devname;
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_ci    /* Output buffering */
113141cc406Sopenharmony_ci    hp_byte_t	buf[HP_SCSI_BUFSIZ];
114141cc406Sopenharmony_ci    hp_byte_t *	bufp;
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_ci    hp_byte_t	inq_data[HP_SCSI_INQ_LEN];
117141cc406Sopenharmony_ci};
118141cc406Sopenharmony_ci
119141cc406Sopenharmony_ci#define HP_TMP_BUF_SIZE (1024*4)
120141cc406Sopenharmony_ci#define HP_WR_BUF_SIZE (1024*4)
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_citypedef struct
123141cc406Sopenharmony_ci{
124141cc406Sopenharmony_ci  HpProcessData procdata;
125141cc406Sopenharmony_ci
126141cc406Sopenharmony_ci  int outfd;
127141cc406Sopenharmony_ci  const unsigned char *map;
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_ci  unsigned char *image_buf; /* Buffer to store complete image (if req.) */
130141cc406Sopenharmony_ci  unsigned char *image_ptr;
131141cc406Sopenharmony_ci  int image_buf_size;
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci  unsigned char *tmp_buf; /* Buffer for scan data to get even number of bytes */
134141cc406Sopenharmony_ci  int tmp_buf_size;
135141cc406Sopenharmony_ci  int tmp_buf_len;
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci  unsigned char wr_buf[HP_WR_BUF_SIZE];
138141cc406Sopenharmony_ci  unsigned char *wr_ptr;
139141cc406Sopenharmony_ci  int wr_buf_size;
140141cc406Sopenharmony_ci  int wr_left;
141141cc406Sopenharmony_ci} PROCDATA_HANDLE;
142141cc406Sopenharmony_ci
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_ci/* Initialize structure where we remember out open file descriptors */
145141cc406Sopenharmony_civoid
146141cc406Sopenharmony_cisanei_hp_init_openfd ()
147141cc406Sopenharmony_ci{int iCount;
148141cc406Sopenharmony_ci memset (asHpOpenFd, 0, sizeof (asHpOpenFd));
149141cc406Sopenharmony_ci
150141cc406Sopenharmony_ci for (iCount = 0; iCount < HP_MAX_OPEN_FD; iCount++)
151141cc406Sopenharmony_ci     asHpOpenFd[iCount].fd = -1;
152141cc406Sopenharmony_ci}
153141cc406Sopenharmony_ci
154141cc406Sopenharmony_ci
155141cc406Sopenharmony_ci/* Look if the device is still open */
156141cc406Sopenharmony_cistatic SANE_Status
157141cc406Sopenharmony_cihp_GetOpenDevice (const char *devname, HpConnect connect, int *pfd)
158141cc406Sopenharmony_ci
159141cc406Sopenharmony_ci{int iCount;
160141cc406Sopenharmony_ci
161141cc406Sopenharmony_ci for (iCount = 0; iCount < HP_MAX_OPEN_FD; iCount++)
162141cc406Sopenharmony_ci     {
163141cc406Sopenharmony_ci     if (!asHpOpenFd[iCount].devname) continue;
164141cc406Sopenharmony_ci     if (   (strcmp (asHpOpenFd[iCount].devname, devname) == 0)
165141cc406Sopenharmony_ci         && (asHpOpenFd[iCount].connect == connect) )
166141cc406Sopenharmony_ci         {
167141cc406Sopenharmony_ci         if (pfd) *pfd = asHpOpenFd[iCount].fd;
168141cc406Sopenharmony_ci         DBG(3, "hp_GetOpenDevice: device %s is open with fd=%d\n", devname,
169141cc406Sopenharmony_ci             asHpOpenFd[iCount].fd);
170141cc406Sopenharmony_ci         return SANE_STATUS_GOOD;
171141cc406Sopenharmony_ci         }
172141cc406Sopenharmony_ci     }
173141cc406Sopenharmony_ci DBG(3, "hp_GetOpenDevice: device %s not open\n", devname);
174141cc406Sopenharmony_ci return SANE_STATUS_INVAL;
175141cc406Sopenharmony_ci}
176141cc406Sopenharmony_ci
177141cc406Sopenharmony_ci/* Add an open file descriptor. This also decides */
178141cc406Sopenharmony_ci/* if we keep a connection open or not. */
179141cc406Sopenharmony_cistatic SANE_Status
180141cc406Sopenharmony_cihp_AddOpenDevice (const char *devname, HpConnect connect, int fd)
181141cc406Sopenharmony_ci
182141cc406Sopenharmony_ci{int iCount, iKeepOpen;
183141cc406Sopenharmony_ci static int iInitKeepFlags = 1;
184141cc406Sopenharmony_ci
185141cc406Sopenharmony_ci /* The default values which connections to keep open or not */
186141cc406Sopenharmony_ci static int iKeepOpenSCSI = 0;
187141cc406Sopenharmony_ci static int iKeepOpenUSB = 1;
188141cc406Sopenharmony_ci static int iKeepOpenDevice = 0;
189141cc406Sopenharmony_ci static int iKeepOpenPIO = 0;
190141cc406Sopenharmony_ci
191141cc406Sopenharmony_ci if (iInitKeepFlags) /* Change the defaults by environment */
192141cc406Sopenharmony_ci     {char *eptr;
193141cc406Sopenharmony_ci
194141cc406Sopenharmony_ci     iInitKeepFlags = 0;
195141cc406Sopenharmony_ci
196141cc406Sopenharmony_ci     eptr = getenv ("SANE_HP_KEEPOPEN_SCSI");
197141cc406Sopenharmony_ci     if ( (eptr != NULL) && ((*eptr == '0') || (*eptr == '1')) )
198141cc406Sopenharmony_ci         iKeepOpenSCSI = (*eptr == '1');
199141cc406Sopenharmony_ci
200141cc406Sopenharmony_ci     eptr = getenv ("SANE_HP_KEEPOPEN_USB");
201141cc406Sopenharmony_ci     if ( (eptr != NULL) && ((*eptr == '0') || (*eptr == '1')) )
202141cc406Sopenharmony_ci         iKeepOpenUSB = (*eptr == '1');
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_ci     eptr = getenv ("SANE_HP_KEEPOPEN_DEVICE");
205141cc406Sopenharmony_ci     if ( (eptr != NULL) && ((*eptr == '0') || (*eptr == '1')) )
206141cc406Sopenharmony_ci         iKeepOpenDevice = (*eptr == '1');
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci     eptr = getenv ("SANE_HP_KEEPOPEN_PIO");
209141cc406Sopenharmony_ci     if ( (eptr != NULL) && ((*eptr == '0') || (*eptr == '1')) )
210141cc406Sopenharmony_ci         iKeepOpenPIO = (*eptr == '1');
211141cc406Sopenharmony_ci     }
212141cc406Sopenharmony_ci
213141cc406Sopenharmony_ci /* Look if we should keep it open or not */
214141cc406Sopenharmony_ci iKeepOpen = 0;
215141cc406Sopenharmony_ci switch (connect)
216141cc406Sopenharmony_ci     {
217141cc406Sopenharmony_ci     case HP_CONNECT_SCSI: iKeepOpen = iKeepOpenSCSI;
218141cc406Sopenharmony_ci                           break;
219141cc406Sopenharmony_ci     case HP_CONNECT_PIO : iKeepOpen = iKeepOpenPIO;
220141cc406Sopenharmony_ci                           break;
221141cc406Sopenharmony_ci     case HP_CONNECT_USB : iKeepOpen = iKeepOpenUSB;
222141cc406Sopenharmony_ci                           break;
223141cc406Sopenharmony_ci     case HP_CONNECT_DEVICE : iKeepOpen = iKeepOpenDevice;
224141cc406Sopenharmony_ci                           break;
225141cc406Sopenharmony_ci     case HP_CONNECT_RESERVE:
226141cc406Sopenharmony_ci                           break;
227141cc406Sopenharmony_ci     }
228141cc406Sopenharmony_ci if (!iKeepOpen)
229141cc406Sopenharmony_ci     {
230141cc406Sopenharmony_ci     DBG(3, "hp_AddOpenDevice: %s should not be kept open\n", devname);
231141cc406Sopenharmony_ci     return SANE_STATUS_INVAL;
232141cc406Sopenharmony_ci     }
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_ci for (iCount = 0; iCount < HP_MAX_OPEN_FD; iCount++)
235141cc406Sopenharmony_ci     {
236141cc406Sopenharmony_ci     if (!asHpOpenFd[iCount].devname)  /* Is this entry free ? */
237141cc406Sopenharmony_ci         {
238141cc406Sopenharmony_ci         asHpOpenFd[iCount].devname = sanei_hp_strdup (devname);
239141cc406Sopenharmony_ci         if (!asHpOpenFd[iCount].devname) return SANE_STATUS_NO_MEM;
240141cc406Sopenharmony_ci         DBG(3, "hp_AddOpenDevice: added device %s with fd=%d\n", devname, fd);
241141cc406Sopenharmony_ci         asHpOpenFd[iCount].connect = connect;
242141cc406Sopenharmony_ci         asHpOpenFd[iCount].fd = fd;
243141cc406Sopenharmony_ci         return SANE_STATUS_GOOD;
244141cc406Sopenharmony_ci         }
245141cc406Sopenharmony_ci     }
246141cc406Sopenharmony_ci DBG(3, "hp_AddOpenDevice: %s not added\n", devname);
247141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM;
248141cc406Sopenharmony_ci}
249141cc406Sopenharmony_ci
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci/* Check if we have remembered an open file descriptor */
252141cc406Sopenharmony_cistatic SANE_Status
253141cc406Sopenharmony_cihp_IsOpenFd (int fd, HpConnect connect)
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci{int iCount;
256141cc406Sopenharmony_ci
257141cc406Sopenharmony_ci for (iCount = 0; iCount < HP_MAX_OPEN_FD; iCount++)
258141cc406Sopenharmony_ci     {
259141cc406Sopenharmony_ci     if (   (asHpOpenFd[iCount].devname != NULL)
260141cc406Sopenharmony_ci         && (asHpOpenFd[iCount].fd == fd)
261141cc406Sopenharmony_ci         && (asHpOpenFd[iCount].connect == connect) )
262141cc406Sopenharmony_ci         {
263141cc406Sopenharmony_ci         DBG(3, "hp_IsOpenFd: %d is open\n", fd);
264141cc406Sopenharmony_ci         return SANE_STATUS_GOOD;
265141cc406Sopenharmony_ci         }
266141cc406Sopenharmony_ci     }
267141cc406Sopenharmony_ci DBG(3, "hp_IsOpenFd: %d not open\n", fd);
268141cc406Sopenharmony_ci return SANE_STATUS_INVAL;
269141cc406Sopenharmony_ci}
270141cc406Sopenharmony_ci
271141cc406Sopenharmony_ci
272141cc406Sopenharmony_cistatic SANE_Status
273141cc406Sopenharmony_cihp_RemoveOpenFd (int fd, HpConnect connect)
274141cc406Sopenharmony_ci
275141cc406Sopenharmony_ci{int iCount;
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci for (iCount = 0; iCount < HP_MAX_OPEN_FD; iCount++)
278141cc406Sopenharmony_ci     {
279141cc406Sopenharmony_ci     if (   (asHpOpenFd[iCount].devname != NULL)
280141cc406Sopenharmony_ci         && (asHpOpenFd[iCount].fd == fd)
281141cc406Sopenharmony_ci         && (asHpOpenFd[iCount].connect == connect) )
282141cc406Sopenharmony_ci         {
283141cc406Sopenharmony_ci         sanei_hp_free (asHpOpenFd[iCount].devname);
284141cc406Sopenharmony_ci         asHpOpenFd[iCount].devname = NULL;
285141cc406Sopenharmony_ci         DBG(3, "hp_RemoveOpenFd: removed %d\n", asHpOpenFd[iCount].fd);
286141cc406Sopenharmony_ci         asHpOpenFd[iCount].fd = -1;
287141cc406Sopenharmony_ci         return SANE_STATUS_GOOD;
288141cc406Sopenharmony_ci         }
289141cc406Sopenharmony_ci     }
290141cc406Sopenharmony_ci DBG(3, "hp_RemoveOpenFd: %d not removed\n", fd);
291141cc406Sopenharmony_ci return SANE_STATUS_INVAL;
292141cc406Sopenharmony_ci}
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci
295141cc406Sopenharmony_cistatic SANE_Status
296141cc406Sopenharmony_cihp_nonscsi_write (HpScsi this, hp_byte_t *data, size_t len, HpConnect connect)
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci{int n = -1;
299141cc406Sopenharmony_ci size_t loc_len;
300141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD;
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci if (len <= 0) return SANE_STATUS_GOOD;
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci switch (connect)
305141cc406Sopenharmony_ci {
306141cc406Sopenharmony_ci   case HP_CONNECT_DEVICE:   /* direct device-io */
307141cc406Sopenharmony_ci     n = write (this->fd, data, len);
308141cc406Sopenharmony_ci     break;
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci   case HP_CONNECT_PIO:      /* Use sanepio interface */
311141cc406Sopenharmony_ci     n = sanei_pio_write (this->fd, data, len);
312141cc406Sopenharmony_ci     break;
313141cc406Sopenharmony_ci
314141cc406Sopenharmony_ci   case HP_CONNECT_USB:      /* Not supported */
315141cc406Sopenharmony_ci     loc_len = len;
316141cc406Sopenharmony_ci     status = sanei_usb_write_bulk ((SANE_Int)this->fd, data, &loc_len);
317141cc406Sopenharmony_ci     n = loc_len;
318141cc406Sopenharmony_ci     break;
319141cc406Sopenharmony_ci
320141cc406Sopenharmony_ci   case HP_CONNECT_RESERVE:
321141cc406Sopenharmony_ci     n = -1;
322141cc406Sopenharmony_ci     break;
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci   default:
325141cc406Sopenharmony_ci     n = -1;
326141cc406Sopenharmony_ci     break;
327141cc406Sopenharmony_ci }
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_ci if (n == 0) return SANE_STATUS_EOF;
330141cc406Sopenharmony_ci else if (n < 0) return SANE_STATUS_IO_ERROR;
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci return status;
333141cc406Sopenharmony_ci}
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_cistatic SANE_Status
336141cc406Sopenharmony_cihp_nonscsi_read (HpScsi this, hp_byte_t *data, size_t *len, HpConnect connect,
337141cc406Sopenharmony_ci  int __sane_unused__ isResponse)
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci{int n = -1;
340141cc406Sopenharmony_ci static int retries = -1;
341141cc406Sopenharmony_ci size_t save_len = *len;
342141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD;
343141cc406Sopenharmony_ci
344141cc406Sopenharmony_ci if (*len <= 0) return SANE_STATUS_GOOD;
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_ci if (retries < 0)  /* Read environment */
347141cc406Sopenharmony_ci {char *eptr = getenv ("SANE_HP_RDREDO");
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci   retries = 1;       /* Set default value */
350141cc406Sopenharmony_ci   if (eptr != NULL)
351141cc406Sopenharmony_ci   {
352141cc406Sopenharmony_ci     if (sscanf (eptr, "%d", &retries) != 1) retries = 1; /* Restore default */
353141cc406Sopenharmony_ci     else if (retries < 0) retries = 0; /* Allow no retries here */
354141cc406Sopenharmony_ci   }
355141cc406Sopenharmony_ci }
356141cc406Sopenharmony_ci
357141cc406Sopenharmony_ci for (;;) /* Retry on EOF */
358141cc406Sopenharmony_ci {
359141cc406Sopenharmony_ci   switch (connect)
360141cc406Sopenharmony_ci   {
361141cc406Sopenharmony_ci     case HP_CONNECT_DEVICE:
362141cc406Sopenharmony_ci       n = read (this->fd, data, *len);
363141cc406Sopenharmony_ci       break;
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci     case HP_CONNECT_PIO:
366141cc406Sopenharmony_ci       n = sanei_pio_read (this->fd, data, *len);
367141cc406Sopenharmony_ci       break;
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci     case HP_CONNECT_USB:
370141cc406Sopenharmony_ci       status = sanei_usb_read_bulk((SANE_Int)this->fd, (SANE_Byte *)data, len);
371141cc406Sopenharmony_ci       n = *len;
372141cc406Sopenharmony_ci       break;
373141cc406Sopenharmony_ci
374141cc406Sopenharmony_ci     case HP_CONNECT_RESERVE:
375141cc406Sopenharmony_ci       n = -1;
376141cc406Sopenharmony_ci       break;
377141cc406Sopenharmony_ci
378141cc406Sopenharmony_ci     default:
379141cc406Sopenharmony_ci       n = -1;
380141cc406Sopenharmony_ci       break;
381141cc406Sopenharmony_ci   }
382141cc406Sopenharmony_ci   if ((n != 0) || (retries <= 0)) break;
383141cc406Sopenharmony_ci   retries--;
384141cc406Sopenharmony_ci   usleep (100*1000);  /* sleep 0.1 seconds */
385141cc406Sopenharmony_ci   *len = save_len;    /* Restore value */
386141cc406Sopenharmony_ci }
387141cc406Sopenharmony_ci
388141cc406Sopenharmony_ci if (n == 0) return SANE_STATUS_EOF;
389141cc406Sopenharmony_ci else if (n < 0) return SANE_STATUS_IO_ERROR;
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci *len = n;
392141cc406Sopenharmony_ci return status;
393141cc406Sopenharmony_ci}
394141cc406Sopenharmony_ci
395141cc406Sopenharmony_cistatic SANE_Status
396141cc406Sopenharmony_cihp_nonscsi_open (const char *devname, int *fd, HpConnect connect)
397141cc406Sopenharmony_ci
398141cc406Sopenharmony_ci{int lfd, flags;
399141cc406Sopenharmony_ci SANE_Int dn;
400141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_INVAL;
401141cc406Sopenharmony_ci
402141cc406Sopenharmony_ci#ifdef _O_RDWR
403141cc406Sopenharmony_ci flags = _O_RDWR;
404141cc406Sopenharmony_ci#else
405141cc406Sopenharmony_ci flags = O_RDWR;
406141cc406Sopenharmony_ci#endif
407141cc406Sopenharmony_ci#ifdef _O_EXCL
408141cc406Sopenharmony_ci flags |= _O_EXCL;
409141cc406Sopenharmony_ci#else
410141cc406Sopenharmony_ci flags |= O_EXCL;
411141cc406Sopenharmony_ci#endif
412141cc406Sopenharmony_ci#ifdef _O_BINARY
413141cc406Sopenharmony_ci flags |= _O_BINARY;
414141cc406Sopenharmony_ci#endif
415141cc406Sopenharmony_ci#ifdef O_BINARY
416141cc406Sopenharmony_ci flags |= O_BINARY;
417141cc406Sopenharmony_ci#endif
418141cc406Sopenharmony_ci
419141cc406Sopenharmony_ci switch (connect)
420141cc406Sopenharmony_ci {
421141cc406Sopenharmony_ci   case HP_CONNECT_DEVICE:
422141cc406Sopenharmony_ci     lfd = open (devname, flags);
423141cc406Sopenharmony_ci     if (lfd < 0)
424141cc406Sopenharmony_ci     {
425141cc406Sopenharmony_ci        DBG(1, "hp_nonscsi_open: open device %s failed (%s)\n", devname,
426141cc406Sopenharmony_ci            strerror (errno) );
427141cc406Sopenharmony_ci       status = (errno == EACCES) ? SANE_STATUS_ACCESS_DENIED : SANE_STATUS_INVAL;
428141cc406Sopenharmony_ci     }
429141cc406Sopenharmony_ci     else
430141cc406Sopenharmony_ci       status = SANE_STATUS_GOOD;
431141cc406Sopenharmony_ci     break;
432141cc406Sopenharmony_ci
433141cc406Sopenharmony_ci   case HP_CONNECT_PIO:
434141cc406Sopenharmony_ci     status = sanei_pio_open (devname, &lfd);
435141cc406Sopenharmony_ci     break;
436141cc406Sopenharmony_ci
437141cc406Sopenharmony_ci   case HP_CONNECT_USB:
438141cc406Sopenharmony_ci     DBG(17, "hp_nonscsi_open: open usb with \"%s\"\n", devname);
439141cc406Sopenharmony_ci     status = sanei_usb_open (devname, &dn);
440141cc406Sopenharmony_ci     lfd = (int)dn;
441141cc406Sopenharmony_ci     break;
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_ci   case HP_CONNECT_RESERVE:
444141cc406Sopenharmony_ci     status = SANE_STATUS_INVAL;
445141cc406Sopenharmony_ci     break;
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci   default:
448141cc406Sopenharmony_ci     status = SANE_STATUS_INVAL;
449141cc406Sopenharmony_ci     break;
450141cc406Sopenharmony_ci }
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD)
453141cc406Sopenharmony_ci {
454141cc406Sopenharmony_ci    DBG(1, "hp_nonscsi_open: open device %s failed\n", devname);
455141cc406Sopenharmony_ci }
456141cc406Sopenharmony_ci else
457141cc406Sopenharmony_ci {
458141cc406Sopenharmony_ci    DBG(17,"hp_nonscsi_open: device %s opened, fd=%d\n", devname, lfd);
459141cc406Sopenharmony_ci }
460141cc406Sopenharmony_ci
461141cc406Sopenharmony_ci if (fd) *fd = lfd;
462141cc406Sopenharmony_ci
463141cc406Sopenharmony_ci return status;
464141cc406Sopenharmony_ci}
465141cc406Sopenharmony_ci
466141cc406Sopenharmony_cistatic void
467141cc406Sopenharmony_cihp_nonscsi_close (int fd, HpConnect connect)
468141cc406Sopenharmony_ci
469141cc406Sopenharmony_ci{
470141cc406Sopenharmony_ci switch (connect)
471141cc406Sopenharmony_ci {
472141cc406Sopenharmony_ci   case HP_CONNECT_DEVICE:
473141cc406Sopenharmony_ci     close (fd);
474141cc406Sopenharmony_ci     break;
475141cc406Sopenharmony_ci
476141cc406Sopenharmony_ci   case HP_CONNECT_PIO:
477141cc406Sopenharmony_ci     sanei_pio_close (fd);
478141cc406Sopenharmony_ci     break;
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci   case HP_CONNECT_USB:
481141cc406Sopenharmony_ci     sanei_usb_close (fd);
482141cc406Sopenharmony_ci     break;
483141cc406Sopenharmony_ci
484141cc406Sopenharmony_ci   case HP_CONNECT_RESERVE:
485141cc406Sopenharmony_ci     break;
486141cc406Sopenharmony_ci
487141cc406Sopenharmony_ci   default:
488141cc406Sopenharmony_ci     break;
489141cc406Sopenharmony_ci }
490141cc406Sopenharmony_ci DBG(17,"hp_nonscsi_close: closed fd=%d\n", fd);
491141cc406Sopenharmony_ci}
492141cc406Sopenharmony_ci
493141cc406Sopenharmony_ciSANE_Status
494141cc406Sopenharmony_cisanei_hp_nonscsi_new (HpScsi * newp, const char * devname, HpConnect connect)
495141cc406Sopenharmony_ci{
496141cc406Sopenharmony_ci HpScsi new;
497141cc406Sopenharmony_ci SANE_Status status;
498141cc406Sopenharmony_ci int iAlreadyOpen = 0;
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci  new = sanei_hp_allocz(sizeof(*new));
501141cc406Sopenharmony_ci  if (!new)
502141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
503141cc406Sopenharmony_ci
504141cc406Sopenharmony_ci  /* Is the device already open ? */
505141cc406Sopenharmony_ci  if ( hp_GetOpenDevice (devname, connect, &new->fd) == SANE_STATUS_GOOD )
506141cc406Sopenharmony_ci  {
507141cc406Sopenharmony_ci    iAlreadyOpen = 1;
508141cc406Sopenharmony_ci  }
509141cc406Sopenharmony_ci  else
510141cc406Sopenharmony_ci  {
511141cc406Sopenharmony_ci    status = hp_nonscsi_open(devname, &new->fd, connect);
512141cc406Sopenharmony_ci    if (FAILED(status))
513141cc406Sopenharmony_ci    {
514141cc406Sopenharmony_ci      DBG(1, "nonscsi_new: open failed (%s)\n", sane_strstatus(status));
515141cc406Sopenharmony_ci      sanei_hp_free(new);
516141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
517141cc406Sopenharmony_ci    }
518141cc406Sopenharmony_ci  }
519141cc406Sopenharmony_ci
520141cc406Sopenharmony_ci  /* For SCSI-devices we would have the inquire command here */
521141cc406Sopenharmony_ci  memcpy (new->inq_data, "\003zzzzzzzHP      ------          R000",
522141cc406Sopenharmony_ci          sizeof (new->inq_data));
523141cc406Sopenharmony_ci
524141cc406Sopenharmony_ci  new->bufp = new->buf + HP_SCSI_CMD_LEN;
525141cc406Sopenharmony_ci  new->devname = sanei_hp_alloc ( strlen ( devname ) + 1 );
526141cc406Sopenharmony_ci  if ( new->devname ) strcpy (new->devname, devname);
527141cc406Sopenharmony_ci
528141cc406Sopenharmony_ci  *newp = new;
529141cc406Sopenharmony_ci
530141cc406Sopenharmony_ci  /* Remember the open device */
531141cc406Sopenharmony_ci  if (!iAlreadyOpen) hp_AddOpenDevice (devname, connect, new->fd);
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
534141cc406Sopenharmony_ci}
535141cc406Sopenharmony_ci
536141cc406Sopenharmony_cistatic void
537141cc406Sopenharmony_cihp_scsi_close (HpScsi this, int completely)
538141cc406Sopenharmony_ci{HpConnect connect;
539141cc406Sopenharmony_ci
540141cc406Sopenharmony_ci DBG(3, "scsi_close: closing fd %ld\n", (long)this->fd);
541141cc406Sopenharmony_ci
542141cc406Sopenharmony_ci connect = sanei_hp_scsi_get_connect (this);
543141cc406Sopenharmony_ci
544141cc406Sopenharmony_ci if (!completely)  /* May we keep the device open ? */
545141cc406Sopenharmony_ci {
546141cc406Sopenharmony_ci   if ( hp_IsOpenFd (this->fd, connect) == SANE_STATUS_GOOD )
547141cc406Sopenharmony_ci   {
548141cc406Sopenharmony_ci     DBG(3, "scsi_close: not closing. Keep open\n");
549141cc406Sopenharmony_ci     return;
550141cc406Sopenharmony_ci   }
551141cc406Sopenharmony_ci
552141cc406Sopenharmony_ci }
553141cc406Sopenharmony_ci assert(this->fd >= 0);
554141cc406Sopenharmony_ci
555141cc406Sopenharmony_ci if (connect != HP_CONNECT_SCSI)
556141cc406Sopenharmony_ci   hp_nonscsi_close (this->fd, connect);
557141cc406Sopenharmony_ci else
558141cc406Sopenharmony_ci   sanei_scsi_close (this->fd);
559141cc406Sopenharmony_ci
560141cc406Sopenharmony_ci DBG(3,"scsi_close: really closed\n");
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_ci /* Remove a remembered open device */
563141cc406Sopenharmony_ci hp_RemoveOpenFd (this->fd, connect);
564141cc406Sopenharmony_ci}
565141cc406Sopenharmony_ci
566141cc406Sopenharmony_ci
567141cc406Sopenharmony_ciSANE_Status
568141cc406Sopenharmony_cisanei_hp_scsi_new (HpScsi * newp, const char * devname)
569141cc406Sopenharmony_ci{
570141cc406Sopenharmony_ci  static hp_byte_t inq_cmd[] = { 0x12, 0, 0, 0, HP_SCSI_INQ_LEN, 0};
571141cc406Sopenharmony_ci  static hp_byte_t tur_cmd[] = { 0x00, 0, 0, 0, 0, 0};
572141cc406Sopenharmony_ci  size_t	inq_len		= HP_SCSI_INQ_LEN;
573141cc406Sopenharmony_ci  HpScsi	new;
574141cc406Sopenharmony_ci  HpConnect     connect;
575141cc406Sopenharmony_ci  SANE_Status	status;
576141cc406Sopenharmony_ci  int iAlreadyOpen = 0;
577141cc406Sopenharmony_ci
578141cc406Sopenharmony_ci  connect = sanei_hp_get_connect (devname);
579141cc406Sopenharmony_ci
580141cc406Sopenharmony_ci  if (connect != HP_CONNECT_SCSI)
581141cc406Sopenharmony_ci    return sanei_hp_nonscsi_new (newp, devname, connect);
582141cc406Sopenharmony_ci
583141cc406Sopenharmony_ci  new = sanei_hp_allocz(sizeof(*new));
584141cc406Sopenharmony_ci  if (!new)
585141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
586141cc406Sopenharmony_ci
587141cc406Sopenharmony_ci  /* Is the device still open ? */
588141cc406Sopenharmony_ci  if ( hp_GetOpenDevice (devname, connect, &new->fd) == SANE_STATUS_GOOD )
589141cc406Sopenharmony_ci  {
590141cc406Sopenharmony_ci    iAlreadyOpen = 1;
591141cc406Sopenharmony_ci  }
592141cc406Sopenharmony_ci  else
593141cc406Sopenharmony_ci  {
594141cc406Sopenharmony_ci    status = sanei_scsi_open(devname, &new->fd, 0, 0);
595141cc406Sopenharmony_ci    if (FAILED(status))
596141cc406Sopenharmony_ci      {
597141cc406Sopenharmony_ci        DBG(1, "scsi_new: open failed (%s)\n", sane_strstatus(status));
598141cc406Sopenharmony_ci        sanei_hp_free(new);
599141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
600141cc406Sopenharmony_ci      }
601141cc406Sopenharmony_ci  }
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_ci  DBG(3, "scsi_inquire: sending INQUIRE\n");
604141cc406Sopenharmony_ci  status = sanei_scsi_cmd(new->fd, inq_cmd, 6, new->inq_data, &inq_len);
605141cc406Sopenharmony_ci  if (FAILED(status))
606141cc406Sopenharmony_ci    {
607141cc406Sopenharmony_ci      DBG(1, "scsi_inquire: inquiry failed: %s\n", sane_strstatus(status));
608141cc406Sopenharmony_ci      sanei_scsi_close(new->fd);
609141cc406Sopenharmony_ci      sanei_hp_free(new);
610141cc406Sopenharmony_ci      return status;
611141cc406Sopenharmony_ci    }
612141cc406Sopenharmony_ci
613141cc406Sopenharmony_ci  {char vendor[9], model[17], rev[5];
614141cc406Sopenharmony_ci   memset (vendor, 0, sizeof (vendor));
615141cc406Sopenharmony_ci   memset (model, 0, sizeof (model));
616141cc406Sopenharmony_ci   memset (rev, 0, sizeof (rev));
617141cc406Sopenharmony_ci   memcpy (vendor, new->inq_data + 8, 8);
618141cc406Sopenharmony_ci   memcpy (model, new->inq_data + 16, 16);
619141cc406Sopenharmony_ci   memcpy (rev, new->inq_data + 32, 4);
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_ci   DBG(3, "vendor=%s, model=%s, rev=%s\n", vendor, model, rev);
622141cc406Sopenharmony_ci  }
623141cc406Sopenharmony_ci
624141cc406Sopenharmony_ci  DBG(3, "scsi_new: sending TEST_UNIT_READY\n");
625141cc406Sopenharmony_ci  status = sanei_scsi_cmd(new->fd, tur_cmd, 6, 0, 0);
626141cc406Sopenharmony_ci  if (FAILED(status))
627141cc406Sopenharmony_ci    {
628141cc406Sopenharmony_ci      DBG(1, "hp_scsi_open: test unit ready failed (%s)\n",
629141cc406Sopenharmony_ci	  sane_strstatus(status));
630141cc406Sopenharmony_ci      usleep (500*1000); /* Wait 0.5 seconds */
631141cc406Sopenharmony_ci      DBG(3, "scsi_new: sending TEST_UNIT_READY second time\n");
632141cc406Sopenharmony_ci      status = sanei_scsi_cmd(new->fd, tur_cmd, 6, 0, 0);
633141cc406Sopenharmony_ci    }
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_ci  if (FAILED(status))
636141cc406Sopenharmony_ci    {
637141cc406Sopenharmony_ci      DBG(1, "hp_scsi_open: test unit ready failed (%s)\n",
638141cc406Sopenharmony_ci	  sane_strstatus(status));
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci      sanei_scsi_close(new->fd);
641141cc406Sopenharmony_ci      sanei_hp_free(new);
642141cc406Sopenharmony_ci      return status; /* Fix problem with non-scanner devices */
643141cc406Sopenharmony_ci    }
644141cc406Sopenharmony_ci
645141cc406Sopenharmony_ci  new->bufp = new->buf + HP_SCSI_CMD_LEN;
646141cc406Sopenharmony_ci  new->devname = sanei_hp_alloc ( strlen ( devname ) + 1 );
647141cc406Sopenharmony_ci  if ( new->devname ) strcpy (new->devname, devname);
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci  *newp = new;
650141cc406Sopenharmony_ci
651141cc406Sopenharmony_ci  /* Remember the open device */
652141cc406Sopenharmony_ci  if (!iAlreadyOpen) hp_AddOpenDevice (devname, connect, new->fd);
653141cc406Sopenharmony_ci
654141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
655141cc406Sopenharmony_ci}
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_ci
658141cc406Sopenharmony_ci
659141cc406Sopenharmony_ci/* The "completely" parameter was added for OfficeJet support.
660141cc406Sopenharmony_ci * For JetDirect connections, closing and re-opening the scan
661141cc406Sopenharmony_ci * channel is very time consuming.  Also, the OfficeJet G85
662141cc406Sopenharmony_ci * unloads a loaded document in the ADF when the scan channel
663141cc406Sopenharmony_ci * gets closed.  The solution is to "completely" destroy the
664141cc406Sopenharmony_ci * connection, including closing and deallocating the PTAL
665141cc406Sopenharmony_ci * channel, when initially probing the device in hp-device.c,
666141cc406Sopenharmony_ci * but leave it open while the frontend is actually using the
667141cc406Sopenharmony_ci * device (from hp-handle.c), and "completely" destroy it when
668141cc406Sopenharmony_ci * the frontend closes its handle. */
669141cc406Sopenharmony_civoid
670141cc406Sopenharmony_cisanei_hp_scsi_destroy (HpScsi this,int completely)
671141cc406Sopenharmony_ci{
672141cc406Sopenharmony_ci  /* Moved to hp_scsi_close():
673141cc406Sopenharmony_ci   * assert(this->fd >= 0);
674141cc406Sopenharmony_ci   * DBG(3, "scsi_close: closing fd %d\n", this->fd);
675141cc406Sopenharmony_ci   */
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci  hp_scsi_close (this, completely);
678141cc406Sopenharmony_ci  if ( this->devname ) sanei_hp_free (this->devname);
679141cc406Sopenharmony_ci  sanei_hp_free(this);
680141cc406Sopenharmony_ci}
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_cihp_byte_t *
683141cc406Sopenharmony_cisanei_hp_scsi_inq (HpScsi this)
684141cc406Sopenharmony_ci{
685141cc406Sopenharmony_ci  return this->inq_data;
686141cc406Sopenharmony_ci}
687141cc406Sopenharmony_ci
688141cc406Sopenharmony_ciconst char *
689141cc406Sopenharmony_cisanei_hp_scsi_vendor (HpScsi this)
690141cc406Sopenharmony_ci{
691141cc406Sopenharmony_ci  static char buf[9];
692141cc406Sopenharmony_ci  memcpy(buf, sanei_hp_scsi_inq(this) + 8, 8);
693141cc406Sopenharmony_ci  buf[8] = '\0';
694141cc406Sopenharmony_ci  return buf;
695141cc406Sopenharmony_ci}
696141cc406Sopenharmony_ci
697141cc406Sopenharmony_ciconst char *
698141cc406Sopenharmony_cisanei_hp_scsi_model (HpScsi this)
699141cc406Sopenharmony_ci{
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci  static char buf[17];
702141cc406Sopenharmony_ci  memcpy(buf, sanei_hp_scsi_inq(this) + 16, 16);
703141cc406Sopenharmony_ci  buf[16] = '\0';
704141cc406Sopenharmony_ci  return buf;
705141cc406Sopenharmony_ci}
706141cc406Sopenharmony_ci
707141cc406Sopenharmony_ciconst char *
708141cc406Sopenharmony_cisanei_hp_scsi_devicename (HpScsi this)
709141cc406Sopenharmony_ci{
710141cc406Sopenharmony_ci  return this->devname;
711141cc406Sopenharmony_ci}
712141cc406Sopenharmony_ci
713141cc406Sopenharmony_cihp_bool_t
714141cc406Sopenharmony_cisanei_hp_is_active_xpa (HpScsi scsi)
715141cc406Sopenharmony_ci{HpDeviceInfo *info;
716141cc406Sopenharmony_ci int model_num;
717141cc406Sopenharmony_ci
718141cc406Sopenharmony_ci info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
719141cc406Sopenharmony_ci if (info->active_xpa < 0)
720141cc406Sopenharmony_ci {
721141cc406Sopenharmony_ci   model_num = sanei_hp_get_max_model (scsi);
722141cc406Sopenharmony_ci   info->active_xpa = (model_num >= 17);
723141cc406Sopenharmony_ci   DBG(5,"sanei_hp_is_active_xpa: model=%d, active_xpa=%d\n",
724141cc406Sopenharmony_ci       model_num, info->active_xpa);
725141cc406Sopenharmony_ci }
726141cc406Sopenharmony_ci return info->active_xpa;
727141cc406Sopenharmony_ci}
728141cc406Sopenharmony_ci
729141cc406Sopenharmony_ciint
730141cc406Sopenharmony_cisanei_hp_get_max_model (HpScsi scsi)
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci{HpDeviceInfo *info;
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename  (scsi) );
735141cc406Sopenharmony_ci if (info->max_model < 0)
736141cc406Sopenharmony_ci {enum hp_device_compat_e compat;
737141cc406Sopenharmony_ci  int model_num;
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_ci   if ( sanei_hp_device_probe_model ( &compat, scsi, &model_num, 0)
740141cc406Sopenharmony_ci            == SANE_STATUS_GOOD )
741141cc406Sopenharmony_ci     info->max_model = model_num;
742141cc406Sopenharmony_ci }
743141cc406Sopenharmony_ci return info->max_model;
744141cc406Sopenharmony_ci}
745141cc406Sopenharmony_ci
746141cc406Sopenharmony_ci
747141cc406Sopenharmony_ciint
748141cc406Sopenharmony_cisanei_hp_is_flatbed_adf (HpScsi scsi)
749141cc406Sopenharmony_ci
750141cc406Sopenharmony_ci{int model = sanei_hp_get_max_model (scsi);
751141cc406Sopenharmony_ci
752141cc406Sopenharmony_ci return ((model == 2) || (model == 4) || (model == 5) || (model == 8));
753141cc406Sopenharmony_ci}
754141cc406Sopenharmony_ci
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_ciHpConnect
757141cc406Sopenharmony_cisanei_hp_get_connect (const char *devname)
758141cc406Sopenharmony_ci
759141cc406Sopenharmony_ci{const HpDeviceInfo *info;
760141cc406Sopenharmony_ci HpConnect connect = HP_CONNECT_SCSI;
761141cc406Sopenharmony_ci int got_connect_type = 0;
762141cc406Sopenharmony_ci
763141cc406Sopenharmony_ci info = sanei_hp_device_info_get (devname);
764141cc406Sopenharmony_ci if (!info)
765141cc406Sopenharmony_ci {
766141cc406Sopenharmony_ci   DBG(1, "sanei_hp_get_connect: Could not get info for %s. Assume SCSI\n",
767141cc406Sopenharmony_ci       devname);
768141cc406Sopenharmony_ci   connect = HP_CONNECT_SCSI;
769141cc406Sopenharmony_ci }
770141cc406Sopenharmony_ci else
771141cc406Sopenharmony_ci if ( !(info->config_is_up) )
772141cc406Sopenharmony_ci {
773141cc406Sopenharmony_ci   DBG(1, "sanei_hp_get_connect: Config not initialized for %s. Assume SCSI\n",
774141cc406Sopenharmony_ci       devname);
775141cc406Sopenharmony_ci   connect = HP_CONNECT_SCSI;
776141cc406Sopenharmony_ci }
777141cc406Sopenharmony_ci else
778141cc406Sopenharmony_ci {
779141cc406Sopenharmony_ci   connect = info->config.connect;
780141cc406Sopenharmony_ci   got_connect_type = info->config.got_connect_type;
781141cc406Sopenharmony_ci }
782141cc406Sopenharmony_ci
783141cc406Sopenharmony_ci /* Beware of using a USB-device as a SCSI-device (not 100% perfect) */
784141cc406Sopenharmony_ci if ((connect == HP_CONNECT_SCSI) && !got_connect_type)
785141cc406Sopenharmony_ci {int maybe_usb;
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_ci   maybe_usb = (   strstr (devname, "usb")
788141cc406Sopenharmony_ci                || strstr (devname, "uscanner")
789141cc406Sopenharmony_ci                || strstr (devname, "ugen"));
790141cc406Sopenharmony_ci   if (maybe_usb)
791141cc406Sopenharmony_ci   {static int print_warning = 1;
792141cc406Sopenharmony_ci
793141cc406Sopenharmony_ci     if (print_warning)
794141cc406Sopenharmony_ci     {
795141cc406Sopenharmony_ci       print_warning = 0;
796141cc406Sopenharmony_ci       DBG(1,"sanei_hp_get_connect: WARNING\n");
797141cc406Sopenharmony_ci       DBG(1,"  Device %s assumed to be SCSI, but device name\n",devname);
798141cc406Sopenharmony_ci       DBG(1,"  looks like USB. Will continue with USB.\n");
799141cc406Sopenharmony_ci       DBG(1,"  If you really want it as SCSI, add the following\n");
800141cc406Sopenharmony_ci       DBG(1,"  to your file .../etc/sane.d/hp.conf:\n");
801141cc406Sopenharmony_ci       DBG(1,"    %s\n", devname);
802141cc406Sopenharmony_ci       DBG(1,"      option connect-scsi\n");
803141cc406Sopenharmony_ci       DBG(1,"  The same warning applies to other device names containing\n");
804141cc406Sopenharmony_ci       DBG(1,"  \"usb\", \"uscanner\" or \"ugen\".\n");
805141cc406Sopenharmony_ci     }
806141cc406Sopenharmony_ci     connect = HP_CONNECT_DEVICE;
807141cc406Sopenharmony_ci   }
808141cc406Sopenharmony_ci }
809141cc406Sopenharmony_ci return connect;
810141cc406Sopenharmony_ci}
811141cc406Sopenharmony_ci
812141cc406Sopenharmony_ciHpConnect
813141cc406Sopenharmony_cisanei_hp_scsi_get_connect (HpScsi this)
814141cc406Sopenharmony_ci
815141cc406Sopenharmony_ci{
816141cc406Sopenharmony_ci return sanei_hp_get_connect (sanei_hp_scsi_devicename (this));
817141cc406Sopenharmony_ci}
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci
820141cc406Sopenharmony_cistatic SANE_Status
821141cc406Sopenharmony_cihp_scsi_flush (HpScsi this)
822141cc406Sopenharmony_ci{
823141cc406Sopenharmony_ci  hp_byte_t *	data	= this->buf + HP_SCSI_CMD_LEN;
824141cc406Sopenharmony_ci  size_t 	len 	= this->bufp - data;
825141cc406Sopenharmony_ci  HpConnect     connect;
826141cc406Sopenharmony_ci
827141cc406Sopenharmony_ci  assert(len < HP_SCSI_MAX_WRITE);
828141cc406Sopenharmony_ci  if (len == 0)
829141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci  this->bufp = this->buf;
832141cc406Sopenharmony_ci
833141cc406Sopenharmony_ci  DBG(16, "scsi_flush: writing %lu bytes:\n", (unsigned long) len);
834141cc406Sopenharmony_ci  DBGDUMP(16, data, len);
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci  *this->bufp++ = 0x0A;
837141cc406Sopenharmony_ci  *this->bufp++ = 0;
838141cc406Sopenharmony_ci  *this->bufp++ = len >> 16;
839141cc406Sopenharmony_ci  *this->bufp++ = len >> 8;
840141cc406Sopenharmony_ci  *this->bufp++ = len;
841141cc406Sopenharmony_ci  *this->bufp++ = 0;
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci  connect = sanei_hp_scsi_get_connect (this);
844141cc406Sopenharmony_ci  if (connect == HP_CONNECT_SCSI)
845141cc406Sopenharmony_ci    return sanei_scsi_cmd (this->fd, this->buf, HP_SCSI_CMD_LEN + len, 0, 0);
846141cc406Sopenharmony_ci  else
847141cc406Sopenharmony_ci    return hp_nonscsi_write (this, this->buf+HP_SCSI_CMD_LEN, len, connect);
848141cc406Sopenharmony_ci}
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_cistatic size_t
851141cc406Sopenharmony_cihp_scsi_room (HpScsi this)
852141cc406Sopenharmony_ci{
853141cc406Sopenharmony_ci  return this->buf + HP_SCSI_BUFSIZ - this->bufp;
854141cc406Sopenharmony_ci}
855141cc406Sopenharmony_ci
856141cc406Sopenharmony_cistatic SANE_Status
857141cc406Sopenharmony_cihp_scsi_need (HpScsi this, size_t need)
858141cc406Sopenharmony_ci{
859141cc406Sopenharmony_ci  assert(need < HP_SCSI_MAX_WRITE);
860141cc406Sopenharmony_ci
861141cc406Sopenharmony_ci  if (need > hp_scsi_room(this))
862141cc406Sopenharmony_ci      RETURN_IF_FAIL( hp_scsi_flush(this) );
863141cc406Sopenharmony_ci
864141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
865141cc406Sopenharmony_ci}
866141cc406Sopenharmony_ci
867141cc406Sopenharmony_cistatic SANE_Status
868141cc406Sopenharmony_cihp_scsi_write (HpScsi this, const void *data, size_t len)
869141cc406Sopenharmony_ci{
870141cc406Sopenharmony_ci  if ( len < HP_SCSI_MAX_WRITE )
871141cc406Sopenharmony_ci    {
872141cc406Sopenharmony_ci      RETURN_IF_FAIL( hp_scsi_need(this, len) );
873141cc406Sopenharmony_ci      memcpy(this->bufp, data, len);
874141cc406Sopenharmony_ci      this->bufp += len;
875141cc406Sopenharmony_ci    }
876141cc406Sopenharmony_ci  else
877141cc406Sopenharmony_ci    {size_t maxwrite = HP_SCSI_MAX_WRITE - 16;
878141cc406Sopenharmony_ci     const char *c_data = (const char *)data;
879141cc406Sopenharmony_ci
880141cc406Sopenharmony_ci      while ( len > 0 )
881141cc406Sopenharmony_ci        {
882141cc406Sopenharmony_ci          if ( maxwrite > len ) maxwrite = len;
883141cc406Sopenharmony_ci          RETURN_IF_FAIL( hp_scsi_write(this, c_data, maxwrite) );
884141cc406Sopenharmony_ci          c_data += maxwrite;
885141cc406Sopenharmony_ci          len -= maxwrite;
886141cc406Sopenharmony_ci        }
887141cc406Sopenharmony_ci    }
888141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
889141cc406Sopenharmony_ci}
890141cc406Sopenharmony_ci
891141cc406Sopenharmony_cistatic SANE_Status
892141cc406Sopenharmony_cihp_scsi_scl(HpScsi this, HpScl scl, int val)
893141cc406Sopenharmony_ci{
894141cc406Sopenharmony_ci  char	group	= tolower(SCL_GROUP_CHAR(scl));
895141cc406Sopenharmony_ci  char	param	= toupper(SCL_PARAM_CHAR(scl));
896141cc406Sopenharmony_ci  int	count;
897141cc406Sopenharmony_ci
898141cc406Sopenharmony_ci  assert(IS_SCL_CONTROL(scl) || IS_SCL_COMMAND(scl));
899141cc406Sopenharmony_ci  assert(isprint(group) && isprint(param));
900141cc406Sopenharmony_ci
901141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_need(this, 10) );
902141cc406Sopenharmony_ci
903141cc406Sopenharmony_ci  /* Don't try to optimize SCL-commands like using <ESC>*a1b0c5T */
904141cc406Sopenharmony_ci  /* Some scanners have problems with it (e.g. HP Photosmart Photoscanner */
905141cc406Sopenharmony_ci  /* with window position/extent, resolution) */
906141cc406Sopenharmony_ci  count = sprintf((char *)this->bufp, "\033*%c%d%c", group, val, param);
907141cc406Sopenharmony_ci  this->bufp += count;
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ci  assert(count > 0 && this->bufp < this->buf + HP_SCSI_BUFSIZ);
910141cc406Sopenharmony_ci
911141cc406Sopenharmony_ci  return hp_scsi_flush(this);
912141cc406Sopenharmony_ci}
913141cc406Sopenharmony_ci
914141cc406Sopenharmony_ci/* Read it bytewise */
915141cc406Sopenharmony_cistatic SANE_Status
916141cc406Sopenharmony_cihp_scsi_read_slow (HpScsi this, void * dest, size_t *len)
917141cc406Sopenharmony_ci{static hp_byte_t read_cmd[6] = { 0x08, 0, 0, 0, 0, 0 };
918141cc406Sopenharmony_ci size_t leftover = *len;
919141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD;
920141cc406Sopenharmony_ci unsigned char *start_dest = (unsigned char *)dest;
921141cc406Sopenharmony_ci unsigned char *next_dest = start_dest;
922141cc406Sopenharmony_ci
923141cc406Sopenharmony_ci DBG(16, "hp_scsi_read_slow: Start reading %d bytes bytewise\n", (int)*len);
924141cc406Sopenharmony_ci
925141cc406Sopenharmony_ci while (leftover > 0)  /* Until we got all the bytes */
926141cc406Sopenharmony_ci {size_t one = 1;
927141cc406Sopenharmony_ci
928141cc406Sopenharmony_ci   read_cmd[2] = 0;
929141cc406Sopenharmony_ci   read_cmd[3] = 0;
930141cc406Sopenharmony_ci   read_cmd[4] = 1;   /* Read one byte */
931141cc406Sopenharmony_ci
932141cc406Sopenharmony_ci   status = sanei_scsi_cmd (this->fd, read_cmd, sizeof(read_cmd),
933141cc406Sopenharmony_ci                            next_dest, &one);
934141cc406Sopenharmony_ci   if ((status != SANE_STATUS_GOOD) || (one != 1))
935141cc406Sopenharmony_ci   {
936141cc406Sopenharmony_ci     DBG(250,"hp_scsi_read_slow: Reading byte %d: status=%s, len=%d\n",
937141cc406Sopenharmony_ci         (int)(next_dest-start_dest), sane_strstatus(status), (int)one);
938141cc406Sopenharmony_ci   }
939141cc406Sopenharmony_ci
940141cc406Sopenharmony_ci   if (status != SANE_STATUS_GOOD) break;  /* Finish on error */
941141cc406Sopenharmony_ci
942141cc406Sopenharmony_ci   next_dest++;
943141cc406Sopenharmony_ci   leftover--;
944141cc406Sopenharmony_ci }
945141cc406Sopenharmony_ci
946141cc406Sopenharmony_ci *len = next_dest-start_dest; /* This is the number of bytes we got */
947141cc406Sopenharmony_ci
948141cc406Sopenharmony_ci DBG(16, "hp_scsi_read_slow: Got %d bytes\n", (int)*len);
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci if ((status != SANE_STATUS_GOOD) && (*len > 0))
951141cc406Sopenharmony_ci {
952141cc406Sopenharmony_ci   DBG(16, "We got some data. Ignore the error \"%s\"\n",
953141cc406Sopenharmony_ci       sane_strstatus(status));
954141cc406Sopenharmony_ci   status = SANE_STATUS_GOOD;
955141cc406Sopenharmony_ci }
956141cc406Sopenharmony_ci return status;
957141cc406Sopenharmony_ci}
958141cc406Sopenharmony_ci
959141cc406Sopenharmony_ci/* The OfficeJets tend to return inquiry responses containing array
960141cc406Sopenharmony_ci * data in two packets.  The added "isResponse" parameter tells
961141cc406Sopenharmony_ci * whether we should keep reading until we get
962141cc406Sopenharmony_ci * a well-formed response.  Naturally, this parameter would be zero
963141cc406Sopenharmony_ci * when reading scan data. */
964141cc406Sopenharmony_cistatic SANE_Status
965141cc406Sopenharmony_cihp_scsi_read (HpScsi this, void * dest, size_t *len, int isResponse)
966141cc406Sopenharmony_ci{
967141cc406Sopenharmony_ci  HpConnect connect;
968141cc406Sopenharmony_ci
969141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_flush(this) );
970141cc406Sopenharmony_ci
971141cc406Sopenharmony_ci  connect = sanei_hp_scsi_get_connect (this);
972141cc406Sopenharmony_ci  if (connect == HP_CONNECT_SCSI)
973141cc406Sopenharmony_ci  {int read_bytewise = 0;
974141cc406Sopenharmony_ci
975141cc406Sopenharmony_ci    if (*len <= 32)   /* Is it a candidate for reading bytewise ? */
976141cc406Sopenharmony_ci    {const HpDeviceInfo *info;
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_ci      info = sanei_hp_device_info_get (sanei_hp_scsi_devicename (this));
979141cc406Sopenharmony_ci      if ((info != NULL) && (info->config_is_up) && info->config.dumb_read)
980141cc406Sopenharmony_ci        read_bytewise = 1;
981141cc406Sopenharmony_ci    }
982141cc406Sopenharmony_ci
983141cc406Sopenharmony_ci    if ( ! read_bytewise )
984141cc406Sopenharmony_ci    {static hp_byte_t read_cmd[6] = { 0x08, 0, 0, 0, 0, 0 };
985141cc406Sopenharmony_ci      read_cmd[2] = *len >> 16;
986141cc406Sopenharmony_ci      read_cmd[3] = *len >> 8;
987141cc406Sopenharmony_ci      read_cmd[4] = *len;
988141cc406Sopenharmony_ci
989141cc406Sopenharmony_ci      RETURN_IF_FAIL( sanei_scsi_cmd (this->fd, read_cmd,
990141cc406Sopenharmony_ci                                      sizeof(read_cmd), dest, len) );
991141cc406Sopenharmony_ci    }
992141cc406Sopenharmony_ci    else
993141cc406Sopenharmony_ci    {
994141cc406Sopenharmony_ci      RETURN_IF_FAIL (hp_scsi_read_slow (this, dest, len));
995141cc406Sopenharmony_ci    }
996141cc406Sopenharmony_ci  }
997141cc406Sopenharmony_ci  else
998141cc406Sopenharmony_ci  {
999141cc406Sopenharmony_ci    RETURN_IF_FAIL( hp_nonscsi_read (this, dest, len, connect, isResponse) );
1000141cc406Sopenharmony_ci  }
1001141cc406Sopenharmony_ci  DBG(16, "scsi_read:  %lu bytes:\n", (unsigned long) *len);
1002141cc406Sopenharmony_ci  DBGDUMP(16, dest, *len);
1003141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1004141cc406Sopenharmony_ci}
1005141cc406Sopenharmony_ci
1006141cc406Sopenharmony_ci
1007141cc406Sopenharmony_cistatic int signal_caught = 0;
1008141cc406Sopenharmony_ci
1009141cc406Sopenharmony_cistatic void
1010141cc406Sopenharmony_cisignal_catcher (int sig)
1011141cc406Sopenharmony_ci{
1012141cc406Sopenharmony_ci  DBG(1,"signal_catcher(sig=%d): old signal_caught=%d\n",sig,signal_caught);
1013141cc406Sopenharmony_ci  if (!signal_caught)
1014141cc406Sopenharmony_ci      signal_caught = sig;
1015141cc406Sopenharmony_ci}
1016141cc406Sopenharmony_ci
1017141cc406Sopenharmony_cistatic void
1018141cc406Sopenharmony_cihp_data_map (register const unsigned char *map, register int count,
1019141cc406Sopenharmony_ci             register unsigned char *data)
1020141cc406Sopenharmony_ci{
1021141cc406Sopenharmony_ci  if (count <= 0) return;
1022141cc406Sopenharmony_ci  while (count--)
1023141cc406Sopenharmony_ci  {
1024141cc406Sopenharmony_ci    *data = map[*data];
1025141cc406Sopenharmony_ci    data++;
1026141cc406Sopenharmony_ci  }
1027141cc406Sopenharmony_ci}
1028141cc406Sopenharmony_ci
1029141cc406Sopenharmony_cistatic const unsigned char *
1030141cc406Sopenharmony_cihp_get_simulation_map (const char *devname, const HpDeviceInfo *info)
1031141cc406Sopenharmony_ci{
1032141cc406Sopenharmony_ci hp_bool_t     sim_gamma, sim_brightness, sim_contrast;
1033141cc406Sopenharmony_ci int           k, ind;
1034141cc406Sopenharmony_ci const unsigned char *map = NULL;
1035141cc406Sopenharmony_ci static unsigned char map8x8[256];
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci  sim_gamma = info->simulate.gamma_simulate;
1038141cc406Sopenharmony_ci  sim_brightness = sanei_hp_device_simulate_get (devname, SCL_BRIGHTNESS);
1039141cc406Sopenharmony_ci  sim_contrast = sanei_hp_device_simulate_get (devname, SCL_CONTRAST);
1040141cc406Sopenharmony_ci
1041141cc406Sopenharmony_ci  if ( sim_gamma )
1042141cc406Sopenharmony_ci  {
1043141cc406Sopenharmony_ci    map = &(info->simulate.gamma_map[0]);
1044141cc406Sopenharmony_ci  }
1045141cc406Sopenharmony_ci  else if ( sim_brightness && sim_contrast )
1046141cc406Sopenharmony_ci  {
1047141cc406Sopenharmony_ci    for (k = 0; k < 256; k++)
1048141cc406Sopenharmony_ci    {
1049141cc406Sopenharmony_ci      ind = info->simulate.contrast_map[k];
1050141cc406Sopenharmony_ci      map8x8[k] = info->simulate.brightness_map[ind];
1051141cc406Sopenharmony_ci    }
1052141cc406Sopenharmony_ci    map = &(map8x8[0]);
1053141cc406Sopenharmony_ci  }
1054141cc406Sopenharmony_ci  else if ( sim_brightness )
1055141cc406Sopenharmony_ci    map = &(info->simulate.brightness_map[0]);
1056141cc406Sopenharmony_ci  else if ( sim_contrast )
1057141cc406Sopenharmony_ci    map = &(info->simulate.contrast_map[0]);
1058141cc406Sopenharmony_ci
1059141cc406Sopenharmony_ci  return map;
1060141cc406Sopenharmony_ci}
1061141cc406Sopenharmony_ci
1062141cc406Sopenharmony_ci
1063141cc406Sopenharmony_ci/* Check the native byte order on the local machine */
1064141cc406Sopenharmony_cistatic hp_bool_t
1065141cc406Sopenharmony_ciis_lowbyte_first_byteorder (void)
1066141cc406Sopenharmony_ci
1067141cc406Sopenharmony_ci{unsigned short testvar = 1;
1068141cc406Sopenharmony_ci unsigned char *testptr = (unsigned char *)&testvar;
1069141cc406Sopenharmony_ci
1070141cc406Sopenharmony_ci if (sizeof (unsigned short) == 2)
1071141cc406Sopenharmony_ci   return (testptr[0] == 1);
1072141cc406Sopenharmony_ci else if (sizeof (unsigned short) == 4)
1073141cc406Sopenharmony_ci   return ((testptr[0] == 1) || (testptr[2] == 1));
1074141cc406Sopenharmony_ci else
1075141cc406Sopenharmony_ci   return (   (testptr[0] == 1) || (testptr[2] == 1)
1076141cc406Sopenharmony_ci           || (testptr[4] == 1) || (testptr[6] == 1));
1077141cc406Sopenharmony_ci}
1078141cc406Sopenharmony_ci
1079141cc406Sopenharmony_ci/* The SANE standard defines that 2-byte data must use the full 16 bit range.
1080141cc406Sopenharmony_ci * Byte order returned by the backend must be native byte order.
1081141cc406Sopenharmony_ci * Scaling to 16 bit and byte order is achieved by hp_scale_to_16bit.
1082141cc406Sopenharmony_ci * for >8 bits data, take the two data bytes and scale their content
1083141cc406Sopenharmony_ci * to the full 16 bit range, using
1084141cc406Sopenharmony_ci *     scaled = unscaled << (newlen - oldlen) +
1085141cc406Sopenharmony_ci *              unscaled >> (oldlen - (newlen - oldlen)),
1086141cc406Sopenharmony_ci * with newlen=16 and oldlen the original bit depth.
1087141cc406Sopenharmony_ci */
1088141cc406Sopenharmony_cistatic void
1089141cc406Sopenharmony_cihp_scale_to_16bit(int count, register unsigned char *data, int depth,
1090141cc406Sopenharmony_ci                  hp_bool_t invert)
1091141cc406Sopenharmony_ci{
1092141cc406Sopenharmony_ci    register unsigned int tmp;
1093141cc406Sopenharmony_ci    register unsigned int mask;
1094141cc406Sopenharmony_ci    register hp_bool_t lowbyte_first = is_lowbyte_first_byteorder ();
1095141cc406Sopenharmony_ci    unsigned int shift1 = 16 - depth;
1096141cc406Sopenharmony_ci    unsigned int shift2 = 2*depth - 16;
1097141cc406Sopenharmony_ci    int k;
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci    if (count <= 0) return;
1100141cc406Sopenharmony_ci
1101141cc406Sopenharmony_ci    mask = 1;
1102141cc406Sopenharmony_ci    for (k = 1; k < depth; k++) mask |= (1 << k);
1103141cc406Sopenharmony_ci
1104141cc406Sopenharmony_ci    if (lowbyte_first)
1105141cc406Sopenharmony_ci    {
1106141cc406Sopenharmony_ci      while (count--) {
1107141cc406Sopenharmony_ci         tmp = ((((unsigned int)data[0])<<8) | ((unsigned int)data[1])) & mask;
1108141cc406Sopenharmony_ci         tmp = (tmp << shift1) + (tmp >> shift2);
1109141cc406Sopenharmony_ci         if (invert) tmp = ~tmp;
1110141cc406Sopenharmony_ci         *data++ = tmp & 255U;
1111141cc406Sopenharmony_ci         *data++ = (tmp >> 8) & 255U;
1112141cc406Sopenharmony_ci      }
1113141cc406Sopenharmony_ci    }
1114141cc406Sopenharmony_ci    else  /* Highbyte first */
1115141cc406Sopenharmony_ci    {
1116141cc406Sopenharmony_ci      while (count--) {
1117141cc406Sopenharmony_ci         tmp = ((((unsigned int)data[0])<<8) | ((unsigned int)data[1])) & mask;
1118141cc406Sopenharmony_ci         tmp = (tmp << shift1) + (tmp >> shift2);
1119141cc406Sopenharmony_ci         if (invert) tmp = ~tmp;
1120141cc406Sopenharmony_ci         *data++ = (tmp >> 8) & 255U;
1121141cc406Sopenharmony_ci         *data++ = tmp & 255U;
1122141cc406Sopenharmony_ci      }
1123141cc406Sopenharmony_ci    }
1124141cc406Sopenharmony_ci}
1125141cc406Sopenharmony_ci
1126141cc406Sopenharmony_ci
1127141cc406Sopenharmony_cistatic void
1128141cc406Sopenharmony_cihp_scale_to_8bit(int count, register unsigned char *data, int depth,
1129141cc406Sopenharmony_ci                 hp_bool_t invert)
1130141cc406Sopenharmony_ci{
1131141cc406Sopenharmony_ci    register unsigned int tmp, mask;
1132141cc406Sopenharmony_ci    register hp_bool_t lowbyte_first = is_lowbyte_first_byteorder ();
1133141cc406Sopenharmony_ci    unsigned int shift1 = depth-8;
1134141cc406Sopenharmony_ci    int k;
1135141cc406Sopenharmony_ci    unsigned char *dataout = data;
1136141cc406Sopenharmony_ci
1137141cc406Sopenharmony_ci    if ((count <= 0) || (shift1 <= 0)) return;
1138141cc406Sopenharmony_ci
1139141cc406Sopenharmony_ci    mask = 1;
1140141cc406Sopenharmony_ci    for (k = 1; k < depth; k++) mask |= (1 << k);
1141141cc406Sopenharmony_ci
1142141cc406Sopenharmony_ci    if (lowbyte_first)
1143141cc406Sopenharmony_ci    {
1144141cc406Sopenharmony_ci      while (count--) {
1145141cc406Sopenharmony_ci         tmp = ((((unsigned int)data[0])<<8) | ((unsigned int)data[1])) & mask;
1146141cc406Sopenharmony_ci         tmp >>= shift1;
1147141cc406Sopenharmony_ci         if (invert) tmp = ~tmp;
1148141cc406Sopenharmony_ci         *(dataout++) = tmp & 255U;
1149141cc406Sopenharmony_ci         data += 2;
1150141cc406Sopenharmony_ci      }
1151141cc406Sopenharmony_ci    }
1152141cc406Sopenharmony_ci    else  /* Highbyte first */
1153141cc406Sopenharmony_ci    {
1154141cc406Sopenharmony_ci      while (count--) {
1155141cc406Sopenharmony_ci         tmp = ((((unsigned int)data[0])<<8) | ((unsigned int)data[1])) & mask;
1156141cc406Sopenharmony_ci         tmp >>= shift1;
1157141cc406Sopenharmony_ci         if (invert) tmp = ~tmp;
1158141cc406Sopenharmony_ci         *(dataout++) = tmp & 255U;
1159141cc406Sopenharmony_ci         data += 2;
1160141cc406Sopenharmony_ci      }
1161141cc406Sopenharmony_ci    }
1162141cc406Sopenharmony_ci}
1163141cc406Sopenharmony_ci
1164141cc406Sopenharmony_cistatic void
1165141cc406Sopenharmony_cihp_soft_invert(int count, register unsigned char *data) {
1166141cc406Sopenharmony_ci	while (count>0) {
1167141cc406Sopenharmony_ci		*data = ~(*data);
1168141cc406Sopenharmony_ci		data++;
1169141cc406Sopenharmony_ci		count--;
1170141cc406Sopenharmony_ci	}
1171141cc406Sopenharmony_ci}
1172141cc406Sopenharmony_ci
1173141cc406Sopenharmony_cistatic PROCDATA_HANDLE *
1174141cc406Sopenharmony_ciprocess_data_init (HpProcessData *procdata, const unsigned char *map,
1175141cc406Sopenharmony_ci                   int outfd, hp_bool_t use_imgbuf)
1176141cc406Sopenharmony_ci
1177141cc406Sopenharmony_ci{PROCDATA_HANDLE *ph = sanei_hp_alloc (sizeof (PROCDATA_HANDLE));
1178141cc406Sopenharmony_ci int tsz;
1179141cc406Sopenharmony_ci
1180141cc406Sopenharmony_ci if (ph == NULL) return NULL;
1181141cc406Sopenharmony_ci
1182141cc406Sopenharmony_ci memset (ph, 0, sizeof (*ph));
1183141cc406Sopenharmony_ci memcpy (&(ph->procdata), procdata, sizeof (*procdata));
1184141cc406Sopenharmony_ci procdata = &(ph->procdata);
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci tsz = (HP_TMP_BUF_SIZE <= 0) ? procdata->bytes_per_line : HP_TMP_BUF_SIZE;
1187141cc406Sopenharmony_ci ph->tmp_buf = sanei_hp_alloc (tsz);
1188141cc406Sopenharmony_ci if (ph->tmp_buf == NULL)
1189141cc406Sopenharmony_ci {
1190141cc406Sopenharmony_ci   sanei_hp_free (ph);
1191141cc406Sopenharmony_ci   return NULL;
1192141cc406Sopenharmony_ci }
1193141cc406Sopenharmony_ci ph->tmp_buf_size = tsz;
1194141cc406Sopenharmony_ci ph->tmp_buf_len = 0;
1195141cc406Sopenharmony_ci
1196141cc406Sopenharmony_ci ph->map = map;
1197141cc406Sopenharmony_ci ph->outfd = outfd;
1198141cc406Sopenharmony_ci
1199141cc406Sopenharmony_ci if ( procdata->mirror_vertical || use_imgbuf)
1200141cc406Sopenharmony_ci {
1201141cc406Sopenharmony_ci   tsz = procdata->lines*procdata->bytes_per_line;
1202141cc406Sopenharmony_ci   if (procdata->out8) tsz /= 2;
1203141cc406Sopenharmony_ci   ph->image_ptr = ph->image_buf = sanei_hp_alloc (tsz);
1204141cc406Sopenharmony_ci   if ( !ph->image_buf )
1205141cc406Sopenharmony_ci   {
1206141cc406Sopenharmony_ci     procdata->mirror_vertical = 0;
1207141cc406Sopenharmony_ci     ph->image_buf_size = 0;
1208141cc406Sopenharmony_ci     DBG(1, "process_scanline_init: Not enough memory to mirror image\n");
1209141cc406Sopenharmony_ci   }
1210141cc406Sopenharmony_ci   else
1211141cc406Sopenharmony_ci     ph->image_buf_size = tsz;
1212141cc406Sopenharmony_ci }
1213141cc406Sopenharmony_ci
1214141cc406Sopenharmony_ci ph->wr_ptr = ph->wr_buf;
1215141cc406Sopenharmony_ci ph->wr_buf_size = ph->wr_left = sizeof (ph->wr_buf);
1216141cc406Sopenharmony_ci
1217141cc406Sopenharmony_ci return ph;
1218141cc406Sopenharmony_ci}
1219141cc406Sopenharmony_ci
1220141cc406Sopenharmony_ci
1221141cc406Sopenharmony_cistatic SANE_Status
1222141cc406Sopenharmony_ciprocess_data_write (PROCDATA_HANDLE *ph, unsigned char *data, int nbytes)
1223141cc406Sopenharmony_ci
1224141cc406Sopenharmony_ci{int ncopy;
1225141cc406Sopenharmony_ci
1226141cc406Sopenharmony_ci if (ph == NULL) return SANE_STATUS_INVAL;
1227141cc406Sopenharmony_ci
1228141cc406Sopenharmony_ci /* Fill up write buffer */
1229141cc406Sopenharmony_ci ncopy = ph->wr_left;
1230141cc406Sopenharmony_ci if (ncopy > nbytes) ncopy = nbytes;
1231141cc406Sopenharmony_ci
1232141cc406Sopenharmony_ci memcpy (ph->wr_ptr, data, ncopy);
1233141cc406Sopenharmony_ci ph->wr_ptr += ncopy;
1234141cc406Sopenharmony_ci ph->wr_left -= ncopy;
1235141cc406Sopenharmony_ci data += ncopy;
1236141cc406Sopenharmony_ci nbytes -= ncopy;
1237141cc406Sopenharmony_ci
1238141cc406Sopenharmony_ci if ( ph->wr_left > 0 )  /* Did not fill up the write buffer ? Finished */
1239141cc406Sopenharmony_ci   return SANE_STATUS_GOOD;
1240141cc406Sopenharmony_ci
1241141cc406Sopenharmony_ci DBG(12, "process_data_write: write %d bytes\n", ph->wr_buf_size);
1242141cc406Sopenharmony_ci /* Don't write data if we got a signal in the meantime */
1243141cc406Sopenharmony_ci if (   signal_caught
1244141cc406Sopenharmony_ci     || (write (ph->outfd, ph->wr_buf, ph->wr_buf_size) != ph->wr_buf_size))
1245141cc406Sopenharmony_ci {
1246141cc406Sopenharmony_ci   DBG(1, "process_data_write: write failed: %s\n",
1247141cc406Sopenharmony_ci       signal_caught ? "signal caught" : strerror(errno));
1248141cc406Sopenharmony_ci   return SANE_STATUS_IO_ERROR;
1249141cc406Sopenharmony_ci }
1250141cc406Sopenharmony_ci ph->wr_ptr = ph->wr_buf;
1251141cc406Sopenharmony_ci ph->wr_left = ph->wr_buf_size;
1252141cc406Sopenharmony_ci
1253141cc406Sopenharmony_ci /* For large amount of data write it from data-buffer */
1254141cc406Sopenharmony_ci while ( nbytes > ph->wr_buf_size )
1255141cc406Sopenharmony_ci {
1256141cc406Sopenharmony_ci   if (   signal_caught
1257141cc406Sopenharmony_ci       || (write (ph->outfd, data, ph->wr_buf_size) != ph->wr_buf_size))
1258141cc406Sopenharmony_ci   {
1259141cc406Sopenharmony_ci     DBG(1, "process_data_write: write failed: %s\n",
1260141cc406Sopenharmony_ci         signal_caught ? "signal caught" : strerror(errno));
1261141cc406Sopenharmony_ci     return SANE_STATUS_IO_ERROR;
1262141cc406Sopenharmony_ci   }
1263141cc406Sopenharmony_ci   nbytes -= ph->wr_buf_size;
1264141cc406Sopenharmony_ci   data += ph->wr_buf_size;
1265141cc406Sopenharmony_ci }
1266141cc406Sopenharmony_ci
1267141cc406Sopenharmony_ci if ( nbytes > 0 ) /* Something left ? Save it to (empty) write buffer */
1268141cc406Sopenharmony_ci {
1269141cc406Sopenharmony_ci   memcpy (ph->wr_ptr, data, nbytes);
1270141cc406Sopenharmony_ci   ph->wr_ptr += nbytes;
1271141cc406Sopenharmony_ci   ph->wr_left -= nbytes;
1272141cc406Sopenharmony_ci }
1273141cc406Sopenharmony_ci return SANE_STATUS_GOOD;
1274141cc406Sopenharmony_ci}
1275141cc406Sopenharmony_ci
1276141cc406Sopenharmony_cistatic SANE_Status
1277141cc406Sopenharmony_ciprocess_scanline (PROCDATA_HANDLE *ph, unsigned char *linebuf,
1278141cc406Sopenharmony_ci                  int bytes_per_line)
1279141cc406Sopenharmony_ci
1280141cc406Sopenharmony_ci{int out_bytes_per_line = bytes_per_line;
1281141cc406Sopenharmony_ci HpProcessData *procdata;
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci if (ph == NULL) return SANE_STATUS_INVAL;
1284141cc406Sopenharmony_ci procdata = &(ph->procdata);
1285141cc406Sopenharmony_ci
1286141cc406Sopenharmony_ci if ( ph->map )
1287141cc406Sopenharmony_ci   hp_data_map (ph->map, bytes_per_line, linebuf);
1288141cc406Sopenharmony_ci
1289141cc406Sopenharmony_ci if (procdata->bits_per_channel > 8)
1290141cc406Sopenharmony_ci {
1291141cc406Sopenharmony_ci   if (procdata->out8)
1292141cc406Sopenharmony_ci   {
1293141cc406Sopenharmony_ci     hp_scale_to_8bit( bytes_per_line/2, linebuf,
1294141cc406Sopenharmony_ci                       procdata->bits_per_channel,
1295141cc406Sopenharmony_ci                       procdata->invert);
1296141cc406Sopenharmony_ci     out_bytes_per_line /= 2;
1297141cc406Sopenharmony_ci   }
1298141cc406Sopenharmony_ci   else
1299141cc406Sopenharmony_ci   {
1300141cc406Sopenharmony_ci     hp_scale_to_16bit( bytes_per_line/2, linebuf,
1301141cc406Sopenharmony_ci                        procdata->bits_per_channel,
1302141cc406Sopenharmony_ci                        procdata->invert);
1303141cc406Sopenharmony_ci   }
1304141cc406Sopenharmony_ci } else if (procdata->invert) {
1305141cc406Sopenharmony_ci   hp_soft_invert(bytes_per_line,linebuf);
1306141cc406Sopenharmony_ci }
1307141cc406Sopenharmony_ci
1308141cc406Sopenharmony_ci if ( ph->image_buf )
1309141cc406Sopenharmony_ci {
1310141cc406Sopenharmony_ci   DBG(5, "process_scanline: save in memory\n");
1311141cc406Sopenharmony_ci
1312141cc406Sopenharmony_ci   if (    ph->image_ptr+out_bytes_per_line-1
1313141cc406Sopenharmony_ci        <= ph->image_buf+ph->image_buf_size-1 )
1314141cc406Sopenharmony_ci   {
1315141cc406Sopenharmony_ci     memcpy(ph->image_ptr, linebuf, out_bytes_per_line);
1316141cc406Sopenharmony_ci     ph->image_ptr += out_bytes_per_line;
1317141cc406Sopenharmony_ci   }
1318141cc406Sopenharmony_ci   else
1319141cc406Sopenharmony_ci   {
1320141cc406Sopenharmony_ci     DBG(1, "process_scanline: would exceed image buffer\n");
1321141cc406Sopenharmony_ci   }
1322141cc406Sopenharmony_ci }
1323141cc406Sopenharmony_ci else /* Save scanlines in a bigger buffer. */
1324141cc406Sopenharmony_ci {    /* Otherwise we will get performance problems */
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci   RETURN_IF_FAIL ( process_data_write (ph, linebuf, out_bytes_per_line) );
1327141cc406Sopenharmony_ci }
1328141cc406Sopenharmony_ci return SANE_STATUS_GOOD;
1329141cc406Sopenharmony_ci}
1330141cc406Sopenharmony_ci
1331141cc406Sopenharmony_ci
1332141cc406Sopenharmony_cistatic SANE_Status
1333141cc406Sopenharmony_ciprocess_data (PROCDATA_HANDLE *ph, unsigned char *read_ptr, int nread)
1334141cc406Sopenharmony_ci
1335141cc406Sopenharmony_ci{int bytes_left;
1336141cc406Sopenharmony_ci
1337141cc406Sopenharmony_ci if (nread <= 0) return SANE_STATUS_GOOD;
1338141cc406Sopenharmony_ci
1339141cc406Sopenharmony_ci if (ph == NULL) return SANE_STATUS_INVAL;
1340141cc406Sopenharmony_ci
1341141cc406Sopenharmony_ci if ( ph->tmp_buf_len > 0 )  /* Something left ? */
1342141cc406Sopenharmony_ci {
1343141cc406Sopenharmony_ci   bytes_left = ph->tmp_buf_size - ph->tmp_buf_len;
1344141cc406Sopenharmony_ci   if (nread < bytes_left)  /* All to buffer ? */
1345141cc406Sopenharmony_ci   {
1346141cc406Sopenharmony_ci     memcpy (ph->tmp_buf+ph->tmp_buf_len, read_ptr, nread);
1347141cc406Sopenharmony_ci     ph->tmp_buf_len += nread;
1348141cc406Sopenharmony_ci     return SANE_STATUS_GOOD;
1349141cc406Sopenharmony_ci   }
1350141cc406Sopenharmony_ci   memcpy (ph->tmp_buf+ph->tmp_buf_len, read_ptr, bytes_left);
1351141cc406Sopenharmony_ci   read_ptr += bytes_left;
1352141cc406Sopenharmony_ci   nread -= bytes_left;
1353141cc406Sopenharmony_ci   RETURN_IF_FAIL ( process_scanline (ph, ph->tmp_buf, ph->tmp_buf_size) );
1354141cc406Sopenharmony_ci   ph->tmp_buf_len = 0;
1355141cc406Sopenharmony_ci }
1356141cc406Sopenharmony_ci while (nread > 0)
1357141cc406Sopenharmony_ci {
1358141cc406Sopenharmony_ci   if (nread >= ph->tmp_buf_size)
1359141cc406Sopenharmony_ci   {
1360141cc406Sopenharmony_ci     RETURN_IF_FAIL ( process_scanline (ph, read_ptr, ph->tmp_buf_size) );
1361141cc406Sopenharmony_ci     read_ptr += ph->tmp_buf_size;
1362141cc406Sopenharmony_ci     nread -= ph->tmp_buf_size;
1363141cc406Sopenharmony_ci   }
1364141cc406Sopenharmony_ci   else
1365141cc406Sopenharmony_ci   {
1366141cc406Sopenharmony_ci     memcpy (ph->tmp_buf, read_ptr, nread);
1367141cc406Sopenharmony_ci     ph->tmp_buf_len = nread;
1368141cc406Sopenharmony_ci     nread = 0;
1369141cc406Sopenharmony_ci   }
1370141cc406Sopenharmony_ci }
1371141cc406Sopenharmony_ci return SANE_STATUS_GOOD;
1372141cc406Sopenharmony_ci}
1373141cc406Sopenharmony_ci
1374141cc406Sopenharmony_ci
1375141cc406Sopenharmony_cistatic SANE_Status
1376141cc406Sopenharmony_ciprocess_data_flush (PROCDATA_HANDLE *ph)
1377141cc406Sopenharmony_ci
1378141cc406Sopenharmony_ci{SANE_Status status = SANE_STATUS_GOOD;
1379141cc406Sopenharmony_ci HpProcessData *procdata;
1380141cc406Sopenharmony_ci unsigned char *image_data;
1381141cc406Sopenharmony_ci size_t image_len;
1382141cc406Sopenharmony_ci int num_lines, bytes_per_line;
1383141cc406Sopenharmony_ci int nbytes;
1384141cc406Sopenharmony_ci
1385141cc406Sopenharmony_ci if (ph == NULL) return SANE_STATUS_INVAL;
1386141cc406Sopenharmony_ci
1387141cc406Sopenharmony_ci if ( ph->tmp_buf_len > 0 )
1388141cc406Sopenharmony_ci   process_scanline (ph, ph->tmp_buf, ph->tmp_buf_len);
1389141cc406Sopenharmony_ci
1390141cc406Sopenharmony_ci if ( ph->wr_left != ph->wr_buf_size ) /* Something in write buffer ? */
1391141cc406Sopenharmony_ci {
1392141cc406Sopenharmony_ci   nbytes = ph->wr_buf_size - ph->wr_left;
1393141cc406Sopenharmony_ci   if ( signal_caught || (write (ph->outfd, ph->wr_buf, nbytes) != nbytes))
1394141cc406Sopenharmony_ci   {
1395141cc406Sopenharmony_ci     DBG(1, "process_data_flush: write failed: %s\n",
1396141cc406Sopenharmony_ci         signal_caught ? "signal caught" : strerror(errno));
1397141cc406Sopenharmony_ci     return SANE_STATUS_IO_ERROR;
1398141cc406Sopenharmony_ci   }
1399141cc406Sopenharmony_ci   ph->wr_ptr = ph->wr_buf;
1400141cc406Sopenharmony_ci   ph->wr_left = ph->wr_buf_size;
1401141cc406Sopenharmony_ci }
1402141cc406Sopenharmony_ci
1403141cc406Sopenharmony_ci procdata = &(ph->procdata);
1404141cc406Sopenharmony_ci if ( ph->image_buf )
1405141cc406Sopenharmony_ci {
1406141cc406Sopenharmony_ci   bytes_per_line = procdata->bytes_per_line;
1407141cc406Sopenharmony_ci   if (procdata->out8) bytes_per_line /= 2;
1408141cc406Sopenharmony_ci   image_len = (size_t) (ph->image_ptr - ph->image_buf);
1409141cc406Sopenharmony_ci   num_lines = ((int)(image_len + bytes_per_line-1)) / bytes_per_line;
1410141cc406Sopenharmony_ci
1411141cc406Sopenharmony_ci   DBG(3, "process_data_finish: write %d bytes from memory...\n",
1412141cc406Sopenharmony_ci       (int)image_len);
1413141cc406Sopenharmony_ci
1414141cc406Sopenharmony_ci   if ( procdata->mirror_vertical )
1415141cc406Sopenharmony_ci   {
1416141cc406Sopenharmony_ci     image_data = ph->image_buf + (num_lines-1) * bytes_per_line;
1417141cc406Sopenharmony_ci     while (num_lines > 0 )
1418141cc406Sopenharmony_ci     {
1419141cc406Sopenharmony_ci       if (   signal_caught
1420141cc406Sopenharmony_ci           || (write(ph->outfd, image_data, bytes_per_line) != bytes_per_line))
1421141cc406Sopenharmony_ci       {
1422141cc406Sopenharmony_ci         DBG(1,"process_data_finish: write from memory failed: %s\n",
1423141cc406Sopenharmony_ci             signal_caught ? "signal caught" : strerror(errno));
1424141cc406Sopenharmony_ci         status = SANE_STATUS_IO_ERROR;
1425141cc406Sopenharmony_ci         break;
1426141cc406Sopenharmony_ci       }
1427141cc406Sopenharmony_ci       num_lines--;
1428141cc406Sopenharmony_ci       image_data -= bytes_per_line;
1429141cc406Sopenharmony_ci     }
1430141cc406Sopenharmony_ci   }
1431141cc406Sopenharmony_ci   else
1432141cc406Sopenharmony_ci   {
1433141cc406Sopenharmony_ci     image_data = ph->image_buf;
1434141cc406Sopenharmony_ci     while (num_lines > 0 )
1435141cc406Sopenharmony_ci     {
1436141cc406Sopenharmony_ci       if (   signal_caught
1437141cc406Sopenharmony_ci           || (write(ph->outfd, image_data, bytes_per_line) != bytes_per_line))
1438141cc406Sopenharmony_ci       {
1439141cc406Sopenharmony_ci         DBG(1,"process_data_finish: write from memory failed: %s\n",
1440141cc406Sopenharmony_ci             signal_caught ? "signal caught" : strerror(errno));
1441141cc406Sopenharmony_ci         status = SANE_STATUS_IO_ERROR;
1442141cc406Sopenharmony_ci         break;
1443141cc406Sopenharmony_ci       }
1444141cc406Sopenharmony_ci       num_lines--;
1445141cc406Sopenharmony_ci       image_data += bytes_per_line;
1446141cc406Sopenharmony_ci     }
1447141cc406Sopenharmony_ci   }
1448141cc406Sopenharmony_ci }
1449141cc406Sopenharmony_ci return status;
1450141cc406Sopenharmony_ci}
1451141cc406Sopenharmony_ci
1452141cc406Sopenharmony_ci
1453141cc406Sopenharmony_cistatic void
1454141cc406Sopenharmony_ciprocess_data_finish (PROCDATA_HANDLE *ph)
1455141cc406Sopenharmony_ci
1456141cc406Sopenharmony_ci{
1457141cc406Sopenharmony_ci DBG(12, "process_data_finish called\n");
1458141cc406Sopenharmony_ci
1459141cc406Sopenharmony_ci if (ph == NULL) return;
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci if (ph->image_buf != NULL) sanei_hp_free (ph->image_buf);
1462141cc406Sopenharmony_ci
1463141cc406Sopenharmony_ci sanei_hp_free (ph->tmp_buf);
1464141cc406Sopenharmony_ci sanei_hp_free (ph);
1465141cc406Sopenharmony_ci}
1466141cc406Sopenharmony_ci
1467141cc406Sopenharmony_ci
1468141cc406Sopenharmony_ciSANE_Status
1469141cc406Sopenharmony_cisanei_hp_scsi_pipeout (HpScsi this, int outfd, HpProcessData *procdata)
1470141cc406Sopenharmony_ci{
1471141cc406Sopenharmony_ci  /* We will catch these signals, and rethrow them after cleaning up,
1472141cc406Sopenharmony_ci   * anything not in this list, we will ignore. */
1473141cc406Sopenharmony_ci  static int kill_sig[] = {
1474141cc406Sopenharmony_ci      SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGPIPE, SIGALRM, SIGTERM,
1475141cc406Sopenharmony_ci      SIGUSR1, SIGUSR2, SIGBUS,
1476141cc406Sopenharmony_ci#ifdef SIGSTKFLT
1477141cc406Sopenharmony_ci      SIGSTKFLT,
1478141cc406Sopenharmony_ci#endif
1479141cc406Sopenharmony_ci#ifdef SIGIO
1480141cc406Sopenharmony_ci      SIGIO,
1481141cc406Sopenharmony_ci#else
1482141cc406Sopenharmony_ci# ifdef SIGPOLL
1483141cc406Sopenharmony_ci      SIGPOLL,
1484141cc406Sopenharmony_ci# endif
1485141cc406Sopenharmony_ci#endif
1486141cc406Sopenharmony_ci#ifdef SIGXCPU
1487141cc406Sopenharmony_ci      SIGXCPU,
1488141cc406Sopenharmony_ci#endif
1489141cc406Sopenharmony_ci#ifdef SIGXFSZ
1490141cc406Sopenharmony_ci      SIGXFSZ,
1491141cc406Sopenharmony_ci#endif
1492141cc406Sopenharmony_ci#ifdef SIGVTALRM
1493141cc406Sopenharmony_ci      SIGVTALRM,
1494141cc406Sopenharmony_ci#endif
1495141cc406Sopenharmony_ci#ifdef SIGPWR
1496141cc406Sopenharmony_ci      SIGPWR,
1497141cc406Sopenharmony_ci#endif
1498141cc406Sopenharmony_ci  };
1499141cc406Sopenharmony_ci#define HP_NSIGS (sizeof(kill_sig)/sizeof(kill_sig[0]))
1500141cc406Sopenharmony_ci  struct SIGACTION old_handler[HP_NSIGS];
1501141cc406Sopenharmony_ci  struct SIGACTION sa;
1502141cc406Sopenharmony_ci  sigset_t	old_set, sig_set;
1503141cc406Sopenharmony_ci  int		i;
1504141cc406Sopenharmony_ci  int           bits_per_channel = procdata->bits_per_channel;
1505141cc406Sopenharmony_ci
1506141cc406Sopenharmony_ci#define HP_PIPEBUF	32768
1507141cc406Sopenharmony_ci  SANE_Status	status	= SANE_STATUS_GOOD;
1508141cc406Sopenharmony_ci  struct {
1509141cc406Sopenharmony_ci      size_t	len;
1510141cc406Sopenharmony_ci      void *	id;
1511141cc406Sopenharmony_ci      hp_byte_t	cmd[6];
1512141cc406Sopenharmony_ci      hp_byte_t	data[HP_PIPEBUF];
1513141cc406Sopenharmony_ci  } 	buf[2], *req = NULL;
1514141cc406Sopenharmony_ci
1515141cc406Sopenharmony_ci  int		reqs_completed = 0;
1516141cc406Sopenharmony_ci  int		reqs_issued = 0;
1517141cc406Sopenharmony_ci  char          *image_buf = 0;
1518141cc406Sopenharmony_ci  char          *read_buf = 0;
1519141cc406Sopenharmony_ci  const HpDeviceInfo *info;
1520141cc406Sopenharmony_ci  const char    *devname = sanei_hp_scsi_devicename (this);
1521141cc406Sopenharmony_ci  int           enable_requests = 1;
1522141cc406Sopenharmony_ci  int           enable_image_buffering = 0;
1523141cc406Sopenharmony_ci  const unsigned char *map = NULL;
1524141cc406Sopenharmony_ci  HpConnect     connect;
1525141cc406Sopenharmony_ci  PROCDATA_HANDLE *ph = NULL;
1526141cc406Sopenharmony_ci  size_t count = procdata->lines * procdata->bytes_per_line;
1527141cc406Sopenharmony_ci
1528141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_flush(this) );
1529141cc406Sopenharmony_ci
1530141cc406Sopenharmony_ci  connect = sanei_hp_get_connect (devname);
1531141cc406Sopenharmony_ci  info = sanei_hp_device_info_get (devname);
1532141cc406Sopenharmony_ci
1533141cc406Sopenharmony_ci  assert (info);
1534141cc406Sopenharmony_ci
1535141cc406Sopenharmony_ci  if ( info->config_is_up )
1536141cc406Sopenharmony_ci  {
1537141cc406Sopenharmony_ci    enable_requests = info->config.use_scsi_request;
1538141cc406Sopenharmony_ci    enable_image_buffering = info->config.use_image_buffering;
1539141cc406Sopenharmony_ci  }
1540141cc406Sopenharmony_ci  else
1541141cc406Sopenharmony_ci  {
1542141cc406Sopenharmony_ci    enable_requests = 0;
1543141cc406Sopenharmony_ci  }
1544141cc406Sopenharmony_ci
1545141cc406Sopenharmony_ci  if (connect != HP_CONNECT_SCSI)
1546141cc406Sopenharmony_ci    enable_requests = 0;
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_ci  /* Currently we can only simulate 8 bits mapping */
1549141cc406Sopenharmony_ci  if (bits_per_channel == 8)
1550141cc406Sopenharmony_ci    map = hp_get_simulation_map (devname, info);
1551141cc406Sopenharmony_ci
1552141cc406Sopenharmony_ci  sigfillset(&sig_set);
1553141cc406Sopenharmony_ci  sigprocmask(SIG_BLOCK, &sig_set, &old_set);
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci  memset(&sa, 0, sizeof(sa));
1556141cc406Sopenharmony_ci  sa.sa_handler = signal_catcher;
1557141cc406Sopenharmony_ci  sigfillset(&sa.sa_mask);
1558141cc406Sopenharmony_ci
1559141cc406Sopenharmony_ci  sigemptyset(&sig_set);
1560141cc406Sopenharmony_ci  for (i = 0; i < (int)(HP_NSIGS); i++)
1561141cc406Sopenharmony_ci    {
1562141cc406Sopenharmony_ci      sigaction(kill_sig[i], &sa, &old_handler[i]);
1563141cc406Sopenharmony_ci      sigaddset(&sig_set, kill_sig[i]);
1564141cc406Sopenharmony_ci    }
1565141cc406Sopenharmony_ci  signal_caught = 0;
1566141cc406Sopenharmony_ci  sigprocmask(SIG_UNBLOCK, &sig_set, 0);
1567141cc406Sopenharmony_ci
1568141cc406Sopenharmony_ci  /* Wait for front button push ? */
1569141cc406Sopenharmony_ci  if ( procdata->startscan )
1570141cc406Sopenharmony_ci  {
1571141cc406Sopenharmony_ci    for (;;)
1572141cc406Sopenharmony_ci    {int val = 0;
1573141cc406Sopenharmony_ci
1574141cc406Sopenharmony_ci       if (signal_caught) goto quit;
1575141cc406Sopenharmony_ci       sanei_hp_scl_inquire (this, SCL_FRONT_BUTTON, &val, 0, 0);
1576141cc406Sopenharmony_ci       if (val) break;
1577141cc406Sopenharmony_ci       usleep ((unsigned long)333*1000); /* Wait 1/3 second */
1578141cc406Sopenharmony_ci    }
1579141cc406Sopenharmony_ci    status = sanei_hp_scl_startScan (this, procdata->startscan);
1580141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD )
1581141cc406Sopenharmony_ci    {
1582141cc406Sopenharmony_ci      DBG(1, "do_read: Error starting scan in reader process\n");
1583141cc406Sopenharmony_ci      goto quit;
1584141cc406Sopenharmony_ci    }
1585141cc406Sopenharmony_ci  }
1586141cc406Sopenharmony_ci  ph = process_data_init (procdata, map, outfd, enable_image_buffering);
1587141cc406Sopenharmony_ci
1588141cc406Sopenharmony_ci  if ( ph == NULL )
1589141cc406Sopenharmony_ci  {
1590141cc406Sopenharmony_ci    DBG(1, "do_read: Error with process_data_init()\n");
1591141cc406Sopenharmony_ci    goto quit;
1592141cc406Sopenharmony_ci  }
1593141cc406Sopenharmony_ci
1594141cc406Sopenharmony_ci  DBG(1, "do_read: Start reading data from scanner\n");
1595141cc406Sopenharmony_ci
1596141cc406Sopenharmony_ci  if (enable_requests)   /* Issue SCSI-requests ? */
1597141cc406Sopenharmony_ci  {
1598141cc406Sopenharmony_ci    while (count > 0 || reqs_completed < reqs_issued)
1599141cc406Sopenharmony_ci    {
1600141cc406Sopenharmony_ci      while (count > 0 && reqs_issued < reqs_completed + 2)
1601141cc406Sopenharmony_ci	{
1602141cc406Sopenharmony_ci	  req = buf + (reqs_issued++ % 2);
1603141cc406Sopenharmony_ci
1604141cc406Sopenharmony_ci	  req->len = HP_PIPEBUF;
1605141cc406Sopenharmony_ci	  if (count < req->len)
1606141cc406Sopenharmony_ci	      req->len = count;
1607141cc406Sopenharmony_ci	  count -= req->len;
1608141cc406Sopenharmony_ci
1609141cc406Sopenharmony_ci	  req->cmd[0] = 0x08;
1610141cc406Sopenharmony_ci	  req->cmd[1] = 0;
1611141cc406Sopenharmony_ci	  req->cmd[2] = req->len >> 16;
1612141cc406Sopenharmony_ci	  req->cmd[3] = req->len >> 8;
1613141cc406Sopenharmony_ci	  req->cmd[4] = req->len;
1614141cc406Sopenharmony_ci	  req->cmd[5] = 0;
1615141cc406Sopenharmony_ci
1616141cc406Sopenharmony_ci	  DBG(3, "do_read: entering request to read %lu bytes\n",
1617141cc406Sopenharmony_ci	      (unsigned long) req->len);
1618141cc406Sopenharmony_ci
1619141cc406Sopenharmony_ci	  status = sanei_scsi_req_enter(this->fd, req->cmd, 6,
1620141cc406Sopenharmony_ci				      req->data, &req->len, &req->id);
1621141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
1622141cc406Sopenharmony_ci	    {
1623141cc406Sopenharmony_ci	      DBG(1, "do_read: Error from scsi_req_enter: %s\n",
1624141cc406Sopenharmony_ci		  sane_strstatus(status));
1625141cc406Sopenharmony_ci	      goto quit;
1626141cc406Sopenharmony_ci	    }
1627141cc406Sopenharmony_ci	  if (signal_caught)
1628141cc406Sopenharmony_ci	      goto quit;
1629141cc406Sopenharmony_ci	}
1630141cc406Sopenharmony_ci
1631141cc406Sopenharmony_ci      if (signal_caught)
1632141cc406Sopenharmony_ci	  goto quit;
1633141cc406Sopenharmony_ci
1634141cc406Sopenharmony_ci      assert(reqs_completed < reqs_issued);
1635141cc406Sopenharmony_ci      req = buf + (reqs_completed++ % 2);
1636141cc406Sopenharmony_ci
1637141cc406Sopenharmony_ci      DBG(3, "do_read: waiting for data\n");
1638141cc406Sopenharmony_ci      status = sanei_scsi_req_wait(req->id);
1639141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1640141cc406Sopenharmony_ci	{
1641141cc406Sopenharmony_ci	  DBG(1, "do_read: Error from scsi_req_wait: %s\n",
1642141cc406Sopenharmony_ci	      sane_strstatus(status));
1643141cc406Sopenharmony_ci	  goto quit;
1644141cc406Sopenharmony_ci	}
1645141cc406Sopenharmony_ci      if (signal_caught)
1646141cc406Sopenharmony_ci	  goto quit;
1647141cc406Sopenharmony_ci
1648141cc406Sopenharmony_ci      status = process_data (ph, (unsigned char *)req->data, (int)req->len);
1649141cc406Sopenharmony_ci      if ( status != SANE_STATUS_GOOD )
1650141cc406Sopenharmony_ci      {
1651141cc406Sopenharmony_ci        DBG(1,"do_read: Error in process_data\n");
1652141cc406Sopenharmony_ci        goto quit;
1653141cc406Sopenharmony_ci      }
1654141cc406Sopenharmony_ci    }
1655141cc406Sopenharmony_ci  }
1656141cc406Sopenharmony_ci  else  /* Read directly */
1657141cc406Sopenharmony_ci  {
1658141cc406Sopenharmony_ci    read_buf = sanei_hp_alloc ( HP_PIPEBUF );
1659141cc406Sopenharmony_ci    if (!read_buf)
1660141cc406Sopenharmony_ci    {
1661141cc406Sopenharmony_ci      DBG(1, "do_read: not enough memory for read buffer\n");
1662141cc406Sopenharmony_ci      goto quit;
1663141cc406Sopenharmony_ci    }
1664141cc406Sopenharmony_ci
1665141cc406Sopenharmony_ci    while (count > 0)
1666141cc406Sopenharmony_ci    {size_t nread;
1667141cc406Sopenharmony_ci
1668141cc406Sopenharmony_ci      if (signal_caught)
1669141cc406Sopenharmony_ci	  goto quit;
1670141cc406Sopenharmony_ci
1671141cc406Sopenharmony_ci      DBG(5, "do_read: %lu bytes left to read\n", (unsigned long)count);
1672141cc406Sopenharmony_ci
1673141cc406Sopenharmony_ci      nread = HP_PIPEBUF;
1674141cc406Sopenharmony_ci      if (nread > count) nread = count;
1675141cc406Sopenharmony_ci
1676141cc406Sopenharmony_ci      DBG(3, "do_read: try to read data (%lu bytes)\n", (unsigned long)nread);
1677141cc406Sopenharmony_ci
1678141cc406Sopenharmony_ci      status = hp_scsi_read (this, read_buf, &nread, 0);
1679141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1680141cc406Sopenharmony_ci      {
1681141cc406Sopenharmony_ci        DBG(1, "do_read: Error from scsi_read: %s\n",sane_strstatus(status));
1682141cc406Sopenharmony_ci        goto quit;
1683141cc406Sopenharmony_ci      }
1684141cc406Sopenharmony_ci
1685141cc406Sopenharmony_ci      DBG(3, "do_read: got %lu bytes\n", (unsigned long)nread);
1686141cc406Sopenharmony_ci
1687141cc406Sopenharmony_ci      if (nread <= 0)
1688141cc406Sopenharmony_ci      {
1689141cc406Sopenharmony_ci        DBG(1, "do_read: Nothing read\n");
1690141cc406Sopenharmony_ci        continue;
1691141cc406Sopenharmony_ci      }
1692141cc406Sopenharmony_ci
1693141cc406Sopenharmony_ci      status = process_data (ph, (unsigned char *)read_buf, (int)nread);
1694141cc406Sopenharmony_ci      if ( status != SANE_STATUS_GOOD )
1695141cc406Sopenharmony_ci      {
1696141cc406Sopenharmony_ci        DBG(1,"do_read: Error in process_data\n");
1697141cc406Sopenharmony_ci        goto quit;
1698141cc406Sopenharmony_ci      }
1699141cc406Sopenharmony_ci      count -= nread;
1700141cc406Sopenharmony_ci    }
1701141cc406Sopenharmony_ci  }
1702141cc406Sopenharmony_ci
1703141cc406Sopenharmony_ci  process_data_flush (ph);
1704141cc406Sopenharmony_ci
1705141cc406Sopenharmony_ciquit:
1706141cc406Sopenharmony_ci
1707141cc406Sopenharmony_ci  process_data_finish (ph);
1708141cc406Sopenharmony_ci
1709141cc406Sopenharmony_ci  if ( image_buf ) sanei_hp_free ( image_buf );
1710141cc406Sopenharmony_ci  if ( read_buf ) sanei_hp_free ( read_buf );
1711141cc406Sopenharmony_ci
1712141cc406Sopenharmony_ci  if (enable_requests && (reqs_completed < reqs_issued))
1713141cc406Sopenharmony_ci    {
1714141cc406Sopenharmony_ci      DBG(1, "do_read: cleaning up leftover requests\n");
1715141cc406Sopenharmony_ci      while (reqs_completed < reqs_issued)
1716141cc406Sopenharmony_ci	{
1717141cc406Sopenharmony_ci	  req = buf + (reqs_completed++ % 2);
1718141cc406Sopenharmony_ci	  sanei_scsi_req_wait(req->id);
1719141cc406Sopenharmony_ci	}
1720141cc406Sopenharmony_ci    }
1721141cc406Sopenharmony_ci
1722141cc406Sopenharmony_ci  sigfillset(&sig_set);
1723141cc406Sopenharmony_ci  sigprocmask(SIG_BLOCK, &sig_set, 0);
1724141cc406Sopenharmony_ci  for (i = 0; i < (int)(HP_NSIGS); i++)
1725141cc406Sopenharmony_ci      sigaction(kill_sig[i], &old_handler[i], 0);
1726141cc406Sopenharmony_ci  sigprocmask(SIG_SETMASK, &old_set, 0);
1727141cc406Sopenharmony_ci
1728141cc406Sopenharmony_ci  if (signal_caught)
1729141cc406Sopenharmony_ci    {
1730141cc406Sopenharmony_ci      DBG(1, "do_read: caught signal %d\n", signal_caught);
1731141cc406Sopenharmony_ci      raise(signal_caught);
1732141cc406Sopenharmony_ci      return SANE_STATUS_CANCELLED;
1733141cc406Sopenharmony_ci    }
1734141cc406Sopenharmony_ci
1735141cc406Sopenharmony_ci  return status;
1736141cc406Sopenharmony_ci}
1737141cc406Sopenharmony_ci
1738141cc406Sopenharmony_ci
1739141cc406Sopenharmony_ci
1740141cc406Sopenharmony_ci/*
1741141cc406Sopenharmony_ci *
1742141cc406Sopenharmony_ci */
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_cistatic SANE_Status
1745141cc406Sopenharmony_ci_hp_scl_inq (HpScsi scsi, HpScl scl, HpScl inq_cmnd,
1746141cc406Sopenharmony_ci	     void *valp, size_t *lengthp)
1747141cc406Sopenharmony_ci{
1748141cc406Sopenharmony_ci  size_t	bufsize	= 16 + (lengthp ? *lengthp: 0);
1749141cc406Sopenharmony_ci  char *	buf	= alloca(bufsize);
1750141cc406Sopenharmony_ci  char		expect[16], expect_char;
1751141cc406Sopenharmony_ci  int		val, count;
1752141cc406Sopenharmony_ci  SANE_Status	status;
1753141cc406Sopenharmony_ci
1754141cc406Sopenharmony_ci  if (!buf)
1755141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1756141cc406Sopenharmony_ci
1757141cc406Sopenharmony_ci  /* Flush data before sending inquiry. */
1758141cc406Sopenharmony_ci  /* Otherwise scanner might not generate a response. */
1759141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_flush (scsi)) ;
1760141cc406Sopenharmony_ci
1761141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_scl(scsi, inq_cmnd, SCL_INQ_ID(scl)) );
1762141cc406Sopenharmony_ci  usleep (1000); /* 500 works, too, but not 100 */
1763141cc406Sopenharmony_ci
1764141cc406Sopenharmony_ci  status =  hp_scsi_read(scsi, buf, &bufsize, 1);
1765141cc406Sopenharmony_ci  if (FAILED(status))
1766141cc406Sopenharmony_ci    {
1767141cc406Sopenharmony_ci      DBG(1, "scl_inq: read failed (%s)\n", sane_strstatus(status));
1768141cc406Sopenharmony_ci      return status;
1769141cc406Sopenharmony_ci    }
1770141cc406Sopenharmony_ci
1771141cc406Sopenharmony_ci  if (SCL_PARAM_CHAR(inq_cmnd) == 'R')
1772141cc406Sopenharmony_ci      expect_char = 'p';
1773141cc406Sopenharmony_ci  else
1774141cc406Sopenharmony_ci      expect_char = tolower(SCL_PARAM_CHAR(inq_cmnd) - 1);
1775141cc406Sopenharmony_ci
1776141cc406Sopenharmony_ci  count = sprintf(expect, "\033*s%d%c", SCL_INQ_ID(scl), expect_char);
1777141cc406Sopenharmony_ci  if (memcmp(buf, expect, count) != 0)
1778141cc406Sopenharmony_ci    {
1779141cc406Sopenharmony_ci      DBG(1, "scl_inq: malformed response: expected '%s', got '%.*s'\n",
1780141cc406Sopenharmony_ci	  expect, count, buf);
1781141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1782141cc406Sopenharmony_ci    }
1783141cc406Sopenharmony_ci  buf += count;
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci  if (buf[0] == 'N')
1786141cc406Sopenharmony_ci    {				/* null response */
1787141cc406Sopenharmony_ci      DBG(3, "scl_inq: parameter %d unsupported\n", SCL_INQ_ID(scl));
1788141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1789141cc406Sopenharmony_ci    }
1790141cc406Sopenharmony_ci
1791141cc406Sopenharmony_ci  if (sscanf(buf, "%d%n", &val, &count) != 1)
1792141cc406Sopenharmony_ci    {
1793141cc406Sopenharmony_ci      DBG(1, "scl_inq: malformed response: expected int, got '%.8s'\n", buf);
1794141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1795141cc406Sopenharmony_ci    }
1796141cc406Sopenharmony_ci  buf += count;
1797141cc406Sopenharmony_ci
1798141cc406Sopenharmony_ci  expect_char = lengthp ? 'W' : 'V';
1799141cc406Sopenharmony_ci  if (*buf++ != expect_char)
1800141cc406Sopenharmony_ci    {
1801141cc406Sopenharmony_ci      DBG(1, "scl_inq: malformed response: expected '%c', got '%.4s'\n",
1802141cc406Sopenharmony_ci	  expect_char, buf - 1);
1803141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1804141cc406Sopenharmony_ci    }
1805141cc406Sopenharmony_ci
1806141cc406Sopenharmony_ci  if (!lengthp)
1807141cc406Sopenharmony_ci      *(int *)valp = val; /* Get integer value */
1808141cc406Sopenharmony_ci  else
1809141cc406Sopenharmony_ci    {
1810141cc406Sopenharmony_ci      if (val > (int)*lengthp)
1811141cc406Sopenharmony_ci	{
1812141cc406Sopenharmony_ci	  DBG(1, "scl_inq: inquiry returned %d bytes, expected <= %lu\n",
1813141cc406Sopenharmony_ci	      val, (unsigned long) *lengthp);
1814141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
1815141cc406Sopenharmony_ci	}
1816141cc406Sopenharmony_ci      *lengthp = val;
1817141cc406Sopenharmony_ci      memcpy(valp, buf , *lengthp); /* Get binary data */
1818141cc406Sopenharmony_ci    }
1819141cc406Sopenharmony_ci
1820141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1821141cc406Sopenharmony_ci}
1822141cc406Sopenharmony_ci
1823141cc406Sopenharmony_ci
1824141cc406Sopenharmony_ciSANE_Status
1825141cc406Sopenharmony_cisanei_hp_scl_upload_binary (HpScsi scsi, HpScl scl, size_t *lengthhp,
1826141cc406Sopenharmony_ci                            char **bufhp)
1827141cc406Sopenharmony_ci{
1828141cc406Sopenharmony_ci  size_t	bufsize	= 16, sv;
1829141cc406Sopenharmony_ci  char *	buf	= alloca(bufsize);
1830141cc406Sopenharmony_ci  char *        bufstart = buf;
1831141cc406Sopenharmony_ci  char *        hpdata;
1832141cc406Sopenharmony_ci  char		expect[16], expect_char;
1833141cc406Sopenharmony_ci  int		n, val, count;
1834141cc406Sopenharmony_ci  SANE_Status	status;
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_ci  if (!buf)
1837141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1838141cc406Sopenharmony_ci
1839141cc406Sopenharmony_ci  assert ( IS_SCL_DATA_TYPE (scl) );
1840141cc406Sopenharmony_ci
1841141cc406Sopenharmony_ci  /* Flush data before sending inquiry. */
1842141cc406Sopenharmony_ci  /* Otherwise scanner might not generate a response. */
1843141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_flush (scsi)) ;
1844141cc406Sopenharmony_ci
1845141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_scl(scsi, SCL_UPLOAD_BINARY_DATA, SCL_INQ_ID(scl)) );
1846141cc406Sopenharmony_ci
1847141cc406Sopenharmony_ci  status =  hp_scsi_read(scsi, buf, &bufsize, 0);
1848141cc406Sopenharmony_ci  if (FAILED(status))
1849141cc406Sopenharmony_ci    {
1850141cc406Sopenharmony_ci      DBG(1, "scl_upload_binary: read failed (%s)\n", sane_strstatus(status));
1851141cc406Sopenharmony_ci      return status;
1852141cc406Sopenharmony_ci    }
1853141cc406Sopenharmony_ci
1854141cc406Sopenharmony_ci  expect_char = 't';
1855141cc406Sopenharmony_ci  count = sprintf(expect, "\033*s%d%c", SCL_INQ_ID(scl), expect_char);
1856141cc406Sopenharmony_ci  if (memcmp(buf, expect, count) != 0)
1857141cc406Sopenharmony_ci    {
1858141cc406Sopenharmony_ci      DBG(1, "scl_upload_binary: malformed response: expected '%s', got '%.*s'\n",
1859141cc406Sopenharmony_ci	  expect, count, buf);
1860141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1861141cc406Sopenharmony_ci    }
1862141cc406Sopenharmony_ci  buf += count;
1863141cc406Sopenharmony_ci
1864141cc406Sopenharmony_ci  if (buf[0] == 'N')
1865141cc406Sopenharmony_ci    {				/* null response */
1866141cc406Sopenharmony_ci      DBG(1, "scl_upload_binary: parameter %d unsupported\n", SCL_INQ_ID(scl));
1867141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1868141cc406Sopenharmony_ci    }
1869141cc406Sopenharmony_ci
1870141cc406Sopenharmony_ci  if (sscanf(buf, "%d%n", &val, &count) != 1)
1871141cc406Sopenharmony_ci    {
1872141cc406Sopenharmony_ci      DBG(1, "scl_inq: malformed response: expected int, got '%.8s'\n", buf);
1873141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1874141cc406Sopenharmony_ci    }
1875141cc406Sopenharmony_ci  buf += count;
1876141cc406Sopenharmony_ci
1877141cc406Sopenharmony_ci  expect_char = 'W';
1878141cc406Sopenharmony_ci  if (*buf++ != expect_char)
1879141cc406Sopenharmony_ci    {
1880141cc406Sopenharmony_ci      DBG(1, "scl_inq: malformed response: expected '%c', got '%.4s'\n",
1881141cc406Sopenharmony_ci	  expect_char, buf - 1);
1882141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
1883141cc406Sopenharmony_ci    }
1884141cc406Sopenharmony_ci
1885141cc406Sopenharmony_ci  *lengthhp = val;
1886141cc406Sopenharmony_ci  *bufhp = hpdata = sanei_hp_alloc ( val );
1887141cc406Sopenharmony_ci  if (!hpdata)
1888141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1889141cc406Sopenharmony_ci
1890141cc406Sopenharmony_ci  if (buf < bufstart + bufsize)
1891141cc406Sopenharmony_ci    {
1892141cc406Sopenharmony_ci       n = bufsize - (buf - bufstart);
1893141cc406Sopenharmony_ci       if (n > val) n = val;
1894141cc406Sopenharmony_ci       memcpy (hpdata, buf, n);
1895141cc406Sopenharmony_ci       hpdata += n;
1896141cc406Sopenharmony_ci       val -= n;
1897141cc406Sopenharmony_ci    }
1898141cc406Sopenharmony_ci
1899141cc406Sopenharmony_ci  status = SANE_STATUS_GOOD;
1900141cc406Sopenharmony_ci  if ( val > 0 )
1901141cc406Sopenharmony_ci    {
1902141cc406Sopenharmony_ci      sv = val;
1903141cc406Sopenharmony_ci      status = hp_scsi_read(scsi, hpdata, &sv, 0);
1904141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1905141cc406Sopenharmony_ci        sanei_hp_free ( *bufhp );
1906141cc406Sopenharmony_ci    }
1907141cc406Sopenharmony_ci
1908141cc406Sopenharmony_ci  return status;
1909141cc406Sopenharmony_ci}
1910141cc406Sopenharmony_ci
1911141cc406Sopenharmony_ci
1912141cc406Sopenharmony_ciSANE_Status
1913141cc406Sopenharmony_cisanei_hp_scl_set(HpScsi scsi, HpScl scl, int val)
1914141cc406Sopenharmony_ci{
1915141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_scl(scsi, scl, val) );
1916141cc406Sopenharmony_ci
1917141cc406Sopenharmony_ci
1918141cc406Sopenharmony_ci#ifdef PARANOID
1919141cc406Sopenharmony_ci  RETURN_IF_FAIL( sanei_hp_scl_errcheck(scsi) );
1920141cc406Sopenharmony_ci#endif
1921141cc406Sopenharmony_ci
1922141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1923141cc406Sopenharmony_ci}
1924141cc406Sopenharmony_ci
1925141cc406Sopenharmony_ciSANE_Status
1926141cc406Sopenharmony_cisanei_hp_scl_inquire(HpScsi scsi, HpScl scl, int * valp, int * minp, int * maxp)
1927141cc406Sopenharmony_ci{
1928141cc406Sopenharmony_ci  HpScl	inquiry = ( IS_SCL_CONTROL(scl)
1929141cc406Sopenharmony_ci		    ? SCL_INQUIRE_PRESENT_VALUE
1930141cc406Sopenharmony_ci		    : SCL_INQUIRE_DEVICE_PARAMETER );
1931141cc406Sopenharmony_ci
1932141cc406Sopenharmony_ci  assert(IS_SCL_CONTROL(scl) || IS_SCL_PARAMETER(scl));
1933141cc406Sopenharmony_ci  assert(IS_SCL_CONTROL(scl) || (!minp && !maxp));
1934141cc406Sopenharmony_ci
1935141cc406Sopenharmony_ci  if (valp)
1936141cc406Sopenharmony_ci      RETURN_IF_FAIL( _hp_scl_inq(scsi, scl, inquiry, valp, 0) );
1937141cc406Sopenharmony_ci  if (minp)
1938141cc406Sopenharmony_ci      RETURN_IF_FAIL( _hp_scl_inq(scsi, scl,
1939141cc406Sopenharmony_ci				  SCL_INQUIRE_MINIMUM_VALUE, minp, 0) );
1940141cc406Sopenharmony_ci  if (maxp)
1941141cc406Sopenharmony_ci      RETURN_IF_FAIL( _hp_scl_inq(scsi, scl,
1942141cc406Sopenharmony_ci				  SCL_INQUIRE_MAXIMUM_VALUE, maxp, 0) );
1943141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1944141cc406Sopenharmony_ci}
1945141cc406Sopenharmony_ci
1946141cc406Sopenharmony_ci#ifdef _HP_NOT_USED
1947141cc406Sopenharmony_cistatic SANE_Status
1948141cc406Sopenharmony_cihp_scl_get_bounds(HpScsi scsi, HpScl scl, int * minp, int * maxp)
1949141cc406Sopenharmony_ci{
1950141cc406Sopenharmony_ci  assert(IS_SCL_CONTROL(scl));
1951141cc406Sopenharmony_ci  RETURN_IF_FAIL( _hp_scl_inq(scsi, scl, SCL_INQUIRE_MINIMUM_VALUE, minp, 0) );
1952141cc406Sopenharmony_ci  return _hp_scl_inq(scsi, scl, SCL_INQUIRE_MAXIMUM_VALUE, maxp, 0);
1953141cc406Sopenharmony_ci}
1954141cc406Sopenharmony_ci#endif
1955141cc406Sopenharmony_ci
1956141cc406Sopenharmony_ci#ifdef _HP_NOT_USED
1957141cc406Sopenharmony_cistatic SANE_Status
1958141cc406Sopenharmony_cihp_scl_get_bounds_and_val(HpScsi scsi, HpScl scl,
1959141cc406Sopenharmony_ci			  int * minp, int * maxp, int * valp)
1960141cc406Sopenharmony_ci{
1961141cc406Sopenharmony_ci  assert(IS_SCL_CONTROL(scl));
1962141cc406Sopenharmony_ci  RETURN_IF_FAIL( _hp_scl_inq(scsi, scl, SCL_INQUIRE_MINIMUM_VALUE, minp, 0) );
1963141cc406Sopenharmony_ci  RETURN_IF_FAIL( _hp_scl_inq(scsi, scl, SCL_INQUIRE_MAXIMUM_VALUE, maxp, 0) );
1964141cc406Sopenharmony_ci  return    _hp_scl_inq(scsi, scl, SCL_INQUIRE_PRESENT_VALUE, valp, 0);
1965141cc406Sopenharmony_ci}
1966141cc406Sopenharmony_ci#endif
1967141cc406Sopenharmony_ci
1968141cc406Sopenharmony_ciSANE_Status
1969141cc406Sopenharmony_cisanei_hp_scl_download(HpScsi scsi, HpScl scl, const void * valp, size_t len)
1970141cc406Sopenharmony_ci{
1971141cc406Sopenharmony_ci  assert(IS_SCL_DATA_TYPE(scl));
1972141cc406Sopenharmony_ci
1973141cc406Sopenharmony_ci  sanei_hp_scl_clearErrors ( scsi );
1974141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_need(scsi, 16) );
1975141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_scl(scsi, SCL_DOWNLOAD_TYPE, SCL_INQ_ID(scl)) );
1976141cc406Sopenharmony_ci                            /* Download type not supported ? */
1977141cc406Sopenharmony_ci  RETURN_IF_FAIL( sanei_hp_scl_errcheck(scsi) );
1978141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_scl(scsi, SCL_DOWNLOAD_LENGTH, len) );
1979141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_write(scsi, valp, len) );
1980141cc406Sopenharmony_ci
1981141cc406Sopenharmony_ci#ifdef PARANOID
1982141cc406Sopenharmony_ci  RETURN_IF_FAIL( sanei_hp_scl_errcheck(scsi) );
1983141cc406Sopenharmony_ci#endif
1984141cc406Sopenharmony_ci
1985141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1986141cc406Sopenharmony_ci}
1987141cc406Sopenharmony_ci
1988141cc406Sopenharmony_ciSANE_Status
1989141cc406Sopenharmony_cisanei_hp_scl_upload(HpScsi scsi, HpScl scl, void * valp, size_t len)
1990141cc406Sopenharmony_ci{
1991141cc406Sopenharmony_ci  size_t	nread = len;
1992141cc406Sopenharmony_ci  HpScl		inquiry = ( IS_SCL_DATA_TYPE(scl)
1993141cc406Sopenharmony_ci			    ? SCL_UPLOAD_BINARY_DATA
1994141cc406Sopenharmony_ci			    : SCL_INQUIRE_DEVICE_PARAMETER );
1995141cc406Sopenharmony_ci
1996141cc406Sopenharmony_ci  assert(IS_SCL_DATA_TYPE(scl) || IS_SCL_PARAMETER(scl));
1997141cc406Sopenharmony_ci
1998141cc406Sopenharmony_ci  RETURN_IF_FAIL( _hp_scl_inq(scsi, scl, inquiry, valp, &nread) );
1999141cc406Sopenharmony_ci  if (IS_SCL_PARAMETER(scl) && nread < len)
2000141cc406Sopenharmony_ci      ((char *)valp)[nread] = '\0';
2001141cc406Sopenharmony_ci  else if (len != nread)
2002141cc406Sopenharmony_ci    {
2003141cc406Sopenharmony_ci      DBG(1, "scl_upload: requested %lu bytes, got %lu\n",
2004141cc406Sopenharmony_ci	  (unsigned long) len, (unsigned long) nread);
2005141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2006141cc406Sopenharmony_ci    }
2007141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2008141cc406Sopenharmony_ci}
2009141cc406Sopenharmony_ci
2010141cc406Sopenharmony_ciSANE_Status
2011141cc406Sopenharmony_cisanei_hp_scl_calibrate(HpScsi scsi)
2012141cc406Sopenharmony_ci{
2013141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_scl(scsi, SCL_CALIBRATE, 0) );
2014141cc406Sopenharmony_ci  return hp_scsi_flush(scsi);
2015141cc406Sopenharmony_ci}
2016141cc406Sopenharmony_ci
2017141cc406Sopenharmony_ciSANE_Status
2018141cc406Sopenharmony_cisanei_hp_scl_startScan(HpScsi scsi, HpScl scl)
2019141cc406Sopenharmony_ci{
2020141cc406Sopenharmony_ci  char *msg = "";
2021141cc406Sopenharmony_ci
2022141cc406Sopenharmony_ci  if (scl == SCL_ADF_SCAN) msg = " (ADF)";
2023141cc406Sopenharmony_ci  else if (scl == SCL_XPA_SCAN) msg = " (XPA)";
2024141cc406Sopenharmony_ci  else scl = SCL_START_SCAN;
2025141cc406Sopenharmony_ci
2026141cc406Sopenharmony_ci  DBG(1, "sanei_hp_scl_startScan: Start scan%s\n", msg);
2027141cc406Sopenharmony_ci
2028141cc406Sopenharmony_ci  /* For active XPA we must not use XPA scan */
2029141cc406Sopenharmony_ci  if ((scl == SCL_XPA_SCAN) && sanei_hp_is_active_xpa (scsi))
2030141cc406Sopenharmony_ci  {
2031141cc406Sopenharmony_ci    DBG(3,"Map XPA scan to scan because of active XPA\n");
2032141cc406Sopenharmony_ci    scl = SCL_START_SCAN;
2033141cc406Sopenharmony_ci  }
2034141cc406Sopenharmony_ci
2035141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_scl(scsi, scl, 0) );
2036141cc406Sopenharmony_ci  return hp_scsi_flush(scsi);
2037141cc406Sopenharmony_ci}
2038141cc406Sopenharmony_ci
2039141cc406Sopenharmony_ciSANE_Status
2040141cc406Sopenharmony_cisanei_hp_scl_reset(HpScsi scsi)
2041141cc406Sopenharmony_ci{
2042141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_write(scsi, "\033E", 2) );
2043141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_flush(scsi) );
2044141cc406Sopenharmony_ci  return sanei_hp_scl_errcheck(scsi);
2045141cc406Sopenharmony_ci}
2046141cc406Sopenharmony_ci
2047141cc406Sopenharmony_ciSANE_Status
2048141cc406Sopenharmony_cisanei_hp_scl_clearErrors(HpScsi scsi)
2049141cc406Sopenharmony_ci{
2050141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_flush(scsi) );
2051141cc406Sopenharmony_ci  RETURN_IF_FAIL( hp_scsi_write(scsi, "\033*oE", 4) );
2052141cc406Sopenharmony_ci  return hp_scsi_flush(scsi);
2053141cc406Sopenharmony_ci}
2054141cc406Sopenharmony_ci
2055141cc406Sopenharmony_cistatic const char *
2056141cc406Sopenharmony_cihp_scl_strerror (int errnum)
2057141cc406Sopenharmony_ci{
2058141cc406Sopenharmony_ci  static const char * errlist[] = {
2059141cc406Sopenharmony_ci      "Command Format Error",
2060141cc406Sopenharmony_ci      "Unrecognized Command",
2061141cc406Sopenharmony_ci      "Parameter Error",
2062141cc406Sopenharmony_ci      "Illegal Window",
2063141cc406Sopenharmony_ci      "Scaling Error",
2064141cc406Sopenharmony_ci      "Dither ID Error",
2065141cc406Sopenharmony_ci      "Tone Map ID Error",
2066141cc406Sopenharmony_ci      "Lamp Error",
2067141cc406Sopenharmony_ci      "Matrix ID Error",
2068141cc406Sopenharmony_ci      "Cal Strip Param Error",
2069141cc406Sopenharmony_ci      "Gross Calibration Error"
2070141cc406Sopenharmony_ci  };
2071141cc406Sopenharmony_ci
2072141cc406Sopenharmony_ci  if (errnum >= 0 && errnum < (int)(sizeof(errlist)/sizeof(errlist[0])))
2073141cc406Sopenharmony_ci      return errlist[errnum];
2074141cc406Sopenharmony_ci  else
2075141cc406Sopenharmony_ci      switch(errnum) {
2076141cc406Sopenharmony_ci      case 1024: return "ADF Paper Jam";
2077141cc406Sopenharmony_ci      case 1025: return "Home Position Missing";
2078141cc406Sopenharmony_ci      case 1026: return "Paper Not Loaded";
2079141cc406Sopenharmony_ci      default: return "??Unknown Error??";
2080141cc406Sopenharmony_ci      }
2081141cc406Sopenharmony_ci}
2082141cc406Sopenharmony_ci
2083141cc406Sopenharmony_ci/* Check for SCL errors */
2084141cc406Sopenharmony_ciSANE_Status
2085141cc406Sopenharmony_cisanei_hp_scl_errcheck (HpScsi scsi)
2086141cc406Sopenharmony_ci{
2087141cc406Sopenharmony_ci  int		errnum;
2088141cc406Sopenharmony_ci  int		nerrors;
2089141cc406Sopenharmony_ci  SANE_Status	status;
2090141cc406Sopenharmony_ci
2091141cc406Sopenharmony_ci  status = sanei_hp_scl_inquire(scsi, SCL_CURRENT_ERROR_STACK, &nerrors,0,0);
2092141cc406Sopenharmony_ci  if (!FAILED(status) && nerrors)
2093141cc406Sopenharmony_ci      status = sanei_hp_scl_inquire(scsi, SCL_OLDEST_ERROR, &errnum,0,0);
2094141cc406Sopenharmony_ci  if (FAILED(status))
2095141cc406Sopenharmony_ci    {
2096141cc406Sopenharmony_ci      DBG(1, "scl_errcheck: Can't read SCL error stack: %s\n",
2097141cc406Sopenharmony_ci	  sane_strstatus(status));
2098141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2099141cc406Sopenharmony_ci    }
2100141cc406Sopenharmony_ci
2101141cc406Sopenharmony_ci  if (nerrors)
2102141cc406Sopenharmony_ci    {
2103141cc406Sopenharmony_ci      DBG(1, "Scanner issued SCL error: (%d) %s\n",
2104141cc406Sopenharmony_ci	  errnum, hp_scl_strerror(errnum));
2105141cc406Sopenharmony_ci
2106141cc406Sopenharmony_ci      sanei_hp_scl_clearErrors (scsi);
2107141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2108141cc406Sopenharmony_ci    }
2109141cc406Sopenharmony_ci
2110141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2111141cc406Sopenharmony_ci}
2112