1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
3    Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
4    Copyright (c) 2003 Henning Meier-Geinitz, <henning@meier-geinitz.de>
5 
6    Originally copied from HP3300 testtools. Original notice follows:
7 
8    Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl)
9 
10    This file is part of the SANE package.
11 
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    as published by the Free Software Foundation; either version 2
15    of the License, or (at your option) any later version.
16 
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21 
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <https://www.gnu.org/licenses/>.
24 
25    As a special exception, the authors of SANE give permission for
26    additional uses of the libraries contained in this release of SANE.
27 
28    The exception is that, if you link a SANE library with other files
29    to produce an executable, this does not by itself cause the
30    resulting executable to be covered by the GNU General Public
31    License.  Your use of that executable is in no way restricted on
32    account of linking the SANE library code into it.
33 
34    This exception does not, however, invalidate any other reasons why
35    the executable file might be covered by the GNU General Public
36    License.
37 
38    If you submit changes to SANE to the maintainers to be included in
39    a subsequent release, you agree by submitting the changes that
40    those changes may be distributed with this exception intact.
41 
42    If you write modifications of your own for SANE, it is your choice
43    whether to permit this exception to apply to your modifications.
44    If you do not wish that, delete this exception notice.
45 
46    Transport layer for communication with HP5400/5470 scanner.
47 
48    Implementation using sanei_usb
49 
50    Additions to support bulk data transport. Added debugging info - 19/02/2003 Martijn
51    Changed to use sanei_usb instead of direct /dev/usb/scanner access - 15/04/2003 Henning
52 */
53 
54 
55 #include "hp5400_xfer.h"
56 #include "hp5400_debug.h"
57 #include <stdio.h>
58 #include "../include/sane/sanei_usb.h"
59 
60 #define CMD_INITBULK1   0x0087	/* send 0x14 */
61 #define CMD_INITBULK2   0x0083	/* send 0x24 */
62 #define CMD_INITBULK3   0x0082	/* transfer length 0xf000 */
63 
64 
65 
66 static void
_UsbWriteControl(int fd,int iValue,int iIndex,void * pabData,int iSize)67 _UsbWriteControl (int fd, int iValue, int iIndex, void *pabData, int iSize)
68 {
69   int requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT;
70   int request = (iSize > 1) ? 0x04 : 0x0C;
71 
72   HP5400_DBG (DBG_MSG,
73        "Write: reqtype = 0x%02X, req = 0x%02X, value = %04X, len = %d\n",
74        requesttype, request, iValue, iSize);
75 
76   if (iSize > 0)
77     {
78       int i;
79       HP5400_DBG (DBG_MSG, "  Data: ");
80       for (i = 0; i < iSize && i < 8; i++)
81 	HP5400_DBG (DBG_MSG, "%02X ", ((unsigned char *) pabData)[i]);
82       if (iSize > 8)
83 	HP5400_DBG (DBG_MSG, "...");
84       HP5400_DBG (DBG_MSG, "\n");
85     }
86 
87   if (fd != -1)
88     {
89       sanei_usb_control_msg (fd, requesttype, request, iValue, iIndex, iSize,
90 			     pabData);
91     }
92   /* No error checking? */
93 
94 }
95 
96 void
hp5400_command_write_noverify(int fd,int iValue,void * pabData,int iSize)97 hp5400_command_write_noverify (int fd, int iValue, void *pabData, int iSize)
98 {
99   _UsbWriteControl (fd, iValue, 0, pabData, iSize);
100 }
101 
102 static void
_UsbReadControl(int fd,int iValue,int iIndex,void * pabData,int iSize)103 _UsbReadControl (int fd, int iValue, int iIndex, void *pabData, int iSize)
104 {
105   int requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN;
106   int request = (iSize > 1) ? 0x04 : 0x0C;
107 
108   HP5400_DBG (DBG_MSG, "Read: reqtype = 0x%02X, req = 0x%02X, value = %04X\n",
109        requesttype, request, iValue);
110 
111   if (fd != -1)
112     {
113       sanei_usb_control_msg (fd, requesttype, request, iValue, iIndex, iSize,
114 			     pabData);
115     }
116 }
117 
118 
119 HP5400_SANE_STATIC int
hp5400_open(const char * filename)120 hp5400_open (const char *filename)
121 {
122   int fd, iVendor, iProduct;
123   SANE_Status status;
124 
125   if (!filename)
126     filename = "/dev/usb/scanner0";
127 
128   status = sanei_usb_open (filename, &fd);
129   if (status != SANE_STATUS_GOOD)
130     {
131       HP5400_DBG (DBG_MSG, "hp5400_open: open returned %s\n",
132 	   sane_strstatus (status));
133       return -1;
134     }
135 
136   status = sanei_usb_get_vendor_product (fd, &iVendor, &iProduct);
137   if (status != SANE_STATUS_GOOD)
138     {
139       HP5400_DBG (DBG_MSG, "hp5400_open: can't get vendor/product ids: %s\n",
140 	   sane_strstatus (status));
141       sanei_usb_close (fd);
142       return -1;
143     }
144 
145   if ((iVendor != 0x03F0) || ((iProduct != 0x1005) && (iProduct != 0x1105)))
146     {
147       HP5400_DBG (DBG_MSG, "hp5400_open: vendor/product 0x%04X-0x%04X is not "
148 	   "supported\n", iVendor, iProduct);
149       sanei_usb_close (fd);
150       return -1;
151     }
152 
153   HP5400_DBG (DBG_MSG, "vendor/product 0x%04X-0x%04X opened\n", iVendor, iProduct);
154 
155   return fd;
156 }
157 
158 
159 void
hp5400_close(int iHandle)160 hp5400_close (int iHandle)
161 {
162   sanei_usb_close (iHandle);
163 }
164 
165 
166 /* returns value > 0 if verify ok */
167 int
hp5400_command_verify(int iHandle,int iCmd)168 hp5400_command_verify (int iHandle, int iCmd)
169 {
170   unsigned char abData[4];
171   int fd;
172 
173   if (iHandle < 0)
174     {
175       HP5400_DBG (DBG_ERR, "hp5400_command_verify: invalid handle\n");
176       return -1;
177     }
178   fd = iHandle;
179 
180   /* command 0xc500: read back previous command */
181   _UsbReadControl (fd, 0xc500, 0, (char *) abData, 2);
182 
183   if (abData[0] != (iCmd >> 8))
184     {
185       HP5400_DBG (DBG_ERR,
186 	   "hp5400_command_verify failed, expected 0x%02X%02X, got 0x%02X%02X\n",
187 	   (int) (iCmd >> 8), (int) (iCmd & 0xff), (int) abData[0],
188 	   (int) abData[1]);
189 
190       return -1;
191     }
192 
193   if (abData[1] != 0)		/* Error code non-zero */
194     {
195       _UsbReadControl (fd, 0x0300, 0, (char *) abData, 3);
196       HP5400_DBG (DBG_ERR, "  error response is: %02X %02X %02X\n", abData[0],
197 	   abData[1], abData[2]);
198 
199       return -1;
200     }
201 
202   HP5400_DBG (DBG_MSG, "Command %02X verified\n", abData[0]);
203   return 1;
204 }
205 
206 
207 /* returns > 0 if command OK */
208 int
hp5400_command_read_noverify(int iHandle,int iCmd,int iLen,void * pbData)209 hp5400_command_read_noverify (int iHandle, int iCmd, int iLen, void *pbData)
210 {
211   int fd;
212 
213   if (iHandle < 0)
214     {
215       HP5400_DBG (DBG_ERR, "hp5400_command_read: invalid handle\n");
216       return -1;
217     }
218   fd = iHandle;
219 
220   _UsbReadControl (fd, iCmd, 0, pbData, iLen);
221 
222   return 1;
223 }
224 
225 /* returns > 0 if command OK */
226 int
hp5400_command_read(int iHandle,int iCmd,int iLen,void * pbData)227 hp5400_command_read (int iHandle, int iCmd, int iLen, void *pbData)
228 {
229   hp5400_command_read_noverify (iHandle, iCmd, iLen, pbData);
230 
231   return hp5400_command_verify (iHandle, iCmd);
232 }
233 
234 
235 /* returns >0 if command OK */
236 int
hp5400_command_write(int iHandle,int iCmd,int iLen,void * pbData)237 hp5400_command_write (int iHandle, int iCmd, int iLen, void *pbData)
238 {
239   int fd;
240 
241   if (iHandle < 0)
242     {
243       HP5400_DBG (DBG_ERR, "hp5400_command_write: invalid handle\n");
244       return -1;
245     }
246   fd = iHandle;
247 
248   _UsbWriteControl (fd, iCmd, 0, (char *) pbData, iLen);
249 
250   return hp5400_command_verify (iHandle, iCmd);
251 }
252 
253 #ifdef STANDALONE
254 /* returns >0 if command OK */
255 int
hp5400_bulk_read(int iHandle,size_t len,int block,FILE * file)256 hp5400_bulk_read (int iHandle, size_t len, int block, FILE * file)
257 {
258   SANE_Int fd;
259   char x1 = 0x14, x2 = 0x24;
260   short buf[4] = { 0, 0, 0, 0 };
261   SANE_Byte *buffer;
262   size_t res = 0;
263 
264   buf[2] = block;
265 
266   if (iHandle < 0)
267     {
268       HP5400_DBG (DBG_ERR, "hp5400_command_read: invalid handle\n");
269       return -1;
270     }
271   fd = iHandle;
272 
273   buffer = (unsigned char*) malloc (block);
274 
275   _UsbWriteControl (fd, CMD_INITBULK1, 0, &x1, 1);
276   _UsbWriteControl (fd, CMD_INITBULK2, 0, &x2, 1);
277 
278   while (len > 0)
279     {
280       _UsbWriteControl (fd, CMD_INITBULK3, 0, (unsigned char *) &buf,
281 			sizeof (buf));
282       res = block;
283       sanei_usb_read_bulk (fd, buffer, &res);
284       HP5400_DBG (DBG_MSG, "Read bulk returned %lu, %lu remain\n",
285 		  (u_long) res, (u_long) len);
286       if (res > 0)
287 	{
288 	  fwrite (buffer, (len < res) ? len : res, 1, file);
289 	}
290       len -= block;
291     }
292   /* error handling? */
293   return 0;
294 }
295 #endif
296 
297 /* returns >0 if command OK */
298 int
hp5400_bulk_read_block(int iHandle,int iCmd,void * cmd,int cmdlen,void * buffer,int len)299 hp5400_bulk_read_block (int iHandle, int iCmd, void *cmd, int cmdlen,
300 			void *buffer, int len)
301 {
302   SANE_Int fd;
303   size_t res = 0;
304 
305   if (iHandle < 0)
306     {
307       HP5400_DBG (DBG_ERR, "hp5400_command_read_block: invalid handle\n");
308       return -1;
309     }
310   fd = iHandle;
311 
312   _UsbWriteControl (fd, iCmd, 0, cmd, cmdlen);
313   res = len;
314   sanei_usb_read_bulk (fd, (SANE_Byte *) buffer, &res);
315   HP5400_DBG (DBG_MSG, "Read block returned %lu when reading %d\n",
316 	      (u_long) res, len);
317   return res;
318 }
319 
320 /* returns >0 if command OK */
321 int
hp5400_bulk_command_write(int iHandle,int iCmd,void * cmd,int cmdlen,int datalen,int block,char * data)322 hp5400_bulk_command_write (int iHandle, int iCmd, void *cmd, int cmdlen,
323 			   int datalen, int block, char *data)
324 {
325   SANE_Int fd;
326   size_t res = 0, offset = 0;
327 
328   if (iHandle < 0)
329     {
330       HP5400_DBG (DBG_ERR, "hp5400_bulk_command_write: invalid handle\n");
331       return -1;
332     }
333   fd = iHandle;
334 
335   HP5400_DBG (DBG_MSG, "bulk_command_write(%04X,<%d bytes>,<%d bytes>)\n", iCmd,
336        cmdlen, datalen);
337 
338   _UsbWriteControl (fd, iCmd, 0, cmd, cmdlen);
339 
340   while (datalen > 0)
341     {
342       {
343 	int i;
344 	HP5400_DBG (DBG_MSG, "  Data: ");
345 	for (i = 0; i < datalen && i < block && i < 8; i++)
346 	  HP5400_DBG (DBG_MSG, "%02X ", ((unsigned char *) data + offset)[i]);
347 	if (i >= 8)
348 	  HP5400_DBG (DBG_MSG, "...");
349 	HP5400_DBG (DBG_MSG, "\n");
350       }
351       res = (datalen < block) ? datalen : block;
352       sanei_usb_write_bulk (fd, (SANE_Byte *) (data + offset), &res);
353       HP5400_DBG (DBG_MSG, "Write returned %lu, %d remain\n", (u_long) res, datalen);
354       datalen -= block;
355       offset += block;
356     }
357 
358   return hp5400_command_verify (iHandle, iCmd);
359 }
360 
361 #ifdef STANDALONE
362 /**
363   ScannerIsOn
364     retrieve on/off status from scanner
365     @return 1 if is on 0 if is off -1 if is not reachable
366 */
367 int
hp5400_isOn(int iHandle)368 hp5400_isOn (int iHandle)
369 {
370   unsigned char text2400[3];
371 
372   hp5400_command_read (iHandle, 0x2400, 0x03, text2400);
373 
374   /* byte 0 indicates if is on or off if 0x02 */
375   /* byte 1 indicates time since is on */
376   /* byte 2 indicates time since is power plugged */
377 
378   if (text2400[0] & 0x02)
379     {
380       return 1;			/* is on */
381     }
382 
383   return 0;			/* is off */
384 }
385 #endif
386