1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 2007 Ilia Sotnikov <hostcc@gmail.com>
3    This file is part of the SANE package.
4 
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 
18    As a special exception, the authors of SANE give permission for
19    additional uses of the libraries contained in this release of SANE.
20 
21    The exception is that, if you link a SANE library with other files
22    to produce an executable, this does not by itself cause the
23    resulting executable to be covered by the GNU General Public
24    License.  Your use of that executable is in no way restricted on
25    account of linking the SANE library code into it.
26 
27    This exception does not, however, invalidate any other reasons why
28    the executable file might be covered by the GNU General Public
29    License.
30 
31    If you submit changes to SANE to the maintainers to be included in
32    a subsequent release, you agree by submitting the changes that
33    those changes may be distributed with this exception intact.
34 
35    If you write modifications of your own for SANE, it is your choice
36    whether to permit this exception to apply to your modifications.
37    If you do not wish that, delete this exception notice.
38 
39    This file is part of a SANE backend for
40    HP ScanJet 4500C/4570C/5500C/5550C/5590/7650 Scanners
41 */
42 
43 #include "../include/sane/config.h"
44 
45 #include <stdio.h>
46 #include <string.h>
47 #include <errno.h>
48 #ifdef HAVE_NETINET_IN_H
49 # include <netinet/in.h>
50 #endif /* HAVE_NETINET_IN_H */
51 
52 #include "byteorder.h"
53 
54 #include "../include/sane/sanei_debug.h"
55 #include "../include/sane/sanei_usb.h"
56 #include "../include/_stdint.h"
57 #include "hp5590_low.h"
58 
59 /* Debug levels */
60 #define DBG_err         0
61 #define DBG_proc        10
62 #define DBG_usb         50
63 
64 /* Custom assert() macro */
65 #define hp5590_low_assert(exp) if(!(exp)) { \
66   DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\
67   return SANE_STATUS_INVAL; \
68 }
69 
70 /* Structure describing bulk transfer size */
71 struct bulk_size
72 {
73   uint16_t      size;
74   uint8_t       unused;
75 } __attribute__ ((packed));
76 
77 /* Structure describing bulk URB */
78 /* FIXME: Verify according to USB standard */
79 struct usb_in_usb_bulk_setup
80 {
81   uint8_t       bRequestType;
82   uint8_t       bRequest;
83   uint8_t       bEndpoint;
84   uint16_t      unknown;
85   uint16_t      wLength;        /* MSB first */
86   uint8_t       pad;
87 } __attribute__ ((packed));
88 
89 /* Structure describing control URB */
90 struct usb_in_usb_ctrl_setup {
91   uint8_t  bRequestType;
92   uint8_t  bRequest;
93   uint16_t wValue;              /* MSB first */
94   uint16_t wIndex;              /* MSB first */
95   uint16_t wLength;             /* LSB first */
96 } __attribute__ ((packed));
97 
98 /* CORE status flag - ready or not */
99 #define CORE_FLAG_NOT_READY             1 << 1
100 
101 /* Bulk transfers are done in pages, below their respective sizes */
102 #define BULK_WRITE_PAGE_SIZE            0x0f000
103 #define BULK_READ_PAGE_SIZE             0x10000
104 #define ALLOCATE_BULK_READ_PAGES        16      /* 16 * 65536 = 1Mb */
105 
106 /* Structure describing bulk read state, because bulk reads will be done in
107  * pages, but function caller uses its own buffer, whose size is certainly
108  * different. Also, each bulk read page is ACK'ed by special command
109  * so total pages received should be tracked as well
110  */
111 struct bulk_read_state
112 {
113   unsigned char *buffer;
114   unsigned int  buffer_size;
115   unsigned int  bytes_available;
116   unsigned char *buffer_out_ptr;
117   unsigned char *buffer_in_ptr;
118   unsigned int  total_pages;
119   unsigned char *buffer_end_ptr;
120   unsigned int  initialized;
121 };
122 
123 /*******************************************************************************
124  * USB-in-USB: get acknowledge for last USB-in-USB operation
125  *
126  * Parameters
127  * dn - sanei_usb device descriptor
128  *
129  * Returns
130  * SANE_STATUS_GOOD - if correct acknowledge was received
131  * SANE_STATUS_DEVICE_BUSY - otherwise
132  */
133 static SANE_Status
hp5590_get_ack(SANE_Int dn, enum proto_flags proto_flags)134 hp5590_get_ack (SANE_Int dn,
135                 enum proto_flags proto_flags)
136 {
137   uint8_t       status;
138   SANE_Status   ret;
139 
140   /* Bypass reading acknowledge if the device doesn't need it */
141   if (proto_flags & PF_NO_USB_IN_USB_ACK)
142     return SANE_STATUS_GOOD;
143 
144   DBG (DBG_proc, "%s\n", __func__);
145 
146   /* Check if USB-in-USB operation was accepted */
147   ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR,
148                                0x0c, 0x8e, 0x20,
149                                sizeof (status), &status);
150   if (ret != SANE_STATUS_GOOD)
151     {
152       DBG (DBG_err, "%s: USB-in-USB: error getting acknowledge\n",
153            __func__);
154       return ret;
155     }
156 
157   DBG (DBG_usb, "%s: USB-in-USB: accepted\n", __func__);
158 
159   /* Check if we received correct acknowledgment */
160   if (status != 0x01)
161     {
162       DBG (DBG_err, "%s: USB-in-USB: not accepted (status %u)\n",
163            __func__, status);
164       return SANE_STATUS_DEVICE_BUSY;
165     }
166 
167   return SANE_STATUS_GOOD;
168 }
169 
170 /*******************************************************************************
171  * USB-in-USB: get device status
172  *
173  * Parameters
174  * dn - sanei_usb device descriptor
175  *
176  * Returns
177  * SANE_STATUS_GOOD - if correct status was received
178  * SANE_STATUS_DEVICE_BUSY - otherwise
179  */
180 static SANE_Status
hp5590_get_status(SANE_Int dn, __sane_unused__ enum proto_flags proto_flags)181 hp5590_get_status (SANE_Int dn,
182                    __sane_unused__ enum proto_flags proto_flags)
183 {
184   uint8_t status;
185   SANE_Status ret;
186 
187   DBG (DBG_proc, "%s\n", __func__);
188 
189   ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR,
190                                0x0c, 0x8e, 0x00,
191                                sizeof (status), &status);
192   if (ret != SANE_STATUS_GOOD)
193     {
194       DBG (DBG_err, "%s: USB-in-USB: error getting device status\n",
195            __func__);
196       return ret;
197     }
198 
199   /* Check if we received correct status */
200   if (status != 0x00)
201     {
202       DBG (DBG_err, "%s: USB-in-USB: got non-zero device status (status %u)\n",
203            __func__, status);
204       return SANE_STATUS_DEVICE_BUSY;
205     }
206 
207   return SANE_STATUS_GOOD;
208 }
209 
210 /*******************************************************************************
211  * USB-in-USB: sends control message for IN or OUT operation
212  *
213  * Parameters
214  * dn - sanei_usb device descriptor
215  * requesttype, request, value, index - their meanings are similar to
216  * sanei_control_msg()
217  * bytes - pointer to data buffer
218  * size - size of data
219  * core_flags -
220  *  CORE_NONE - no CORE operation will be performed
221  *  CORE_DATA - operation on CORE data will be performed
222  *  CORE_BULK_IN - preparation for bulk IN transfer (not used yet)
223  *  CORE_BULK_OUT - preparation for bulk OUT transfer
224  *
225  * Returns
226  * SANE_STATUS_GOOD - control message was sent w/o any errors
227  * all other SANE_Status values - otherwise
228  */
229 static SANE_Status
hp5590_control_msg(SANE_Int dn, enum proto_flags proto_flags, int requesttype, int request, int value, int index, unsigned char *bytes, int size, int core_flags)230 hp5590_control_msg (SANE_Int dn,
231                     enum proto_flags proto_flags,
232                     int requesttype, int request,
233                     int value, int index, unsigned char *bytes,
234                     int size, int core_flags)
235 {
236   struct usb_in_usb_ctrl_setup  ctrl;
237   SANE_Status                   ret;
238   unsigned int                  len;
239   unsigned char                 *ptr;
240   uint8_t                       ack;
241   uint8_t                       response;
242   unsigned int                  needed_response;
243 
244   DBG (DBG_proc, "%s: USB-in-USB: core data: %s\n",
245        __func__, core_flags & CORE_DATA ? "yes" : "no");
246 
247   hp5590_low_assert (bytes != NULL);
248 
249   /* IN (read) operation will be performed */
250   if (requesttype & USB_DIR_IN)
251     {
252       /* Prepare USB-in-USB control message */
253       memset (&ctrl, 0, sizeof (ctrl));
254       ctrl.bRequestType = 0xc0;
255       ctrl.bRequest = request;
256       ctrl.wValue = htons (value);
257       ctrl.wIndex = htons (index);
258       ctrl.wLength = htole16 (size);
259 
260       DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __func__);
261       /* Send USB-in-USB control message */
262       ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR,
263                                    0x04, 0x8f, 0x00,
264                                    sizeof (ctrl), (unsigned char *) &ctrl);
265       if (ret != SANE_STATUS_GOOD)
266         {
267           DBG (DBG_err, "%s: USB-in-USB: error sending control message\n",
268                __func__);
269           return ret;
270         }
271 
272       /* USB-in-USB: checking acknowledge for control message */
273       ret = hp5590_get_ack (dn, proto_flags);
274       if (ret != SANE_STATUS_GOOD)
275         return ret;
276 
277       len = size;
278       ptr = bytes;
279       /* Data is read in 8 byte portions */
280       while (len)
281         {
282           unsigned int next_packet_size;
283           next_packet_size = 8;
284           if (len < 8)
285             next_packet_size = len;
286 
287           /* Read USB-in-USB data */
288           ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR,
289                                        core_flags & CORE_DATA ? 0x0c : 0x04,
290                                        0x90, 0x00, next_packet_size, ptr);
291           if (ret != SANE_STATUS_GOOD)
292             {
293               DBG (DBG_err, "%s: USB-in-USB: error reading data\n", __func__);
294               return ret;
295             }
296 
297           ptr += next_packet_size;
298           len -= next_packet_size;
299         }
300 
301       /* Confirm data reception */
302       ack = 0;
303       ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR,
304                                    0x0c, 0x8f, 0x00,
305                                    sizeof (ack), &ack);
306       if (ret != SANE_STATUS_GOOD)
307         {
308           DBG (DBG_err, "%s: USB-in-USB: error confirming data reception\n",
309                __func__);
310           return -1;
311         }
312 
313       /* USB-in-USB: checking if confirmation was acknowledged */
314       ret = hp5590_get_ack (dn, proto_flags);
315       if (ret != SANE_STATUS_GOOD)
316         return ret;
317     }
318 
319   /* OUT (write) operation will be performed */
320   if (!(requesttype & USB_DIR_IN))
321     {
322       /* Prepare USB-in-USB control message */
323       memset (&ctrl, 0, sizeof (ctrl));
324       ctrl.bRequestType = 0x40;
325       ctrl.bRequest = request;
326       ctrl.wValue = htons (value);
327       ctrl.wIndex = htons (index);
328       ctrl.wLength = htole16 (size);
329 
330       DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __func__);
331       /* Send USB-in-USB control message */
332       ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR,
333                                    0x04, 0x8f, 0x00,
334                                    sizeof (ctrl), (unsigned char *) &ctrl);
335       if (ret != SANE_STATUS_GOOD)
336         {
337           DBG (DBG_err, "%s: USB-in-USB: error sending control message\n",
338                __func__);
339           return ret;
340         }
341 
342       /* USB-in-USB: checking acknowledge for control message */
343       ret = hp5590_get_ack (dn, proto_flags);
344       if (ret != SANE_STATUS_GOOD)
345         return ret;
346 
347       len = size;
348       ptr = bytes;
349       /* Data is sent in 8 byte portions */
350       while (len)
351         {
352           unsigned int next_packet_size;
353           next_packet_size = 8;
354           if (len < 8)
355             next_packet_size = len;
356 
357           /* Send USB-in-USB data */
358           ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR,
359                                        core_flags & CORE_DATA ? 0x04 : 0x0c,
360                                        0x8f, 0x00, next_packet_size, ptr);
361           if (ret != SANE_STATUS_GOOD)
362             {
363               DBG (DBG_err, "%s: USB-in-USB: error sending data\n", __func__);
364               return ret;
365             }
366 
367           /* CORE data is acknowledged packet by packet */
368           if (core_flags & CORE_DATA)
369             {
370               /* USB-in-USB: checking if data was accepted */
371               ret = hp5590_get_ack (dn, proto_flags);
372               if (ret != SANE_STATUS_GOOD)
373                 return ret;
374             }
375 
376           ptr += next_packet_size;
377           len -= next_packet_size;
378         }
379 
380       /* Normal (non-CORE) data is acknowledged after its full transmission */
381       if (!(core_flags & CORE_DATA))
382         {
383           /* USB-in-USB: checking if data was accepted */
384           ret = hp5590_get_ack (dn, proto_flags);
385           if (ret != SANE_STATUS_GOOD)
386             return ret;
387         }
388 
389       /* Getting  response after data transmission */
390       DBG (DBG_usb, "%s: USB-in-USB: getting response\n", __func__);
391       ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR,
392                                    0x0c, 0x90, 0x00,
393                                    sizeof (response), &response);
394       if (ret != SANE_STATUS_GOOD)
395         {
396           DBG (DBG_err, "%s: USB-in-USB: error getting response\n", __func__);
397           return ret;
398         }
399 
400       /* Necessary response after normal (non-CORE) data is 0x00,
401        * after bulk OUT preparation - 0x24
402        */
403       needed_response = core_flags & CORE_BULK_OUT ? 0x24 : 0x00;
404       if (response == needed_response)
405         DBG (DBG_usb, "%s: USB-in-USB: got correct response\n",
406              __func__);
407 
408       if (response != needed_response)
409         {
410           DBG (DBG_err,
411                "%s: USB-in-USB: invalid response received "
412                "(needed %04x, got %04x)\n",
413                __func__, needed_response, response);
414           return SANE_STATUS_IO_ERROR;
415         }
416 
417       /* Send bulk OUT flags is bulk OUT preparation is performed */
418       if (core_flags & CORE_BULK_OUT)
419         {
420           uint8_t bulk_flags = 0x24;
421           DBG (DBG_usb, "%s: USB-in-USB: sending bulk flags\n",
422                __func__);
423 
424           ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR,
425                                        0x0c, 0x83, 0x00,
426                                        sizeof (bulk_flags), &bulk_flags);
427           if (ret != SANE_STATUS_GOOD)
428             {
429               DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n",
430                    __func__);
431               return ret;
432             }
433 
434           /* USB-in-USB: checking confirmation for bulk flags */
435           ret = hp5590_get_ack (dn, proto_flags);
436           if (ret != SANE_STATUS_GOOD)
437             return ret;
438         }
439     }
440 
441   return SANE_STATUS_GOOD;
442 }
443 
444 /*******************************************************************************
445  * USB-in-USB: verifies last command
446  *
447  * Parameters
448  * dn - sanei_usb device descriptor
449  * cmd - command to verify
450  *
451  * Returns
452  * SANE_STATUS_GOOD - command verified successfully and CORE is ready
453  * SANE_STATUS_IO_ERROR - command verification failed
454  * SANE_STATUS_DEVICE_BUSY - command verified successfully but CORE isn't ready
455  * all other SANE_Status values - otherwise
456  */
457 static SANE_Status
hp5590_verify_last_cmd(SANE_Int dn, enum proto_flags proto_flags, unsigned int cmd)458 hp5590_verify_last_cmd (SANE_Int dn,
459                         enum proto_flags proto_flags,
460                         unsigned int cmd)
461 {
462   uint16_t      verify_cmd;
463   unsigned int  last_cmd;
464   unsigned int  core_status;
465   SANE_Status   ret;
466 
467   DBG (3, "%s: USB-in-USB: command verification requested\n",
468        __func__);
469 
470   /* Read last command along with CORE status */
471   ret = hp5590_control_msg (dn,
472                             proto_flags,
473                             USB_DIR_IN,
474                             0x04, 0xc5, 0x00,
475                             (unsigned char *) &verify_cmd,
476                             sizeof (verify_cmd), CORE_NONE);
477   if (ret != SANE_STATUS_GOOD)
478     return ret;
479 
480   verify_cmd = le16toh (verify_cmd); /* Response is LSB first */
481 
482   /* Last command - minor byte */
483   last_cmd = verify_cmd & 0xff;
484   /* CORE status - major byte */
485   core_status = (verify_cmd & 0xff00) >> 8;
486 
487   /* Verify last command */
488   DBG (DBG_usb, "%s: USB-in-USB: command verification %04x, "
489        "last command: %04x, core status: %04x\n",
490        __func__, verify_cmd, last_cmd, core_status);
491   if ((cmd & 0x00ff) != last_cmd)
492     {
493       DBG (DBG_err, "%s: USB-in-USB: command verification failed: "
494            "expected 0x%04x, got 0x%04x\n",
495            __func__, cmd, last_cmd);
496       return SANE_STATUS_IO_ERROR;
497     }
498 
499   DBG (DBG_usb, "%s: USB-in-USB: command verified successfully\n",
500        __func__);
501 
502   /* Return value depends on CORE status */
503   return core_status & CORE_FLAG_NOT_READY ?
504     SANE_STATUS_DEVICE_BUSY : SANE_STATUS_GOOD;
505 }
506 
507 /*******************************************************************************
508  * USB-in-USB: send command (convenience wrapper around hp5590_control_msg())
509  *
510  * Parameters
511  * dn - sanei_usb device descriptor
512  * requesttype, request, value, index - their meanings are similar to
513  * sanei_control_msg()
514  * bytes - pointer to data buffer
515  * size - size of data
516  * core_flags -
517  *  CORE_NONE - no CORE operation will be performed
518  *  CORE_DATA - operation on CORE data will be performed
519  *  CORE_BULK_IN - preparation for bulk IN transfer (not used yet)
520  *  CORE_BULK_OUT - preparation for bulk OUT transfer
521  *
522  * Returns
523  * SANE_STATUS_GOOD - command was sent (and possible verified) w/o any errors
524  * all other SANE_Status values - otherwise
525  */
526 static SANE_Status
hp5590_cmd(SANE_Int dn, enum proto_flags proto_flags, unsigned int flags, unsigned int cmd, unsigned char *data, unsigned int size, unsigned int core_flags)527 hp5590_cmd (SANE_Int dn,
528             enum proto_flags proto_flags,
529             unsigned int flags,
530             unsigned int cmd, unsigned char *data, unsigned int size,
531             unsigned int core_flags)
532 {
533   SANE_Status ret;
534 
535   DBG (3, "%s: USB-in-USB: command : %04x\n", __func__, cmd);
536 
537   ret = hp5590_control_msg (dn,
538                             proto_flags,
539                             flags & CMD_IN ? USB_DIR_IN : USB_DIR_OUT,
540                             0x04, cmd, 0x00, data, size, core_flags);
541   if (ret != SANE_STATUS_GOOD)
542     return ret;
543 
544   ret = SANE_STATUS_GOOD;
545   /* Verify last command if requested */
546   if (flags & CMD_VERIFY)
547     {
548       ret = hp5590_verify_last_cmd (dn, proto_flags, cmd);
549     }
550 
551   return ret;
552 }
553 
554 /*******************************************************************************
555  * USB-in-USB: initialized bulk read state
556  *
557  * Parameters
558  * state - pointer to a pointer for initialized state
559  *
560  * Returns
561  * SANE_STATUS_GOOD - if state was initialized successfully
562  * SANE_STATUS_NO_MEM - memory allocation failed
563  */
564 static SANE_Status
hp5590_low_init_bulk_read_state(void **state)565 hp5590_low_init_bulk_read_state (void **state)
566 {
567   struct bulk_read_state *bulk_read_state;
568 
569   DBG (3, "%s: USB-in-USB: initializing bulk read state\n", __func__);
570 
571   hp5590_low_assert (state != NULL);
572 
573   bulk_read_state = malloc (sizeof (struct bulk_read_state));
574   if (!bulk_read_state)
575     return SANE_STATUS_NO_MEM;
576   memset (bulk_read_state, 0, sizeof (struct bulk_read_state));
577 
578   bulk_read_state->buffer = malloc (ALLOCATE_BULK_READ_PAGES
579                                     * BULK_READ_PAGE_SIZE);
580   if (!bulk_read_state->buffer)
581     {
582       DBG (DBG_err, "%s: Memory allocation failed for %u bytes\n",
583            __func__, ALLOCATE_BULK_READ_PAGES * BULK_READ_PAGE_SIZE);
584       return SANE_STATUS_NO_MEM;
585     }
586   bulk_read_state->buffer_size = ALLOCATE_BULK_READ_PAGES
587                                  * BULK_READ_PAGE_SIZE;
588   bulk_read_state->bytes_available = 0;
589   bulk_read_state->buffer_out_ptr = bulk_read_state->buffer;
590   bulk_read_state->buffer_in_ptr = bulk_read_state->buffer;
591   bulk_read_state->total_pages = 0;
592   bulk_read_state->buffer_end_ptr = bulk_read_state->buffer
593                                     + bulk_read_state->buffer_size;
594   bulk_read_state->initialized = 1;
595 
596   *state = bulk_read_state;
597   return SANE_STATUS_GOOD;
598 }
599 
600 /*******************************************************************************
601  * USB-in-USB: free bulk read state
602  *
603  * Parameters
604  * state - pointer to a pointer to bulk read state
605  *
606  * Returns
607  * SANE_STATUS_GOOD - bulk read state freed successfully
608  */
609 static SANE_Status
hp5590_low_free_bulk_read_state(void **state)610 hp5590_low_free_bulk_read_state (void **state)
611 {
612   struct bulk_read_state *bulk_read_state;
613 
614   DBG (3, "%s\n", __func__);
615 
616   hp5590_low_assert (state != NULL);
617   /* Just return if NULL bulk read state was given */
618   if (*state == NULL)
619     return SANE_STATUS_GOOD;
620 
621   bulk_read_state = *state;
622 
623   DBG (3, "%s: USB-in-USB: freeing bulk read state\n", __func__);
624 
625   free (bulk_read_state->buffer);
626   bulk_read_state->buffer = NULL;
627   free (bulk_read_state);
628   *state = NULL;
629 
630   return SANE_STATUS_GOOD;
631 }
632 
633 /* FIXME: perhaps needs to be converted to use hp5590_control_msg() */
634 /*******************************************************************************
635  * USB-in-USB: bulk read
636  *
637  * Parameters
638  * dn - sanei_usb device descriptor
639  * bytes - pointer to data buffer
640  * size - size of data to read
641  * state - pointer to initialized bulk read state structure
642  */
643 static SANE_Status
hp5590_bulk_read(SANE_Int dn, enum proto_flags proto_flags, unsigned char *bytes, unsigned int size, void *state)644 hp5590_bulk_read (SANE_Int dn,
645                   enum proto_flags proto_flags,
646                   unsigned char *bytes, unsigned int size,
647                   void *state)
648 {
649   struct usb_in_usb_bulk_setup  ctrl;
650   SANE_Status                   ret;
651   unsigned int                  next_pages;
652   uint8_t                       bulk_flags;
653   size_t                        next_portion;
654   struct bulk_read_state        *bulk_read_state;
655   unsigned int                  bytes_until_buffer_end;
656 
657   DBG (3, "%s\n", __func__);
658 
659   hp5590_low_assert (state != NULL);
660   hp5590_low_assert (bytes != NULL);
661 
662   bulk_read_state = state;
663   if (bulk_read_state->initialized == 0)
664     {
665       DBG (DBG_err, "%s: USB-in-USB: bulk read state not initialized\n",
666            __func__);
667       return SANE_STATUS_INVAL;
668     }
669 
670   memset (bytes, 0, size);
671 
672   /* Check if requested data would fit into the buffer */
673   if (size > bulk_read_state->buffer_size)
674     {
675       DBG (DBG_err, "Data requested won't fit in the bulk read buffer "
676            "(requested: %u, buffer size: %u\n", size,
677            bulk_read_state->buffer_size);
678       return SANE_STATUS_NO_MEM;
679     }
680 
681   /* Read data until requested size of data will be received */
682   while (bulk_read_state->bytes_available < size)
683     {
684       DBG (DBG_usb, "%s: USB-in-USB: not enough data in buffer available "
685            "(available: %u, requested: %u)\n",
686            __func__, bulk_read_state->bytes_available, size);
687 
688       /* IMPORTANT! 'next_pages' means 'request and receive next_pages pages in
689        * one bulk transfer request '. Windows driver uses 4 pages between each
690        * request.  The more pages are received between requests the less the
691        * scanner does scan head re-positioning thus improving scanning speed.
692        * On the other hand, scanner expects that all of the requested pages
693        * will be received immediately after the request. In case when a
694        * frontend will have a delay between reads we will get bulk transfer
695        * timeout sooner or later.
696        * Having next_pages = 1 is the most safe case.
697        */
698       next_pages = 1;
699       /* Count all received pages to calculate when we will need to send
700        * another bulk request
701        */
702       bulk_read_state->total_pages++;
703       DBG (DBG_usb, "%s: USB-in-USB: total pages done: %u\n",
704            __func__, bulk_read_state->total_pages);
705 
706       /* Send another bulk request for 'next_pages' before first
707        * page or next necessary one
708        */
709       if (   bulk_read_state->total_pages == 1
710           || bulk_read_state->total_pages % next_pages == 0)
711         {
712           /* Send bulk flags */
713           DBG (DBG_usb, "%s: USB-in-USB: sending USB-in-USB bulk flags\n",
714                __func__);
715           bulk_flags = 0x24;
716           ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR,
717                                        0x0c, 0x83, 0x00,
718                                        sizeof (bulk_flags), &bulk_flags);
719           if (ret != SANE_STATUS_GOOD)
720             {
721               DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n",
722                    __func__);
723               return ret;
724             }
725 
726           /* USB-in-USB: checking confirmation for bulk flags\n" */
727           ret = hp5590_get_ack (dn, proto_flags);
728           if (ret != SANE_STATUS_GOOD)
729             return ret;
730 
731           /* Prepare bulk read request */
732           memset (&ctrl, 0, sizeof (ctrl));
733           ctrl.bRequestType = 0x00;
734           ctrl.bEndpoint = 0x82;
735           ctrl.wLength = htons (next_pages);
736 
737           /* Send bulk read request */
738           DBG (DBG_usb, "%s: USB-in-USB: sending control msg for bulk\n",
739                __func__);
740           ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR,
741                                        0x04, 0x82, 0x00,
742                                        sizeof (ctrl),
743                                        (unsigned char *) &ctrl);
744           if (ret != SANE_STATUS_GOOD)
745             {
746               DBG (DBG_err, "%s: USB-in-USB: error sending control msg\n",
747                    __func__);
748               return ret;
749             }
750 
751           /* USB-in-USB: checking if control msg was accepted */
752           ret = hp5590_get_ack (dn, proto_flags);
753           if (ret != SANE_STATUS_GOOD)
754             return ret;
755         }
756 
757       next_portion = BULK_READ_PAGE_SIZE;
758       /* Check if next page will fit into the buffer */
759       if (bulk_read_state->buffer_size
760           - bulk_read_state->bytes_available < next_portion)
761         {
762           DBG (DBG_err, "%s: USB-in-USB: buffer too small\n", __func__);
763           return SANE_STATUS_NO_MEM;
764         }
765 
766       /* Bulk read next page */
767       DBG (DBG_usb, "%s: USB-in-USB: bulk reading %lu bytes\n",
768            __func__, (u_long) next_portion);
769       ret = sanei_usb_read_bulk (dn,
770                                  bulk_read_state->buffer_in_ptr,
771                                  &next_portion);
772       if (ret != SANE_STATUS_GOOD)
773         {
774           if (ret == SANE_STATUS_EOF)
775             return ret;
776           DBG (DBG_err, "%s: USB-in-USB: error during bulk read: %s\n",
777                __func__, sane_strstatus (ret));
778           return ret;
779         }
780 
781       /* Check if we received the same amount of data as requested */
782       if (next_portion != BULK_READ_PAGE_SIZE)
783         {
784           DBG (DBG_err, "%s: USB-in-USB: incomplete bulk read "
785                "(requested %u bytes, got %lu bytes)\n",
786                __func__, BULK_READ_PAGE_SIZE, (u_long) next_portion);
787           return SANE_STATUS_IO_ERROR;
788         }
789 
790       /* Move pointers to the next position */
791       bulk_read_state->buffer_in_ptr += next_portion;
792 
793       /* Check for the end of the buffer */
794       if (bulk_read_state->buffer_in_ptr > bulk_read_state->buffer_end_ptr)
795         {
796           DBG (DBG_err,
797                "%s: USB-in-USB: attempted to access over the end of buffer "
798                "(in_ptr: %p, end_ptr: %p, ptr: %p, buffer size: %u\n",
799                __func__, (void *) bulk_read_state->buffer_in_ptr,
800                (void *) bulk_read_state->buffer_end_ptr,
801                (void *) bulk_read_state->buffer,
802                bulk_read_state->buffer_size);
803           return SANE_STATUS_NO_MEM;
804         }
805 
806       /* Check for buffer pointer wrapping */
807       if (bulk_read_state->buffer_in_ptr == bulk_read_state->buffer_end_ptr)
808         {
809           DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while writing\n",
810                __func__);
811           bulk_read_state->buffer_in_ptr = bulk_read_state->buffer;
812         }
813 
814       /* Count the amount of data we read */
815       bulk_read_state->bytes_available += next_portion;
816     }
817 
818   /* Transfer requested amount of data to the caller */
819   DBG (DBG_usb, "%s: USB-in-USB: data in bulk buffer is available "
820        "(requested %u bytes, available %u bytes)\n",
821        __func__, size, bulk_read_state->bytes_available);
822 
823   /* Check for buffer pointer wrapping */
824   bytes_until_buffer_end = bulk_read_state->buffer_end_ptr
825     - bulk_read_state->buffer_out_ptr;
826   if (bytes_until_buffer_end <= size)
827     {
828       /* First buffer part */
829       DBG (DBG_usb, "%s: USB-in-USB: reached bulk read buffer end\n", __func__);
830       memcpy (bytes, bulk_read_state->buffer_out_ptr, bytes_until_buffer_end);
831       bulk_read_state->buffer_out_ptr = bulk_read_state->buffer;
832       /* And second part (if any) */
833       if (bytes_until_buffer_end < size)
834         {
835           DBG (DBG_usb, "%s: USB-in-USB: giving 2nd buffer part\n", __func__);
836           memcpy (bytes + bytes_until_buffer_end,
837                   bulk_read_state->buffer_out_ptr,
838                   size - bytes_until_buffer_end);
839           bulk_read_state->buffer_out_ptr += size - bytes_until_buffer_end;
840         }
841     }
842   else
843     {
844       /* The data is in one buffer part (w/o wrapping) */
845       memcpy (bytes, bulk_read_state->buffer_out_ptr, size);
846       bulk_read_state->buffer_out_ptr += size;
847       if (bulk_read_state->buffer_out_ptr == bulk_read_state->buffer_end_ptr)
848         {
849           DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while reading\n",
850                __func__);
851           bulk_read_state->buffer_out_ptr = bulk_read_state->buffer;
852         }
853     }
854 
855   /* Count the amount of data transferred to the caller */
856   bulk_read_state->bytes_available -= size;
857 
858   return SANE_STATUS_GOOD;
859 }
860 
861 /*******************************************************************************
862  * USB-in-USB: bulk write
863  *
864  * Parameters
865  * dn - sanei_usb device descriptor
866  * cmd - command for bulk write operation
867  * bytes - pointer to data buffer
868  * size - size of data
869  *
870  * Returns
871  * SANE_STATUS_GOOD - all data transferred successfully
872  * all other SANE_Status value - otherwise
873  */
874 static SANE_Status
hp5590_bulk_write(SANE_Int dn, enum proto_flags proto_flags, int cmd, unsigned char *bytes, unsigned int size)875 hp5590_bulk_write (SANE_Int dn,
876                    enum proto_flags proto_flags,
877                    int cmd, unsigned char *bytes,
878                    unsigned int size)
879 {
880   struct usb_in_usb_bulk_setup  ctrl;
881   SANE_Status                   ret;
882   struct bulk_size              bulk_size;
883 
884   unsigned int len;
885   unsigned char *ptr;
886   size_t next_portion;
887 
888   DBG (3, "%s: USB-in-USB: command: %04x, size %u\n", __func__, cmd,
889        size);
890 
891   hp5590_low_assert (bytes != NULL);
892 
893   /* Prepare bulk write request */
894   memset (&bulk_size, 0, sizeof (bulk_size));
895   /* Counted in page size */
896   bulk_size.size = size / BULK_WRITE_PAGE_SIZE;
897 
898   /* Send bulk write request */
899   DBG (3, "%s: USB-in-USB: total %u pages (each of %u bytes)\n",
900        __func__, bulk_size.size, BULK_WRITE_PAGE_SIZE);
901   ret = hp5590_control_msg (dn,
902                             proto_flags,
903                             USB_DIR_OUT,
904                             0x04, cmd, 0,
905                             (unsigned char *) &bulk_size, sizeof (bulk_size),
906                             CORE_DATA | CORE_BULK_OUT);
907   if (ret != SANE_STATUS_GOOD)
908     return ret;
909 
910   len = size;
911   ptr = bytes;
912 
913   /* Send all data in pages */
914   while (len)
915     {
916       next_portion = BULK_WRITE_PAGE_SIZE;
917       if (len < next_portion)
918         next_portion = len;
919 
920       DBG (3, "%s: USB-in-USB: next portion %lu bytes\n",
921            __func__, (u_long) next_portion);
922 
923       /* Prepare bulk write request */
924       memset (&ctrl, 0, sizeof (ctrl));
925       ctrl.bRequestType = 0x01;
926       ctrl.bEndpoint = 0x82;
927       ctrl.wLength = htons (next_portion);
928 
929       /* Send bulk write request */
930       ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR,
931                                    0x04, 0x82, 0,
932                                    sizeof (ctrl), (unsigned char *) &ctrl);
933       if (ret != SANE_STATUS_GOOD)
934         return ret;
935 
936       /* USB-in-USB: checking if command was accepted */
937       ret = hp5590_get_ack (dn, proto_flags);
938       if (ret != SANE_STATUS_GOOD)
939         return ret;
940 
941       /* Write bulk data */
942       DBG (3, "%s: USB-in-USB: bulk writing %lu bytes\n",
943            __func__, (u_long) next_portion);
944       ret = sanei_usb_write_bulk (dn, ptr, &next_portion);
945       if (ret != SANE_STATUS_GOOD)
946         {
947           /* Treast EOF as successful result */
948           if (ret == SANE_STATUS_EOF)
949             break;
950           DBG (DBG_err, "%s: USB-in-USB: error during bulk write: %s\n",
951                __func__, sane_strstatus (ret));
952           return ret;
953         }
954 
955       /* Move to the next page */
956       len -= next_portion;
957       ptr += next_portion;
958     }
959 
960   /* Verify bulk command */
961   return hp5590_verify_last_cmd (dn, proto_flags, cmd);
962 }
963 /* vim: sw=2 ts=8
964  */
965