1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci Copyright (C) 2007 Ilia Sotnikov <hostcc@gmail.com> 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 40141cc406Sopenharmony_ci HP ScanJet 4500C/4570C/5500C/5550C/5590/7650 Scanners 41141cc406Sopenharmony_ci*/ 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci#include "../include/sane/config.h" 44141cc406Sopenharmony_ci 45141cc406Sopenharmony_ci#include <stdio.h> 46141cc406Sopenharmony_ci#include <string.h> 47141cc406Sopenharmony_ci#include <errno.h> 48141cc406Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 49141cc406Sopenharmony_ci# include <netinet/in.h> 50141cc406Sopenharmony_ci#endif /* HAVE_NETINET_IN_H */ 51141cc406Sopenharmony_ci 52141cc406Sopenharmony_ci#include "byteorder.h" 53141cc406Sopenharmony_ci 54141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h" 55141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 56141cc406Sopenharmony_ci#include "../include/_stdint.h" 57141cc406Sopenharmony_ci#include "hp5590_low.h" 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci/* Debug levels */ 60141cc406Sopenharmony_ci#define DBG_err 0 61141cc406Sopenharmony_ci#define DBG_proc 10 62141cc406Sopenharmony_ci#define DBG_usb 50 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_ci/* Custom assert() macro */ 65141cc406Sopenharmony_ci#define hp5590_low_assert(exp) if(!(exp)) { \ 66141cc406Sopenharmony_ci DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ 67141cc406Sopenharmony_ci return SANE_STATUS_INVAL; \ 68141cc406Sopenharmony_ci} 69141cc406Sopenharmony_ci 70141cc406Sopenharmony_ci/* Structure describing bulk transfer size */ 71141cc406Sopenharmony_cistruct bulk_size 72141cc406Sopenharmony_ci{ 73141cc406Sopenharmony_ci uint16_t size; 74141cc406Sopenharmony_ci uint8_t unused; 75141cc406Sopenharmony_ci} __attribute__ ((packed)); 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ci/* Structure describing bulk URB */ 78141cc406Sopenharmony_ci/* FIXME: Verify according to USB standard */ 79141cc406Sopenharmony_cistruct usb_in_usb_bulk_setup 80141cc406Sopenharmony_ci{ 81141cc406Sopenharmony_ci uint8_t bRequestType; 82141cc406Sopenharmony_ci uint8_t bRequest; 83141cc406Sopenharmony_ci uint8_t bEndpoint; 84141cc406Sopenharmony_ci uint16_t unknown; 85141cc406Sopenharmony_ci uint16_t wLength; /* MSB first */ 86141cc406Sopenharmony_ci uint8_t pad; 87141cc406Sopenharmony_ci} __attribute__ ((packed)); 88141cc406Sopenharmony_ci 89141cc406Sopenharmony_ci/* Structure describing control URB */ 90141cc406Sopenharmony_cistruct usb_in_usb_ctrl_setup { 91141cc406Sopenharmony_ci uint8_t bRequestType; 92141cc406Sopenharmony_ci uint8_t bRequest; 93141cc406Sopenharmony_ci uint16_t wValue; /* MSB first */ 94141cc406Sopenharmony_ci uint16_t wIndex; /* MSB first */ 95141cc406Sopenharmony_ci uint16_t wLength; /* LSB first */ 96141cc406Sopenharmony_ci} __attribute__ ((packed)); 97141cc406Sopenharmony_ci 98141cc406Sopenharmony_ci/* CORE status flag - ready or not */ 99141cc406Sopenharmony_ci#define CORE_FLAG_NOT_READY 1 << 1 100141cc406Sopenharmony_ci 101141cc406Sopenharmony_ci/* Bulk transfers are done in pages, below their respective sizes */ 102141cc406Sopenharmony_ci#define BULK_WRITE_PAGE_SIZE 0x0f000 103141cc406Sopenharmony_ci#define BULK_READ_PAGE_SIZE 0x10000 104141cc406Sopenharmony_ci#define ALLOCATE_BULK_READ_PAGES 16 /* 16 * 65536 = 1Mb */ 105141cc406Sopenharmony_ci 106141cc406Sopenharmony_ci/* Structure describing bulk read state, because bulk reads will be done in 107141cc406Sopenharmony_ci * pages, but function caller uses its own buffer, whose size is certainly 108141cc406Sopenharmony_ci * different. Also, each bulk read page is ACK'ed by special command 109141cc406Sopenharmony_ci * so total pages received should be tracked as well 110141cc406Sopenharmony_ci */ 111141cc406Sopenharmony_cistruct bulk_read_state 112141cc406Sopenharmony_ci{ 113141cc406Sopenharmony_ci unsigned char *buffer; 114141cc406Sopenharmony_ci unsigned int buffer_size; 115141cc406Sopenharmony_ci unsigned int bytes_available; 116141cc406Sopenharmony_ci unsigned char *buffer_out_ptr; 117141cc406Sopenharmony_ci unsigned char *buffer_in_ptr; 118141cc406Sopenharmony_ci unsigned int total_pages; 119141cc406Sopenharmony_ci unsigned char *buffer_end_ptr; 120141cc406Sopenharmony_ci unsigned int initialized; 121141cc406Sopenharmony_ci}; 122141cc406Sopenharmony_ci 123141cc406Sopenharmony_ci/******************************************************************************* 124141cc406Sopenharmony_ci * USB-in-USB: get acknowledge for last USB-in-USB operation 125141cc406Sopenharmony_ci * 126141cc406Sopenharmony_ci * Parameters 127141cc406Sopenharmony_ci * dn - sanei_usb device descriptor 128141cc406Sopenharmony_ci * 129141cc406Sopenharmony_ci * Returns 130141cc406Sopenharmony_ci * SANE_STATUS_GOOD - if correct acknowledge was received 131141cc406Sopenharmony_ci * SANE_STATUS_DEVICE_BUSY - otherwise 132141cc406Sopenharmony_ci */ 133141cc406Sopenharmony_cistatic SANE_Status 134141cc406Sopenharmony_cihp5590_get_ack (SANE_Int dn, 135141cc406Sopenharmony_ci enum proto_flags proto_flags) 136141cc406Sopenharmony_ci{ 137141cc406Sopenharmony_ci uint8_t status; 138141cc406Sopenharmony_ci SANE_Status ret; 139141cc406Sopenharmony_ci 140141cc406Sopenharmony_ci /* Bypass reading acknowledge if the device doesn't need it */ 141141cc406Sopenharmony_ci if (proto_flags & PF_NO_USB_IN_USB_ACK) 142141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 143141cc406Sopenharmony_ci 144141cc406Sopenharmony_ci DBG (DBG_proc, "%s\n", __func__); 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_ci /* Check if USB-in-USB operation was accepted */ 147141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, 148141cc406Sopenharmony_ci 0x0c, 0x8e, 0x20, 149141cc406Sopenharmony_ci sizeof (status), &status); 150141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 151141cc406Sopenharmony_ci { 152141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error getting acknowledge\n", 153141cc406Sopenharmony_ci __func__); 154141cc406Sopenharmony_ci return ret; 155141cc406Sopenharmony_ci } 156141cc406Sopenharmony_ci 157141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: accepted\n", __func__); 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci /* Check if we received correct acknowledgment */ 160141cc406Sopenharmony_ci if (status != 0x01) 161141cc406Sopenharmony_ci { 162141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: not accepted (status %u)\n", 163141cc406Sopenharmony_ci __func__, status); 164141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 165141cc406Sopenharmony_ci } 166141cc406Sopenharmony_ci 167141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 168141cc406Sopenharmony_ci} 169141cc406Sopenharmony_ci 170141cc406Sopenharmony_ci/******************************************************************************* 171141cc406Sopenharmony_ci * USB-in-USB: get device status 172141cc406Sopenharmony_ci * 173141cc406Sopenharmony_ci * Parameters 174141cc406Sopenharmony_ci * dn - sanei_usb device descriptor 175141cc406Sopenharmony_ci * 176141cc406Sopenharmony_ci * Returns 177141cc406Sopenharmony_ci * SANE_STATUS_GOOD - if correct status was received 178141cc406Sopenharmony_ci * SANE_STATUS_DEVICE_BUSY - otherwise 179141cc406Sopenharmony_ci */ 180141cc406Sopenharmony_cistatic SANE_Status 181141cc406Sopenharmony_cihp5590_get_status (SANE_Int dn, 182141cc406Sopenharmony_ci __sane_unused__ enum proto_flags proto_flags) 183141cc406Sopenharmony_ci{ 184141cc406Sopenharmony_ci uint8_t status; 185141cc406Sopenharmony_ci SANE_Status ret; 186141cc406Sopenharmony_ci 187141cc406Sopenharmony_ci DBG (DBG_proc, "%s\n", __func__); 188141cc406Sopenharmony_ci 189141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, 190141cc406Sopenharmony_ci 0x0c, 0x8e, 0x00, 191141cc406Sopenharmony_ci sizeof (status), &status); 192141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 193141cc406Sopenharmony_ci { 194141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error getting device status\n", 195141cc406Sopenharmony_ci __func__); 196141cc406Sopenharmony_ci return ret; 197141cc406Sopenharmony_ci } 198141cc406Sopenharmony_ci 199141cc406Sopenharmony_ci /* Check if we received correct status */ 200141cc406Sopenharmony_ci if (status != 0x00) 201141cc406Sopenharmony_ci { 202141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: got non-zero device status (status %u)\n", 203141cc406Sopenharmony_ci __func__, status); 204141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 205141cc406Sopenharmony_ci } 206141cc406Sopenharmony_ci 207141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 208141cc406Sopenharmony_ci} 209141cc406Sopenharmony_ci 210141cc406Sopenharmony_ci/******************************************************************************* 211141cc406Sopenharmony_ci * USB-in-USB: sends control message for IN or OUT operation 212141cc406Sopenharmony_ci * 213141cc406Sopenharmony_ci * Parameters 214141cc406Sopenharmony_ci * dn - sanei_usb device descriptor 215141cc406Sopenharmony_ci * requesttype, request, value, index - their meanings are similar to 216141cc406Sopenharmony_ci * sanei_control_msg() 217141cc406Sopenharmony_ci * bytes - pointer to data buffer 218141cc406Sopenharmony_ci * size - size of data 219141cc406Sopenharmony_ci * core_flags - 220141cc406Sopenharmony_ci * CORE_NONE - no CORE operation will be performed 221141cc406Sopenharmony_ci * CORE_DATA - operation on CORE data will be performed 222141cc406Sopenharmony_ci * CORE_BULK_IN - preparation for bulk IN transfer (not used yet) 223141cc406Sopenharmony_ci * CORE_BULK_OUT - preparation for bulk OUT transfer 224141cc406Sopenharmony_ci * 225141cc406Sopenharmony_ci * Returns 226141cc406Sopenharmony_ci * SANE_STATUS_GOOD - control message was sent w/o any errors 227141cc406Sopenharmony_ci * all other SANE_Status values - otherwise 228141cc406Sopenharmony_ci */ 229141cc406Sopenharmony_cistatic SANE_Status 230141cc406Sopenharmony_cihp5590_control_msg (SANE_Int dn, 231141cc406Sopenharmony_ci enum proto_flags proto_flags, 232141cc406Sopenharmony_ci int requesttype, int request, 233141cc406Sopenharmony_ci int value, int index, unsigned char *bytes, 234141cc406Sopenharmony_ci int size, int core_flags) 235141cc406Sopenharmony_ci{ 236141cc406Sopenharmony_ci struct usb_in_usb_ctrl_setup ctrl; 237141cc406Sopenharmony_ci SANE_Status ret; 238141cc406Sopenharmony_ci unsigned int len; 239141cc406Sopenharmony_ci unsigned char *ptr; 240141cc406Sopenharmony_ci uint8_t ack; 241141cc406Sopenharmony_ci uint8_t response; 242141cc406Sopenharmony_ci unsigned int needed_response; 243141cc406Sopenharmony_ci 244141cc406Sopenharmony_ci DBG (DBG_proc, "%s: USB-in-USB: core data: %s\n", 245141cc406Sopenharmony_ci __func__, core_flags & CORE_DATA ? "yes" : "no"); 246141cc406Sopenharmony_ci 247141cc406Sopenharmony_ci hp5590_low_assert (bytes != NULL); 248141cc406Sopenharmony_ci 249141cc406Sopenharmony_ci /* IN (read) operation will be performed */ 250141cc406Sopenharmony_ci if (requesttype & USB_DIR_IN) 251141cc406Sopenharmony_ci { 252141cc406Sopenharmony_ci /* Prepare USB-in-USB control message */ 253141cc406Sopenharmony_ci memset (&ctrl, 0, sizeof (ctrl)); 254141cc406Sopenharmony_ci ctrl.bRequestType = 0xc0; 255141cc406Sopenharmony_ci ctrl.bRequest = request; 256141cc406Sopenharmony_ci ctrl.wValue = htons (value); 257141cc406Sopenharmony_ci ctrl.wIndex = htons (index); 258141cc406Sopenharmony_ci ctrl.wLength = htole16 (size); 259141cc406Sopenharmony_ci 260141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __func__); 261141cc406Sopenharmony_ci /* Send USB-in-USB control message */ 262141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 263141cc406Sopenharmony_ci 0x04, 0x8f, 0x00, 264141cc406Sopenharmony_ci sizeof (ctrl), (unsigned char *) &ctrl); 265141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 266141cc406Sopenharmony_ci { 267141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error sending control message\n", 268141cc406Sopenharmony_ci __func__); 269141cc406Sopenharmony_ci return ret; 270141cc406Sopenharmony_ci } 271141cc406Sopenharmony_ci 272141cc406Sopenharmony_ci /* USB-in-USB: checking acknowledge for control message */ 273141cc406Sopenharmony_ci ret = hp5590_get_ack (dn, proto_flags); 274141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 275141cc406Sopenharmony_ci return ret; 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci len = size; 278141cc406Sopenharmony_ci ptr = bytes; 279141cc406Sopenharmony_ci /* Data is read in 8 byte portions */ 280141cc406Sopenharmony_ci while (len) 281141cc406Sopenharmony_ci { 282141cc406Sopenharmony_ci unsigned int next_packet_size; 283141cc406Sopenharmony_ci next_packet_size = 8; 284141cc406Sopenharmony_ci if (len < 8) 285141cc406Sopenharmony_ci next_packet_size = len; 286141cc406Sopenharmony_ci 287141cc406Sopenharmony_ci /* Read USB-in-USB data */ 288141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, 289141cc406Sopenharmony_ci core_flags & CORE_DATA ? 0x0c : 0x04, 290141cc406Sopenharmony_ci 0x90, 0x00, next_packet_size, ptr); 291141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 292141cc406Sopenharmony_ci { 293141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error reading data\n", __func__); 294141cc406Sopenharmony_ci return ret; 295141cc406Sopenharmony_ci } 296141cc406Sopenharmony_ci 297141cc406Sopenharmony_ci ptr += next_packet_size; 298141cc406Sopenharmony_ci len -= next_packet_size; 299141cc406Sopenharmony_ci } 300141cc406Sopenharmony_ci 301141cc406Sopenharmony_ci /* Confirm data reception */ 302141cc406Sopenharmony_ci ack = 0; 303141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 304141cc406Sopenharmony_ci 0x0c, 0x8f, 0x00, 305141cc406Sopenharmony_ci sizeof (ack), &ack); 306141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 307141cc406Sopenharmony_ci { 308141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error confirming data reception\n", 309141cc406Sopenharmony_ci __func__); 310141cc406Sopenharmony_ci return -1; 311141cc406Sopenharmony_ci } 312141cc406Sopenharmony_ci 313141cc406Sopenharmony_ci /* USB-in-USB: checking if confirmation was acknowledged */ 314141cc406Sopenharmony_ci ret = hp5590_get_ack (dn, proto_flags); 315141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 316141cc406Sopenharmony_ci return ret; 317141cc406Sopenharmony_ci } 318141cc406Sopenharmony_ci 319141cc406Sopenharmony_ci /* OUT (write) operation will be performed */ 320141cc406Sopenharmony_ci if (!(requesttype & USB_DIR_IN)) 321141cc406Sopenharmony_ci { 322141cc406Sopenharmony_ci /* Prepare USB-in-USB control message */ 323141cc406Sopenharmony_ci memset (&ctrl, 0, sizeof (ctrl)); 324141cc406Sopenharmony_ci ctrl.bRequestType = 0x40; 325141cc406Sopenharmony_ci ctrl.bRequest = request; 326141cc406Sopenharmony_ci ctrl.wValue = htons (value); 327141cc406Sopenharmony_ci ctrl.wIndex = htons (index); 328141cc406Sopenharmony_ci ctrl.wLength = htole16 (size); 329141cc406Sopenharmony_ci 330141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __func__); 331141cc406Sopenharmony_ci /* Send USB-in-USB control message */ 332141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 333141cc406Sopenharmony_ci 0x04, 0x8f, 0x00, 334141cc406Sopenharmony_ci sizeof (ctrl), (unsigned char *) &ctrl); 335141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 336141cc406Sopenharmony_ci { 337141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error sending control message\n", 338141cc406Sopenharmony_ci __func__); 339141cc406Sopenharmony_ci return ret; 340141cc406Sopenharmony_ci } 341141cc406Sopenharmony_ci 342141cc406Sopenharmony_ci /* USB-in-USB: checking acknowledge for control message */ 343141cc406Sopenharmony_ci ret = hp5590_get_ack (dn, proto_flags); 344141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 345141cc406Sopenharmony_ci return ret; 346141cc406Sopenharmony_ci 347141cc406Sopenharmony_ci len = size; 348141cc406Sopenharmony_ci ptr = bytes; 349141cc406Sopenharmony_ci /* Data is sent in 8 byte portions */ 350141cc406Sopenharmony_ci while (len) 351141cc406Sopenharmony_ci { 352141cc406Sopenharmony_ci unsigned int next_packet_size; 353141cc406Sopenharmony_ci next_packet_size = 8; 354141cc406Sopenharmony_ci if (len < 8) 355141cc406Sopenharmony_ci next_packet_size = len; 356141cc406Sopenharmony_ci 357141cc406Sopenharmony_ci /* Send USB-in-USB data */ 358141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 359141cc406Sopenharmony_ci core_flags & CORE_DATA ? 0x04 : 0x0c, 360141cc406Sopenharmony_ci 0x8f, 0x00, next_packet_size, ptr); 361141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 362141cc406Sopenharmony_ci { 363141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error sending data\n", __func__); 364141cc406Sopenharmony_ci return ret; 365141cc406Sopenharmony_ci } 366141cc406Sopenharmony_ci 367141cc406Sopenharmony_ci /* CORE data is acknowledged packet by packet */ 368141cc406Sopenharmony_ci if (core_flags & CORE_DATA) 369141cc406Sopenharmony_ci { 370141cc406Sopenharmony_ci /* USB-in-USB: checking if data was accepted */ 371141cc406Sopenharmony_ci ret = hp5590_get_ack (dn, proto_flags); 372141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 373141cc406Sopenharmony_ci return ret; 374141cc406Sopenharmony_ci } 375141cc406Sopenharmony_ci 376141cc406Sopenharmony_ci ptr += next_packet_size; 377141cc406Sopenharmony_ci len -= next_packet_size; 378141cc406Sopenharmony_ci } 379141cc406Sopenharmony_ci 380141cc406Sopenharmony_ci /* Normal (non-CORE) data is acknowledged after its full transmission */ 381141cc406Sopenharmony_ci if (!(core_flags & CORE_DATA)) 382141cc406Sopenharmony_ci { 383141cc406Sopenharmony_ci /* USB-in-USB: checking if data was accepted */ 384141cc406Sopenharmony_ci ret = hp5590_get_ack (dn, proto_flags); 385141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 386141cc406Sopenharmony_ci return ret; 387141cc406Sopenharmony_ci } 388141cc406Sopenharmony_ci 389141cc406Sopenharmony_ci /* Getting response after data transmission */ 390141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: getting response\n", __func__); 391141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, 392141cc406Sopenharmony_ci 0x0c, 0x90, 0x00, 393141cc406Sopenharmony_ci sizeof (response), &response); 394141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 395141cc406Sopenharmony_ci { 396141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error getting response\n", __func__); 397141cc406Sopenharmony_ci return ret; 398141cc406Sopenharmony_ci } 399141cc406Sopenharmony_ci 400141cc406Sopenharmony_ci /* Necessary response after normal (non-CORE) data is 0x00, 401141cc406Sopenharmony_ci * after bulk OUT preparation - 0x24 402141cc406Sopenharmony_ci */ 403141cc406Sopenharmony_ci needed_response = core_flags & CORE_BULK_OUT ? 0x24 : 0x00; 404141cc406Sopenharmony_ci if (response == needed_response) 405141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: got correct response\n", 406141cc406Sopenharmony_ci __func__); 407141cc406Sopenharmony_ci 408141cc406Sopenharmony_ci if (response != needed_response) 409141cc406Sopenharmony_ci { 410141cc406Sopenharmony_ci DBG (DBG_err, 411141cc406Sopenharmony_ci "%s: USB-in-USB: invalid response received " 412141cc406Sopenharmony_ci "(needed %04x, got %04x)\n", 413141cc406Sopenharmony_ci __func__, needed_response, response); 414141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 415141cc406Sopenharmony_ci } 416141cc406Sopenharmony_ci 417141cc406Sopenharmony_ci /* Send bulk OUT flags is bulk OUT preparation is performed */ 418141cc406Sopenharmony_ci if (core_flags & CORE_BULK_OUT) 419141cc406Sopenharmony_ci { 420141cc406Sopenharmony_ci uint8_t bulk_flags = 0x24; 421141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: sending bulk flags\n", 422141cc406Sopenharmony_ci __func__); 423141cc406Sopenharmony_ci 424141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 425141cc406Sopenharmony_ci 0x0c, 0x83, 0x00, 426141cc406Sopenharmony_ci sizeof (bulk_flags), &bulk_flags); 427141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 428141cc406Sopenharmony_ci { 429141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n", 430141cc406Sopenharmony_ci __func__); 431141cc406Sopenharmony_ci return ret; 432141cc406Sopenharmony_ci } 433141cc406Sopenharmony_ci 434141cc406Sopenharmony_ci /* USB-in-USB: checking confirmation for bulk flags */ 435141cc406Sopenharmony_ci ret = hp5590_get_ack (dn, proto_flags); 436141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 437141cc406Sopenharmony_ci return ret; 438141cc406Sopenharmony_ci } 439141cc406Sopenharmony_ci } 440141cc406Sopenharmony_ci 441141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 442141cc406Sopenharmony_ci} 443141cc406Sopenharmony_ci 444141cc406Sopenharmony_ci/******************************************************************************* 445141cc406Sopenharmony_ci * USB-in-USB: verifies last command 446141cc406Sopenharmony_ci * 447141cc406Sopenharmony_ci * Parameters 448141cc406Sopenharmony_ci * dn - sanei_usb device descriptor 449141cc406Sopenharmony_ci * cmd - command to verify 450141cc406Sopenharmony_ci * 451141cc406Sopenharmony_ci * Returns 452141cc406Sopenharmony_ci * SANE_STATUS_GOOD - command verified successfully and CORE is ready 453141cc406Sopenharmony_ci * SANE_STATUS_IO_ERROR - command verification failed 454141cc406Sopenharmony_ci * SANE_STATUS_DEVICE_BUSY - command verified successfully but CORE isn't ready 455141cc406Sopenharmony_ci * all other SANE_Status values - otherwise 456141cc406Sopenharmony_ci */ 457141cc406Sopenharmony_cistatic SANE_Status 458141cc406Sopenharmony_cihp5590_verify_last_cmd (SANE_Int dn, 459141cc406Sopenharmony_ci enum proto_flags proto_flags, 460141cc406Sopenharmony_ci unsigned int cmd) 461141cc406Sopenharmony_ci{ 462141cc406Sopenharmony_ci uint16_t verify_cmd; 463141cc406Sopenharmony_ci unsigned int last_cmd; 464141cc406Sopenharmony_ci unsigned int core_status; 465141cc406Sopenharmony_ci SANE_Status ret; 466141cc406Sopenharmony_ci 467141cc406Sopenharmony_ci DBG (3, "%s: USB-in-USB: command verification requested\n", 468141cc406Sopenharmony_ci __func__); 469141cc406Sopenharmony_ci 470141cc406Sopenharmony_ci /* Read last command along with CORE status */ 471141cc406Sopenharmony_ci ret = hp5590_control_msg (dn, 472141cc406Sopenharmony_ci proto_flags, 473141cc406Sopenharmony_ci USB_DIR_IN, 474141cc406Sopenharmony_ci 0x04, 0xc5, 0x00, 475141cc406Sopenharmony_ci (unsigned char *) &verify_cmd, 476141cc406Sopenharmony_ci sizeof (verify_cmd), CORE_NONE); 477141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 478141cc406Sopenharmony_ci return ret; 479141cc406Sopenharmony_ci 480141cc406Sopenharmony_ci verify_cmd = le16toh (verify_cmd); /* Response is LSB first */ 481141cc406Sopenharmony_ci 482141cc406Sopenharmony_ci /* Last command - minor byte */ 483141cc406Sopenharmony_ci last_cmd = verify_cmd & 0xff; 484141cc406Sopenharmony_ci /* CORE status - major byte */ 485141cc406Sopenharmony_ci core_status = (verify_cmd & 0xff00) >> 8; 486141cc406Sopenharmony_ci 487141cc406Sopenharmony_ci /* Verify last command */ 488141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: command verification %04x, " 489141cc406Sopenharmony_ci "last command: %04x, core status: %04x\n", 490141cc406Sopenharmony_ci __func__, verify_cmd, last_cmd, core_status); 491141cc406Sopenharmony_ci if ((cmd & 0x00ff) != last_cmd) 492141cc406Sopenharmony_ci { 493141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: command verification failed: " 494141cc406Sopenharmony_ci "expected 0x%04x, got 0x%04x\n", 495141cc406Sopenharmony_ci __func__, cmd, last_cmd); 496141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 497141cc406Sopenharmony_ci } 498141cc406Sopenharmony_ci 499141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: command verified successfully\n", 500141cc406Sopenharmony_ci __func__); 501141cc406Sopenharmony_ci 502141cc406Sopenharmony_ci /* Return value depends on CORE status */ 503141cc406Sopenharmony_ci return core_status & CORE_FLAG_NOT_READY ? 504141cc406Sopenharmony_ci SANE_STATUS_DEVICE_BUSY : SANE_STATUS_GOOD; 505141cc406Sopenharmony_ci} 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_ci/******************************************************************************* 508141cc406Sopenharmony_ci * USB-in-USB: send command (convenience wrapper around hp5590_control_msg()) 509141cc406Sopenharmony_ci * 510141cc406Sopenharmony_ci * Parameters 511141cc406Sopenharmony_ci * dn - sanei_usb device descriptor 512141cc406Sopenharmony_ci * requesttype, request, value, index - their meanings are similar to 513141cc406Sopenharmony_ci * sanei_control_msg() 514141cc406Sopenharmony_ci * bytes - pointer to data buffer 515141cc406Sopenharmony_ci * size - size of data 516141cc406Sopenharmony_ci * core_flags - 517141cc406Sopenharmony_ci * CORE_NONE - no CORE operation will be performed 518141cc406Sopenharmony_ci * CORE_DATA - operation on CORE data will be performed 519141cc406Sopenharmony_ci * CORE_BULK_IN - preparation for bulk IN transfer (not used yet) 520141cc406Sopenharmony_ci * CORE_BULK_OUT - preparation for bulk OUT transfer 521141cc406Sopenharmony_ci * 522141cc406Sopenharmony_ci * Returns 523141cc406Sopenharmony_ci * SANE_STATUS_GOOD - command was sent (and possible verified) w/o any errors 524141cc406Sopenharmony_ci * all other SANE_Status values - otherwise 525141cc406Sopenharmony_ci */ 526141cc406Sopenharmony_cistatic SANE_Status 527141cc406Sopenharmony_cihp5590_cmd (SANE_Int dn, 528141cc406Sopenharmony_ci enum proto_flags proto_flags, 529141cc406Sopenharmony_ci unsigned int flags, 530141cc406Sopenharmony_ci unsigned int cmd, unsigned char *data, unsigned int size, 531141cc406Sopenharmony_ci unsigned int core_flags) 532141cc406Sopenharmony_ci{ 533141cc406Sopenharmony_ci SANE_Status ret; 534141cc406Sopenharmony_ci 535141cc406Sopenharmony_ci DBG (3, "%s: USB-in-USB: command : %04x\n", __func__, cmd); 536141cc406Sopenharmony_ci 537141cc406Sopenharmony_ci ret = hp5590_control_msg (dn, 538141cc406Sopenharmony_ci proto_flags, 539141cc406Sopenharmony_ci flags & CMD_IN ? USB_DIR_IN : USB_DIR_OUT, 540141cc406Sopenharmony_ci 0x04, cmd, 0x00, data, size, core_flags); 541141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 542141cc406Sopenharmony_ci return ret; 543141cc406Sopenharmony_ci 544141cc406Sopenharmony_ci ret = SANE_STATUS_GOOD; 545141cc406Sopenharmony_ci /* Verify last command if requested */ 546141cc406Sopenharmony_ci if (flags & CMD_VERIFY) 547141cc406Sopenharmony_ci { 548141cc406Sopenharmony_ci ret = hp5590_verify_last_cmd (dn, proto_flags, cmd); 549141cc406Sopenharmony_ci } 550141cc406Sopenharmony_ci 551141cc406Sopenharmony_ci return ret; 552141cc406Sopenharmony_ci} 553141cc406Sopenharmony_ci 554141cc406Sopenharmony_ci/******************************************************************************* 555141cc406Sopenharmony_ci * USB-in-USB: initialized bulk read state 556141cc406Sopenharmony_ci * 557141cc406Sopenharmony_ci * Parameters 558141cc406Sopenharmony_ci * state - pointer to a pointer for initialized state 559141cc406Sopenharmony_ci * 560141cc406Sopenharmony_ci * Returns 561141cc406Sopenharmony_ci * SANE_STATUS_GOOD - if state was initialized successfully 562141cc406Sopenharmony_ci * SANE_STATUS_NO_MEM - memory allocation failed 563141cc406Sopenharmony_ci */ 564141cc406Sopenharmony_cistatic SANE_Status 565141cc406Sopenharmony_cihp5590_low_init_bulk_read_state (void **state) 566141cc406Sopenharmony_ci{ 567141cc406Sopenharmony_ci struct bulk_read_state *bulk_read_state; 568141cc406Sopenharmony_ci 569141cc406Sopenharmony_ci DBG (3, "%s: USB-in-USB: initializing bulk read state\n", __func__); 570141cc406Sopenharmony_ci 571141cc406Sopenharmony_ci hp5590_low_assert (state != NULL); 572141cc406Sopenharmony_ci 573141cc406Sopenharmony_ci bulk_read_state = malloc (sizeof (struct bulk_read_state)); 574141cc406Sopenharmony_ci if (!bulk_read_state) 575141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 576141cc406Sopenharmony_ci memset (bulk_read_state, 0, sizeof (struct bulk_read_state)); 577141cc406Sopenharmony_ci 578141cc406Sopenharmony_ci bulk_read_state->buffer = malloc (ALLOCATE_BULK_READ_PAGES 579141cc406Sopenharmony_ci * BULK_READ_PAGE_SIZE); 580141cc406Sopenharmony_ci if (!bulk_read_state->buffer) 581141cc406Sopenharmony_ci { 582141cc406Sopenharmony_ci DBG (DBG_err, "%s: Memory allocation failed for %u bytes\n", 583141cc406Sopenharmony_ci __func__, ALLOCATE_BULK_READ_PAGES * BULK_READ_PAGE_SIZE); 584141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 585141cc406Sopenharmony_ci } 586141cc406Sopenharmony_ci bulk_read_state->buffer_size = ALLOCATE_BULK_READ_PAGES 587141cc406Sopenharmony_ci * BULK_READ_PAGE_SIZE; 588141cc406Sopenharmony_ci bulk_read_state->bytes_available = 0; 589141cc406Sopenharmony_ci bulk_read_state->buffer_out_ptr = bulk_read_state->buffer; 590141cc406Sopenharmony_ci bulk_read_state->buffer_in_ptr = bulk_read_state->buffer; 591141cc406Sopenharmony_ci bulk_read_state->total_pages = 0; 592141cc406Sopenharmony_ci bulk_read_state->buffer_end_ptr = bulk_read_state->buffer 593141cc406Sopenharmony_ci + bulk_read_state->buffer_size; 594141cc406Sopenharmony_ci bulk_read_state->initialized = 1; 595141cc406Sopenharmony_ci 596141cc406Sopenharmony_ci *state = bulk_read_state; 597141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 598141cc406Sopenharmony_ci} 599141cc406Sopenharmony_ci 600141cc406Sopenharmony_ci/******************************************************************************* 601141cc406Sopenharmony_ci * USB-in-USB: free bulk read state 602141cc406Sopenharmony_ci * 603141cc406Sopenharmony_ci * Parameters 604141cc406Sopenharmony_ci * state - pointer to a pointer to bulk read state 605141cc406Sopenharmony_ci * 606141cc406Sopenharmony_ci * Returns 607141cc406Sopenharmony_ci * SANE_STATUS_GOOD - bulk read state freed successfully 608141cc406Sopenharmony_ci */ 609141cc406Sopenharmony_cistatic SANE_Status 610141cc406Sopenharmony_cihp5590_low_free_bulk_read_state (void **state) 611141cc406Sopenharmony_ci{ 612141cc406Sopenharmony_ci struct bulk_read_state *bulk_read_state; 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ci DBG (3, "%s\n", __func__); 615141cc406Sopenharmony_ci 616141cc406Sopenharmony_ci hp5590_low_assert (state != NULL); 617141cc406Sopenharmony_ci /* Just return if NULL bulk read state was given */ 618141cc406Sopenharmony_ci if (*state == NULL) 619141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 620141cc406Sopenharmony_ci 621141cc406Sopenharmony_ci bulk_read_state = *state; 622141cc406Sopenharmony_ci 623141cc406Sopenharmony_ci DBG (3, "%s: USB-in-USB: freeing bulk read state\n", __func__); 624141cc406Sopenharmony_ci 625141cc406Sopenharmony_ci free (bulk_read_state->buffer); 626141cc406Sopenharmony_ci bulk_read_state->buffer = NULL; 627141cc406Sopenharmony_ci free (bulk_read_state); 628141cc406Sopenharmony_ci *state = NULL; 629141cc406Sopenharmony_ci 630141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 631141cc406Sopenharmony_ci} 632141cc406Sopenharmony_ci 633141cc406Sopenharmony_ci/* FIXME: perhaps needs to be converted to use hp5590_control_msg() */ 634141cc406Sopenharmony_ci/******************************************************************************* 635141cc406Sopenharmony_ci * USB-in-USB: bulk read 636141cc406Sopenharmony_ci * 637141cc406Sopenharmony_ci * Parameters 638141cc406Sopenharmony_ci * dn - sanei_usb device descriptor 639141cc406Sopenharmony_ci * bytes - pointer to data buffer 640141cc406Sopenharmony_ci * size - size of data to read 641141cc406Sopenharmony_ci * state - pointer to initialized bulk read state structure 642141cc406Sopenharmony_ci */ 643141cc406Sopenharmony_cistatic SANE_Status 644141cc406Sopenharmony_cihp5590_bulk_read (SANE_Int dn, 645141cc406Sopenharmony_ci enum proto_flags proto_flags, 646141cc406Sopenharmony_ci unsigned char *bytes, unsigned int size, 647141cc406Sopenharmony_ci void *state) 648141cc406Sopenharmony_ci{ 649141cc406Sopenharmony_ci struct usb_in_usb_bulk_setup ctrl; 650141cc406Sopenharmony_ci SANE_Status ret; 651141cc406Sopenharmony_ci unsigned int next_pages; 652141cc406Sopenharmony_ci uint8_t bulk_flags; 653141cc406Sopenharmony_ci size_t next_portion; 654141cc406Sopenharmony_ci struct bulk_read_state *bulk_read_state; 655141cc406Sopenharmony_ci unsigned int bytes_until_buffer_end; 656141cc406Sopenharmony_ci 657141cc406Sopenharmony_ci DBG (3, "%s\n", __func__); 658141cc406Sopenharmony_ci 659141cc406Sopenharmony_ci hp5590_low_assert (state != NULL); 660141cc406Sopenharmony_ci hp5590_low_assert (bytes != NULL); 661141cc406Sopenharmony_ci 662141cc406Sopenharmony_ci bulk_read_state = state; 663141cc406Sopenharmony_ci if (bulk_read_state->initialized == 0) 664141cc406Sopenharmony_ci { 665141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: bulk read state not initialized\n", 666141cc406Sopenharmony_ci __func__); 667141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 668141cc406Sopenharmony_ci } 669141cc406Sopenharmony_ci 670141cc406Sopenharmony_ci memset (bytes, 0, size); 671141cc406Sopenharmony_ci 672141cc406Sopenharmony_ci /* Check if requested data would fit into the buffer */ 673141cc406Sopenharmony_ci if (size > bulk_read_state->buffer_size) 674141cc406Sopenharmony_ci { 675141cc406Sopenharmony_ci DBG (DBG_err, "Data requested won't fit in the bulk read buffer " 676141cc406Sopenharmony_ci "(requested: %u, buffer size: %u\n", size, 677141cc406Sopenharmony_ci bulk_read_state->buffer_size); 678141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 679141cc406Sopenharmony_ci } 680141cc406Sopenharmony_ci 681141cc406Sopenharmony_ci /* Read data until requested size of data will be received */ 682141cc406Sopenharmony_ci while (bulk_read_state->bytes_available < size) 683141cc406Sopenharmony_ci { 684141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: not enough data in buffer available " 685141cc406Sopenharmony_ci "(available: %u, requested: %u)\n", 686141cc406Sopenharmony_ci __func__, bulk_read_state->bytes_available, size); 687141cc406Sopenharmony_ci 688141cc406Sopenharmony_ci /* IMPORTANT! 'next_pages' means 'request and receive next_pages pages in 689141cc406Sopenharmony_ci * one bulk transfer request '. Windows driver uses 4 pages between each 690141cc406Sopenharmony_ci * request. The more pages are received between requests the less the 691141cc406Sopenharmony_ci * scanner does scan head re-positioning thus improving scanning speed. 692141cc406Sopenharmony_ci * On the other hand, scanner expects that all of the requested pages 693141cc406Sopenharmony_ci * will be received immediately after the request. In case when a 694141cc406Sopenharmony_ci * frontend will have a delay between reads we will get bulk transfer 695141cc406Sopenharmony_ci * timeout sooner or later. 696141cc406Sopenharmony_ci * Having next_pages = 1 is the most safe case. 697141cc406Sopenharmony_ci */ 698141cc406Sopenharmony_ci next_pages = 1; 699141cc406Sopenharmony_ci /* Count all received pages to calculate when we will need to send 700141cc406Sopenharmony_ci * another bulk request 701141cc406Sopenharmony_ci */ 702141cc406Sopenharmony_ci bulk_read_state->total_pages++; 703141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: total pages done: %u\n", 704141cc406Sopenharmony_ci __func__, bulk_read_state->total_pages); 705141cc406Sopenharmony_ci 706141cc406Sopenharmony_ci /* Send another bulk request for 'next_pages' before first 707141cc406Sopenharmony_ci * page or next necessary one 708141cc406Sopenharmony_ci */ 709141cc406Sopenharmony_ci if ( bulk_read_state->total_pages == 1 710141cc406Sopenharmony_ci || bulk_read_state->total_pages % next_pages == 0) 711141cc406Sopenharmony_ci { 712141cc406Sopenharmony_ci /* Send bulk flags */ 713141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: sending USB-in-USB bulk flags\n", 714141cc406Sopenharmony_ci __func__); 715141cc406Sopenharmony_ci bulk_flags = 0x24; 716141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 717141cc406Sopenharmony_ci 0x0c, 0x83, 0x00, 718141cc406Sopenharmony_ci sizeof (bulk_flags), &bulk_flags); 719141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 720141cc406Sopenharmony_ci { 721141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n", 722141cc406Sopenharmony_ci __func__); 723141cc406Sopenharmony_ci return ret; 724141cc406Sopenharmony_ci } 725141cc406Sopenharmony_ci 726141cc406Sopenharmony_ci /* USB-in-USB: checking confirmation for bulk flags\n" */ 727141cc406Sopenharmony_ci ret = hp5590_get_ack (dn, proto_flags); 728141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 729141cc406Sopenharmony_ci return ret; 730141cc406Sopenharmony_ci 731141cc406Sopenharmony_ci /* Prepare bulk read request */ 732141cc406Sopenharmony_ci memset (&ctrl, 0, sizeof (ctrl)); 733141cc406Sopenharmony_ci ctrl.bRequestType = 0x00; 734141cc406Sopenharmony_ci ctrl.bEndpoint = 0x82; 735141cc406Sopenharmony_ci ctrl.wLength = htons (next_pages); 736141cc406Sopenharmony_ci 737141cc406Sopenharmony_ci /* Send bulk read request */ 738141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: sending control msg for bulk\n", 739141cc406Sopenharmony_ci __func__); 740141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 741141cc406Sopenharmony_ci 0x04, 0x82, 0x00, 742141cc406Sopenharmony_ci sizeof (ctrl), 743141cc406Sopenharmony_ci (unsigned char *) &ctrl); 744141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 745141cc406Sopenharmony_ci { 746141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error sending control msg\n", 747141cc406Sopenharmony_ci __func__); 748141cc406Sopenharmony_ci return ret; 749141cc406Sopenharmony_ci } 750141cc406Sopenharmony_ci 751141cc406Sopenharmony_ci /* USB-in-USB: checking if control msg was accepted */ 752141cc406Sopenharmony_ci ret = hp5590_get_ack (dn, proto_flags); 753141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 754141cc406Sopenharmony_ci return ret; 755141cc406Sopenharmony_ci } 756141cc406Sopenharmony_ci 757141cc406Sopenharmony_ci next_portion = BULK_READ_PAGE_SIZE; 758141cc406Sopenharmony_ci /* Check if next page will fit into the buffer */ 759141cc406Sopenharmony_ci if (bulk_read_state->buffer_size 760141cc406Sopenharmony_ci - bulk_read_state->bytes_available < next_portion) 761141cc406Sopenharmony_ci { 762141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: buffer too small\n", __func__); 763141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 764141cc406Sopenharmony_ci } 765141cc406Sopenharmony_ci 766141cc406Sopenharmony_ci /* Bulk read next page */ 767141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: bulk reading %lu bytes\n", 768141cc406Sopenharmony_ci __func__, (u_long) next_portion); 769141cc406Sopenharmony_ci ret = sanei_usb_read_bulk (dn, 770141cc406Sopenharmony_ci bulk_read_state->buffer_in_ptr, 771141cc406Sopenharmony_ci &next_portion); 772141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 773141cc406Sopenharmony_ci { 774141cc406Sopenharmony_ci if (ret == SANE_STATUS_EOF) 775141cc406Sopenharmony_ci return ret; 776141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error during bulk read: %s\n", 777141cc406Sopenharmony_ci __func__, sane_strstatus (ret)); 778141cc406Sopenharmony_ci return ret; 779141cc406Sopenharmony_ci } 780141cc406Sopenharmony_ci 781141cc406Sopenharmony_ci /* Check if we received the same amount of data as requested */ 782141cc406Sopenharmony_ci if (next_portion != BULK_READ_PAGE_SIZE) 783141cc406Sopenharmony_ci { 784141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: incomplete bulk read " 785141cc406Sopenharmony_ci "(requested %u bytes, got %lu bytes)\n", 786141cc406Sopenharmony_ci __func__, BULK_READ_PAGE_SIZE, (u_long) next_portion); 787141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 788141cc406Sopenharmony_ci } 789141cc406Sopenharmony_ci 790141cc406Sopenharmony_ci /* Move pointers to the next position */ 791141cc406Sopenharmony_ci bulk_read_state->buffer_in_ptr += next_portion; 792141cc406Sopenharmony_ci 793141cc406Sopenharmony_ci /* Check for the end of the buffer */ 794141cc406Sopenharmony_ci if (bulk_read_state->buffer_in_ptr > bulk_read_state->buffer_end_ptr) 795141cc406Sopenharmony_ci { 796141cc406Sopenharmony_ci DBG (DBG_err, 797141cc406Sopenharmony_ci "%s: USB-in-USB: attempted to access over the end of buffer " 798141cc406Sopenharmony_ci "(in_ptr: %p, end_ptr: %p, ptr: %p, buffer size: %u\n", 799141cc406Sopenharmony_ci __func__, (void *) bulk_read_state->buffer_in_ptr, 800141cc406Sopenharmony_ci (void *) bulk_read_state->buffer_end_ptr, 801141cc406Sopenharmony_ci (void *) bulk_read_state->buffer, 802141cc406Sopenharmony_ci bulk_read_state->buffer_size); 803141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 804141cc406Sopenharmony_ci } 805141cc406Sopenharmony_ci 806141cc406Sopenharmony_ci /* Check for buffer pointer wrapping */ 807141cc406Sopenharmony_ci if (bulk_read_state->buffer_in_ptr == bulk_read_state->buffer_end_ptr) 808141cc406Sopenharmony_ci { 809141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while writing\n", 810141cc406Sopenharmony_ci __func__); 811141cc406Sopenharmony_ci bulk_read_state->buffer_in_ptr = bulk_read_state->buffer; 812141cc406Sopenharmony_ci } 813141cc406Sopenharmony_ci 814141cc406Sopenharmony_ci /* Count the amount of data we read */ 815141cc406Sopenharmony_ci bulk_read_state->bytes_available += next_portion; 816141cc406Sopenharmony_ci } 817141cc406Sopenharmony_ci 818141cc406Sopenharmony_ci /* Transfer requested amount of data to the caller */ 819141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: data in bulk buffer is available " 820141cc406Sopenharmony_ci "(requested %u bytes, available %u bytes)\n", 821141cc406Sopenharmony_ci __func__, size, bulk_read_state->bytes_available); 822141cc406Sopenharmony_ci 823141cc406Sopenharmony_ci /* Check for buffer pointer wrapping */ 824141cc406Sopenharmony_ci bytes_until_buffer_end = bulk_read_state->buffer_end_ptr 825141cc406Sopenharmony_ci - bulk_read_state->buffer_out_ptr; 826141cc406Sopenharmony_ci if (bytes_until_buffer_end <= size) 827141cc406Sopenharmony_ci { 828141cc406Sopenharmony_ci /* First buffer part */ 829141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: reached bulk read buffer end\n", __func__); 830141cc406Sopenharmony_ci memcpy (bytes, bulk_read_state->buffer_out_ptr, bytes_until_buffer_end); 831141cc406Sopenharmony_ci bulk_read_state->buffer_out_ptr = bulk_read_state->buffer; 832141cc406Sopenharmony_ci /* And second part (if any) */ 833141cc406Sopenharmony_ci if (bytes_until_buffer_end < size) 834141cc406Sopenharmony_ci { 835141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: giving 2nd buffer part\n", __func__); 836141cc406Sopenharmony_ci memcpy (bytes + bytes_until_buffer_end, 837141cc406Sopenharmony_ci bulk_read_state->buffer_out_ptr, 838141cc406Sopenharmony_ci size - bytes_until_buffer_end); 839141cc406Sopenharmony_ci bulk_read_state->buffer_out_ptr += size - bytes_until_buffer_end; 840141cc406Sopenharmony_ci } 841141cc406Sopenharmony_ci } 842141cc406Sopenharmony_ci else 843141cc406Sopenharmony_ci { 844141cc406Sopenharmony_ci /* The data is in one buffer part (w/o wrapping) */ 845141cc406Sopenharmony_ci memcpy (bytes, bulk_read_state->buffer_out_ptr, size); 846141cc406Sopenharmony_ci bulk_read_state->buffer_out_ptr += size; 847141cc406Sopenharmony_ci if (bulk_read_state->buffer_out_ptr == bulk_read_state->buffer_end_ptr) 848141cc406Sopenharmony_ci { 849141cc406Sopenharmony_ci DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while reading\n", 850141cc406Sopenharmony_ci __func__); 851141cc406Sopenharmony_ci bulk_read_state->buffer_out_ptr = bulk_read_state->buffer; 852141cc406Sopenharmony_ci } 853141cc406Sopenharmony_ci } 854141cc406Sopenharmony_ci 855141cc406Sopenharmony_ci /* Count the amount of data transferred to the caller */ 856141cc406Sopenharmony_ci bulk_read_state->bytes_available -= size; 857141cc406Sopenharmony_ci 858141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 859141cc406Sopenharmony_ci} 860141cc406Sopenharmony_ci 861141cc406Sopenharmony_ci/******************************************************************************* 862141cc406Sopenharmony_ci * USB-in-USB: bulk write 863141cc406Sopenharmony_ci * 864141cc406Sopenharmony_ci * Parameters 865141cc406Sopenharmony_ci * dn - sanei_usb device descriptor 866141cc406Sopenharmony_ci * cmd - command for bulk write operation 867141cc406Sopenharmony_ci * bytes - pointer to data buffer 868141cc406Sopenharmony_ci * size - size of data 869141cc406Sopenharmony_ci * 870141cc406Sopenharmony_ci * Returns 871141cc406Sopenharmony_ci * SANE_STATUS_GOOD - all data transferred successfully 872141cc406Sopenharmony_ci * all other SANE_Status value - otherwise 873141cc406Sopenharmony_ci */ 874141cc406Sopenharmony_cistatic SANE_Status 875141cc406Sopenharmony_cihp5590_bulk_write (SANE_Int dn, 876141cc406Sopenharmony_ci enum proto_flags proto_flags, 877141cc406Sopenharmony_ci int cmd, unsigned char *bytes, 878141cc406Sopenharmony_ci unsigned int size) 879141cc406Sopenharmony_ci{ 880141cc406Sopenharmony_ci struct usb_in_usb_bulk_setup ctrl; 881141cc406Sopenharmony_ci SANE_Status ret; 882141cc406Sopenharmony_ci struct bulk_size bulk_size; 883141cc406Sopenharmony_ci 884141cc406Sopenharmony_ci unsigned int len; 885141cc406Sopenharmony_ci unsigned char *ptr; 886141cc406Sopenharmony_ci size_t next_portion; 887141cc406Sopenharmony_ci 888141cc406Sopenharmony_ci DBG (3, "%s: USB-in-USB: command: %04x, size %u\n", __func__, cmd, 889141cc406Sopenharmony_ci size); 890141cc406Sopenharmony_ci 891141cc406Sopenharmony_ci hp5590_low_assert (bytes != NULL); 892141cc406Sopenharmony_ci 893141cc406Sopenharmony_ci /* Prepare bulk write request */ 894141cc406Sopenharmony_ci memset (&bulk_size, 0, sizeof (bulk_size)); 895141cc406Sopenharmony_ci /* Counted in page size */ 896141cc406Sopenharmony_ci bulk_size.size = size / BULK_WRITE_PAGE_SIZE; 897141cc406Sopenharmony_ci 898141cc406Sopenharmony_ci /* Send bulk write request */ 899141cc406Sopenharmony_ci DBG (3, "%s: USB-in-USB: total %u pages (each of %u bytes)\n", 900141cc406Sopenharmony_ci __func__, bulk_size.size, BULK_WRITE_PAGE_SIZE); 901141cc406Sopenharmony_ci ret = hp5590_control_msg (dn, 902141cc406Sopenharmony_ci proto_flags, 903141cc406Sopenharmony_ci USB_DIR_OUT, 904141cc406Sopenharmony_ci 0x04, cmd, 0, 905141cc406Sopenharmony_ci (unsigned char *) &bulk_size, sizeof (bulk_size), 906141cc406Sopenharmony_ci CORE_DATA | CORE_BULK_OUT); 907141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 908141cc406Sopenharmony_ci return ret; 909141cc406Sopenharmony_ci 910141cc406Sopenharmony_ci len = size; 911141cc406Sopenharmony_ci ptr = bytes; 912141cc406Sopenharmony_ci 913141cc406Sopenharmony_ci /* Send all data in pages */ 914141cc406Sopenharmony_ci while (len) 915141cc406Sopenharmony_ci { 916141cc406Sopenharmony_ci next_portion = BULK_WRITE_PAGE_SIZE; 917141cc406Sopenharmony_ci if (len < next_portion) 918141cc406Sopenharmony_ci next_portion = len; 919141cc406Sopenharmony_ci 920141cc406Sopenharmony_ci DBG (3, "%s: USB-in-USB: next portion %lu bytes\n", 921141cc406Sopenharmony_ci __func__, (u_long) next_portion); 922141cc406Sopenharmony_ci 923141cc406Sopenharmony_ci /* Prepare bulk write request */ 924141cc406Sopenharmony_ci memset (&ctrl, 0, sizeof (ctrl)); 925141cc406Sopenharmony_ci ctrl.bRequestType = 0x01; 926141cc406Sopenharmony_ci ctrl.bEndpoint = 0x82; 927141cc406Sopenharmony_ci ctrl.wLength = htons (next_portion); 928141cc406Sopenharmony_ci 929141cc406Sopenharmony_ci /* Send bulk write request */ 930141cc406Sopenharmony_ci ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 931141cc406Sopenharmony_ci 0x04, 0x82, 0, 932141cc406Sopenharmony_ci sizeof (ctrl), (unsigned char *) &ctrl); 933141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 934141cc406Sopenharmony_ci return ret; 935141cc406Sopenharmony_ci 936141cc406Sopenharmony_ci /* USB-in-USB: checking if command was accepted */ 937141cc406Sopenharmony_ci ret = hp5590_get_ack (dn, proto_flags); 938141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 939141cc406Sopenharmony_ci return ret; 940141cc406Sopenharmony_ci 941141cc406Sopenharmony_ci /* Write bulk data */ 942141cc406Sopenharmony_ci DBG (3, "%s: USB-in-USB: bulk writing %lu bytes\n", 943141cc406Sopenharmony_ci __func__, (u_long) next_portion); 944141cc406Sopenharmony_ci ret = sanei_usb_write_bulk (dn, ptr, &next_portion); 945141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) 946141cc406Sopenharmony_ci { 947141cc406Sopenharmony_ci /* Treast EOF as successful result */ 948141cc406Sopenharmony_ci if (ret == SANE_STATUS_EOF) 949141cc406Sopenharmony_ci break; 950141cc406Sopenharmony_ci DBG (DBG_err, "%s: USB-in-USB: error during bulk write: %s\n", 951141cc406Sopenharmony_ci __func__, sane_strstatus (ret)); 952141cc406Sopenharmony_ci return ret; 953141cc406Sopenharmony_ci } 954141cc406Sopenharmony_ci 955141cc406Sopenharmony_ci /* Move to the next page */ 956141cc406Sopenharmony_ci len -= next_portion; 957141cc406Sopenharmony_ci ptr += next_portion; 958141cc406Sopenharmony_ci } 959141cc406Sopenharmony_ci 960141cc406Sopenharmony_ci /* Verify bulk command */ 961141cc406Sopenharmony_ci return hp5590_verify_last_cmd (dn, proto_flags, cmd); 962141cc406Sopenharmony_ci} 963141cc406Sopenharmony_ci/* vim: sw=2 ts=8 964141cc406Sopenharmony_ci */ 965