1141cc406Sopenharmony_ci/* 2141cc406Sopenharmony_ci Copyright (C) 2009, Panasonic Russia Ltd. 3141cc406Sopenharmony_ci Copyright (C) 2010,2011, m. allan noah 4141cc406Sopenharmony_ci*/ 5141cc406Sopenharmony_ci/* 6141cc406Sopenharmony_ci Panasonic KV-S40xx USB-SCSI scanner driver. 7141cc406Sopenharmony_ci*/ 8141cc406Sopenharmony_ci#include "../include/sane/config.h" 9141cc406Sopenharmony_ci#include <string.h> 10141cc406Sopenharmony_ci 11141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 12141cc406Sopenharmony_ci#define BACKEND_NAME kvs40xx 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 15141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 16141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 17141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 18141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h" 19141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci#include "kvs40xx.h" 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h" 24141cc406Sopenharmony_ci 25141cc406Sopenharmony_ci#define COMMAND_BLOCK 1 26141cc406Sopenharmony_ci#define DATA_BLOCK 2 27141cc406Sopenharmony_ci#define RESPONSE_BLOCK 3 28141cc406Sopenharmony_ci 29141cc406Sopenharmony_ci#define COMMAND_CODE 0x9000 30141cc406Sopenharmony_ci#define DATA_CODE 0xb000 31141cc406Sopenharmony_ci#define RESPONSE_CODE 0xa000 32141cc406Sopenharmony_ci#define STATUS_SIZE 4 33141cc406Sopenharmony_ci 34141cc406Sopenharmony_cistruct bulk_header 35141cc406Sopenharmony_ci{ 36141cc406Sopenharmony_ci u32 length; 37141cc406Sopenharmony_ci u16 type; 38141cc406Sopenharmony_ci u16 code; 39141cc406Sopenharmony_ci u32 transaction_id; 40141cc406Sopenharmony_ci}; 41141cc406Sopenharmony_ci 42141cc406Sopenharmony_ci#define TEST_UNIT_READY 0x00 43141cc406Sopenharmony_ci#define INQUIRY 0x12 44141cc406Sopenharmony_ci#define SET_WINDOW 0x24 45141cc406Sopenharmony_ci#define SCAN 0x1B 46141cc406Sopenharmony_ci#define SEND_10 0x2A 47141cc406Sopenharmony_ci#define READ_10 0x28 48141cc406Sopenharmony_ci#define REQUEST_SENSE 0x03 49141cc406Sopenharmony_ci#define GET_BUFFER_STATUS 0x34 50141cc406Sopenharmony_ci#define SET_TIMEOUT 0xE1 51141cc406Sopenharmony_ci#define GET_ADJUST_DATA 0xE0 52141cc406Sopenharmony_ci#define HOPPER_DOWN 0xE1 53141cc406Sopenharmony_ci#define STOP_ADF 0xE1 54141cc406Sopenharmony_ci 55141cc406Sopenharmony_ci 56141cc406Sopenharmony_ci 57141cc406Sopenharmony_ci#define SUPPORT_INFO 0x93 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci 60141cc406Sopenharmony_ci#define GOOD 0 61141cc406Sopenharmony_ci#define CHECK_CONDITION 2 62141cc406Sopenharmony_ci 63141cc406Sopenharmony_citypedef enum 64141cc406Sopenharmony_ci{ 65141cc406Sopenharmony_ci CMD_NONE = 0, 66141cc406Sopenharmony_ci CMD_IN = 0x81, /* scanner to pc */ 67141cc406Sopenharmony_ci CMD_OUT = 0x02 /* pc to scanner */ 68141cc406Sopenharmony_ci} CMD_DIRECTION; /* equals to endpoint address */ 69141cc406Sopenharmony_ci 70141cc406Sopenharmony_ci#define RESPONSE_SIZE 0x12 71141cc406Sopenharmony_ci#define MAX_CMD_SIZE 12 72141cc406Sopenharmony_cistruct cmd 73141cc406Sopenharmony_ci{ 74141cc406Sopenharmony_ci unsigned char cmd[MAX_CMD_SIZE]; 75141cc406Sopenharmony_ci int cmd_size; 76141cc406Sopenharmony_ci void *data; 77141cc406Sopenharmony_ci int data_size; 78141cc406Sopenharmony_ci int dir; 79141cc406Sopenharmony_ci}; 80141cc406Sopenharmony_cistruct response 81141cc406Sopenharmony_ci{ 82141cc406Sopenharmony_ci int status; 83141cc406Sopenharmony_ci unsigned char data[RESPONSE_SIZE]; 84141cc406Sopenharmony_ci}; 85141cc406Sopenharmony_ci 86141cc406Sopenharmony_cistatic SANE_Status 87141cc406Sopenharmony_ciusb_send_command (struct scanner *s, struct cmd *c, struct response *r, 88141cc406Sopenharmony_ci void *buf) 89141cc406Sopenharmony_ci{ 90141cc406Sopenharmony_ci SANE_Status st; 91141cc406Sopenharmony_ci struct bulk_header *h = (struct bulk_header *) buf; 92141cc406Sopenharmony_ci u8 resp[sizeof (*h) + STATUS_SIZE]; 93141cc406Sopenharmony_ci size_t sz = sizeof (*h) + MAX_CMD_SIZE; 94141cc406Sopenharmony_ci memset (h, 0, sz); 95141cc406Sopenharmony_ci h->length = cpu2be32 (sz); 96141cc406Sopenharmony_ci h->type = cpu2be16 (COMMAND_BLOCK); 97141cc406Sopenharmony_ci h->code = cpu2be16 (COMMAND_CODE); 98141cc406Sopenharmony_ci memcpy (h + 1, c->cmd, c->cmd_size); 99141cc406Sopenharmony_ci 100141cc406Sopenharmony_ci st = sanei_usb_write_bulk (s->file, (const SANE_Byte *) h, &sz); 101141cc406Sopenharmony_ci if (st) 102141cc406Sopenharmony_ci return st; 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_ci if (sz != sizeof (*h) + MAX_CMD_SIZE) 105141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 106141cc406Sopenharmony_ci 107141cc406Sopenharmony_ci if (c->dir == CMD_IN) 108141cc406Sopenharmony_ci { 109141cc406Sopenharmony_ci unsigned l; 110141cc406Sopenharmony_ci sz = sizeof (*h) + c->data_size; 111141cc406Sopenharmony_ci c->data_size = 0; 112141cc406Sopenharmony_ci st = sanei_usb_read_bulk (s->file, (SANE_Byte *) h, &sz); 113141cc406Sopenharmony_ci for (l = sz; !st && l != be2cpu32 (h->length); l += sz) 114141cc406Sopenharmony_ci { 115141cc406Sopenharmony_ci DBG (DBG_WARN, "usb wrong read (%d instead %d)\n", 116141cc406Sopenharmony_ci c->data_size, be2cpu32 (h->length)); 117141cc406Sopenharmony_ci sz = be2cpu32 (h->length) - l; 118141cc406Sopenharmony_ci st = sanei_usb_read_bulk (s->file, ((SANE_Byte *) h) + l, &sz); 119141cc406Sopenharmony_ci 120141cc406Sopenharmony_ci } 121141cc406Sopenharmony_ci 122141cc406Sopenharmony_ci c->data = h + 1; 123141cc406Sopenharmony_ci 124141cc406Sopenharmony_ci if (st) 125141cc406Sopenharmony_ci { 126141cc406Sopenharmony_ci st = sanei_usb_release_interface (s->file, 0); 127141cc406Sopenharmony_ci if (st) 128141cc406Sopenharmony_ci return st; 129141cc406Sopenharmony_ci st = sanei_usb_claim_interface (s->file, 0); 130141cc406Sopenharmony_ci 131141cc406Sopenharmony_ci if (st) 132141cc406Sopenharmony_ci return st; 133141cc406Sopenharmony_ci 134141cc406Sopenharmony_ci r->status = CHECK_CONDITION; 135141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 136141cc406Sopenharmony_ci } 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_ci c->data_size = sz - sizeof (*h); 139141cc406Sopenharmony_ci 140141cc406Sopenharmony_ci 141141cc406Sopenharmony_ci } 142141cc406Sopenharmony_ci else if (c->dir == CMD_OUT) 143141cc406Sopenharmony_ci { 144141cc406Sopenharmony_ci sz = sizeof (*h) + c->data_size; 145141cc406Sopenharmony_ci memset (h, 0, sizeof (*h)); 146141cc406Sopenharmony_ci h->length = cpu2be32 (sizeof (*h) + c->data_size); 147141cc406Sopenharmony_ci h->type = cpu2be16 (DATA_BLOCK); 148141cc406Sopenharmony_ci h->code = cpu2be16 (DATA_CODE); 149141cc406Sopenharmony_ci memcpy (h + 1, c->data, c->data_size); 150141cc406Sopenharmony_ci st = sanei_usb_write_bulk (s->file, (const SANE_Byte *) h, &sz); 151141cc406Sopenharmony_ci if (st) 152141cc406Sopenharmony_ci return st; 153141cc406Sopenharmony_ci } 154141cc406Sopenharmony_ci sz = sizeof (resp); 155141cc406Sopenharmony_ci st = sanei_usb_read_bulk (s->file, resp, &sz); 156141cc406Sopenharmony_ci if (st || sz != sizeof (resp)) 157141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci r->status = be2cpu32 (*((u32 *) (resp + sizeof (*h)))); 160141cc406Sopenharmony_ci return st; 161141cc406Sopenharmony_ci} 162141cc406Sopenharmony_ci 163141cc406Sopenharmony_ci#define END_OF_MEDIUM (1<<6) 164141cc406Sopenharmony_ci#define INCORRECT_LENGTH_INDICATOR (1<<5) 165141cc406Sopenharmony_cistatic const struct 166141cc406Sopenharmony_ci{ 167141cc406Sopenharmony_ci unsigned sense, asc, ascq; 168141cc406Sopenharmony_ci SANE_Status st; 169141cc406Sopenharmony_ci} s_errors[] = 170141cc406Sopenharmony_ci{ 171141cc406Sopenharmony_ci { 172141cc406Sopenharmony_ci 2, 0, 0, SANE_STATUS_DEVICE_BUSY}, 173141cc406Sopenharmony_ci { 174141cc406Sopenharmony_ci 2, 4, 1, SANE_STATUS_DEVICE_BUSY}, 175141cc406Sopenharmony_ci { 176141cc406Sopenharmony_ci 2, 4, 0x80, SANE_STATUS_COVER_OPEN}, 177141cc406Sopenharmony_ci { 178141cc406Sopenharmony_ci 2, 4, 0x81, SANE_STATUS_COVER_OPEN}, 179141cc406Sopenharmony_ci { 180141cc406Sopenharmony_ci 2, 4, 0x82, SANE_STATUS_COVER_OPEN}, 181141cc406Sopenharmony_ci { 182141cc406Sopenharmony_ci 2, 4, 0x83, SANE_STATUS_COVER_OPEN}, 183141cc406Sopenharmony_ci { 184141cc406Sopenharmony_ci 2, 4, 0x84, SANE_STATUS_COVER_OPEN}, 185141cc406Sopenharmony_ci { 186141cc406Sopenharmony_ci 2, 0x80, 1, SANE_STATUS_CANCELLED}, 187141cc406Sopenharmony_ci { 188141cc406Sopenharmony_ci 2, 0x80, 2, SANE_STATUS_CANCELLED}, 189141cc406Sopenharmony_ci { 190141cc406Sopenharmony_ci 3, 0x3a, 0, SANE_STATUS_NO_DOCS}, 191141cc406Sopenharmony_ci { 192141cc406Sopenharmony_ci 3, 0x80, 1, SANE_STATUS_JAMMED}, 193141cc406Sopenharmony_ci { 194141cc406Sopenharmony_ci 3, 0x80, 2, SANE_STATUS_JAMMED}, 195141cc406Sopenharmony_ci { 196141cc406Sopenharmony_ci 3, 0x80, 3, SANE_STATUS_JAMMED}, 197141cc406Sopenharmony_ci { 198141cc406Sopenharmony_ci 3, 0x80, 4, SANE_STATUS_JAMMED}, 199141cc406Sopenharmony_ci { 200141cc406Sopenharmony_ci 3, 0x80, 5, SANE_STATUS_JAMMED}, 201141cc406Sopenharmony_ci { 202141cc406Sopenharmony_ci 3, 0x80, 6, SANE_STATUS_JAMMED}, 203141cc406Sopenharmony_ci { 204141cc406Sopenharmony_ci 3, 0x80, 7, SANE_STATUS_JAMMED}, 205141cc406Sopenharmony_ci { 206141cc406Sopenharmony_ci 3, 0x80, 8, SANE_STATUS_JAMMED}, 207141cc406Sopenharmony_ci { 208141cc406Sopenharmony_ci 3, 0x80, 9, SANE_STATUS_JAMMED}, 209141cc406Sopenharmony_ci { 210141cc406Sopenharmony_ci 3, 0x80, 0xa, SANE_STATUS_JAMMED}, 211141cc406Sopenharmony_ci { 212141cc406Sopenharmony_ci 3, 0x80, 0xb, SANE_STATUS_JAMMED}, 213141cc406Sopenharmony_ci { 214141cc406Sopenharmony_ci 3, 0x80, 0xc, SANE_STATUS_JAMMED}, 215141cc406Sopenharmony_ci { 216141cc406Sopenharmony_ci 3, 0x80, 0xd, SANE_STATUS_JAMMED}, 217141cc406Sopenharmony_ci { 218141cc406Sopenharmony_ci 3, 0x80, 0xe, SANE_STATUS_JAMMED}, 219141cc406Sopenharmony_ci { 220141cc406Sopenharmony_ci 3, 0x80, 0xf, SANE_STATUS_JAMMED}, 221141cc406Sopenharmony_ci { 222141cc406Sopenharmony_ci 3, 0x80, 0x10, SANE_STATUS_JAMMED}, 223141cc406Sopenharmony_ci { 224141cc406Sopenharmony_ci 3, 0x80, 0x11, SANE_STATUS_JAMMED}, 225141cc406Sopenharmony_ci { 226141cc406Sopenharmony_ci 5, 0x1a, 0x0, SANE_STATUS_INVAL}, 227141cc406Sopenharmony_ci { 228141cc406Sopenharmony_ci 5, 0x20, 0x0, SANE_STATUS_INVAL}, 229141cc406Sopenharmony_ci { 230141cc406Sopenharmony_ci 5, 0x24, 0x0, SANE_STATUS_INVAL}, 231141cc406Sopenharmony_ci { 232141cc406Sopenharmony_ci 5, 0x25, 0x0, SANE_STATUS_INVAL}, 233141cc406Sopenharmony_ci { 234141cc406Sopenharmony_ci 5, 0x26, 0x0, SANE_STATUS_INVAL}, 235141cc406Sopenharmony_ci { 236141cc406Sopenharmony_ci 5, 0x2c, 0x01, SANE_STATUS_INVAL}, 237141cc406Sopenharmony_ci { 238141cc406Sopenharmony_ci 5, 0x2c, 0x02, SANE_STATUS_INVAL}, 239141cc406Sopenharmony_ci { 240141cc406Sopenharmony_ci 5, 0x2c, 0x80, SANE_STATUS_INVAL}, 241141cc406Sopenharmony_ci { 242141cc406Sopenharmony_ci 5, 0x2c, 0x81, SANE_STATUS_INVAL}, 243141cc406Sopenharmony_ci { 244141cc406Sopenharmony_ci 5, 0x2c, 0x82, SANE_STATUS_INVAL}, 245141cc406Sopenharmony_ci { 246141cc406Sopenharmony_ci5, 0x2c, 0x83, SANE_STATUS_INVAL},}; 247141cc406Sopenharmony_ci 248141cc406Sopenharmony_ciSANE_Status 249141cc406Sopenharmony_cikvs40xx_sense_handler (int __sane_unused__ fd, 250141cc406Sopenharmony_ci u_char * sense_buffer, void __sane_unused__ * arg) 251141cc406Sopenharmony_ci{ 252141cc406Sopenharmony_ci unsigned i; 253141cc406Sopenharmony_ci SANE_Status st = SANE_STATUS_GOOD; 254141cc406Sopenharmony_ci if (sense_buffer[2] & 0xf) 255141cc406Sopenharmony_ci { /*error */ 256141cc406Sopenharmony_ci for (i = 0; i < sizeof (s_errors) / sizeof (s_errors[0]); i++) 257141cc406Sopenharmony_ci { 258141cc406Sopenharmony_ci if ((sense_buffer[2] & 0xf) == s_errors[i].sense 259141cc406Sopenharmony_ci && sense_buffer[12] == s_errors[i].asc 260141cc406Sopenharmony_ci && sense_buffer[13] == s_errors[i].ascq) 261141cc406Sopenharmony_ci { 262141cc406Sopenharmony_ci st = s_errors[i].st; 263141cc406Sopenharmony_ci break; 264141cc406Sopenharmony_ci } 265141cc406Sopenharmony_ci } 266141cc406Sopenharmony_ci if (i == sizeof (s_errors) / sizeof (s_errors[0])) 267141cc406Sopenharmony_ci st = SANE_STATUS_IO_ERROR; 268141cc406Sopenharmony_ci } 269141cc406Sopenharmony_ci else 270141cc406Sopenharmony_ci { 271141cc406Sopenharmony_ci if (sense_buffer[2] & END_OF_MEDIUM) 272141cc406Sopenharmony_ci st = SANE_STATUS_EOF; 273141cc406Sopenharmony_ci else if (sense_buffer[2] & INCORRECT_LENGTH_INDICATOR) 274141cc406Sopenharmony_ci st = INCORRECT_LENGTH; 275141cc406Sopenharmony_ci } 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci DBG (DBG_ERR, 278141cc406Sopenharmony_ci "send_command: CHECK_CONDITION: sense:0x%x ASC:0x%x ASCQ:0x%x\n", 279141cc406Sopenharmony_ci sense_buffer[2], sense_buffer[12], sense_buffer[13]); 280141cc406Sopenharmony_ci 281141cc406Sopenharmony_ci return st; 282141cc406Sopenharmony_ci} 283141cc406Sopenharmony_ci 284141cc406Sopenharmony_cistatic SANE_Status 285141cc406Sopenharmony_cisend_command (struct scanner * s, struct cmd * c) 286141cc406Sopenharmony_ci{ 287141cc406Sopenharmony_ci SANE_Status st = SANE_STATUS_GOOD; 288141cc406Sopenharmony_ci if (s->bus == USB) 289141cc406Sopenharmony_ci { 290141cc406Sopenharmony_ci struct response r; 291141cc406Sopenharmony_ci memset (&r, 0, sizeof (r)); 292141cc406Sopenharmony_ci st = usb_send_command (s, c, &r, s->buffer); 293141cc406Sopenharmony_ci if (st) 294141cc406Sopenharmony_ci return st; 295141cc406Sopenharmony_ci if (r.status) 296141cc406Sopenharmony_ci { 297141cc406Sopenharmony_ci u8 b[sizeof (struct bulk_header) + RESPONSE_SIZE]; 298141cc406Sopenharmony_ci struct cmd c2 = { 299141cc406Sopenharmony_ci {0}, 6, 300141cc406Sopenharmony_ci NULL, RESPONSE_SIZE, 301141cc406Sopenharmony_ci CMD_IN 302141cc406Sopenharmony_ci }; 303141cc406Sopenharmony_ci c2.cmd[0] = REQUEST_SENSE; 304141cc406Sopenharmony_ci c2.cmd[4] = RESPONSE_SIZE; 305141cc406Sopenharmony_ci 306141cc406Sopenharmony_ci st = usb_send_command (s, &c2, &r, b); 307141cc406Sopenharmony_ci if (st) 308141cc406Sopenharmony_ci return st; 309141cc406Sopenharmony_ci st = kvs40xx_sense_handler (0, b + sizeof (struct bulk_header), NULL); 310141cc406Sopenharmony_ci } 311141cc406Sopenharmony_ci } 312141cc406Sopenharmony_ci else 313141cc406Sopenharmony_ci { 314141cc406Sopenharmony_ci if (c->dir == CMD_OUT) 315141cc406Sopenharmony_ci { 316141cc406Sopenharmony_ci memcpy (s->buffer, c->cmd, c->cmd_size); 317141cc406Sopenharmony_ci memcpy (s->buffer + c->cmd_size, c->data, c->data_size); 318141cc406Sopenharmony_ci st = sanei_scsi_cmd (s->file, s->buffer, 319141cc406Sopenharmony_ci c->cmd_size + c->data_size, NULL, NULL); 320141cc406Sopenharmony_ci } 321141cc406Sopenharmony_ci else if (c->dir == CMD_IN) 322141cc406Sopenharmony_ci { 323141cc406Sopenharmony_ci c->data = s->buffer; 324141cc406Sopenharmony_ci st = sanei_scsi_cmd (s->file, c->cmd, c->cmd_size, 325141cc406Sopenharmony_ci c->data, (size_t *) & c->data_size); 326141cc406Sopenharmony_ci } 327141cc406Sopenharmony_ci else 328141cc406Sopenharmony_ci { 329141cc406Sopenharmony_ci st = sanei_scsi_cmd (s->file, c->cmd, c->cmd_size, NULL, NULL); 330141cc406Sopenharmony_ci } 331141cc406Sopenharmony_ci } 332141cc406Sopenharmony_ci return st; 333141cc406Sopenharmony_ci} 334141cc406Sopenharmony_ci 335141cc406Sopenharmony_ciSANE_Status 336141cc406Sopenharmony_cikvs40xx_test_unit_ready (struct scanner * s) 337141cc406Sopenharmony_ci{ 338141cc406Sopenharmony_ci struct cmd c = { 339141cc406Sopenharmony_ci {0}, 6, 340141cc406Sopenharmony_ci NULL, 0, 341141cc406Sopenharmony_ci CMD_NONE 342141cc406Sopenharmony_ci }; 343141cc406Sopenharmony_ci c.cmd[0] = TEST_UNIT_READY; 344141cc406Sopenharmony_ci if (send_command (s, &c)) 345141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 346141cc406Sopenharmony_ci 347141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 348141cc406Sopenharmony_ci} 349141cc406Sopenharmony_ci 350141cc406Sopenharmony_ciSANE_Status 351141cc406Sopenharmony_cikvs40xx_set_timeout (struct scanner * s, int timeout) 352141cc406Sopenharmony_ci{ 353141cc406Sopenharmony_ci u16 t = cpu2be16 ((u16) timeout); 354141cc406Sopenharmony_ci struct cmd c = { 355141cc406Sopenharmony_ci {0}, 10, 356141cc406Sopenharmony_ci NULL, 0, 357141cc406Sopenharmony_ci CMD_OUT 358141cc406Sopenharmony_ci }; 359141cc406Sopenharmony_ci c.data = &t; 360141cc406Sopenharmony_ci c.data_size = sizeof (t); 361141cc406Sopenharmony_ci c.cmd[0] = SET_TIMEOUT; 362141cc406Sopenharmony_ci c.cmd[2] = 0x8d; 363141cc406Sopenharmony_ci copy16 (c.cmd + 7, cpu2be16 (sizeof (t))); 364141cc406Sopenharmony_ci if (s->bus == USB) 365141cc406Sopenharmony_ci sanei_usb_set_timeout (timeout * 1000); 366141cc406Sopenharmony_ci 367141cc406Sopenharmony_ci return send_command (s, &c); 368141cc406Sopenharmony_ci} 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_ciSANE_Status 371141cc406Sopenharmony_cikvs40xx_set_window (struct scanner * s, int wnd_id) 372141cc406Sopenharmony_ci{ 373141cc406Sopenharmony_ci struct window wnd; 374141cc406Sopenharmony_ci struct cmd c = { 375141cc406Sopenharmony_ci {0}, 10, 376141cc406Sopenharmony_ci NULL, 0, 377141cc406Sopenharmony_ci CMD_OUT 378141cc406Sopenharmony_ci }; 379141cc406Sopenharmony_ci c.data = &wnd; 380141cc406Sopenharmony_ci c.data_size = sizeof (wnd); 381141cc406Sopenharmony_ci c.cmd[0] = SET_WINDOW; 382141cc406Sopenharmony_ci copy16 (c.cmd + 7, cpu2be16 (sizeof (wnd))); 383141cc406Sopenharmony_ci kvs40xx_init_window (s, &wnd, wnd_id); 384141cc406Sopenharmony_ci 385141cc406Sopenharmony_ci return send_command (s, &c); 386141cc406Sopenharmony_ci} 387141cc406Sopenharmony_ci 388141cc406Sopenharmony_ciSANE_Status 389141cc406Sopenharmony_cikvs40xx_reset_window (struct scanner * s) 390141cc406Sopenharmony_ci{ 391141cc406Sopenharmony_ci struct cmd c = { 392141cc406Sopenharmony_ci {0}, 10, 393141cc406Sopenharmony_ci NULL, 0, 394141cc406Sopenharmony_ci CMD_NONE 395141cc406Sopenharmony_ci }; 396141cc406Sopenharmony_ci c.cmd[0] = SET_WINDOW; 397141cc406Sopenharmony_ci 398141cc406Sopenharmony_ci return send_command (s, &c); 399141cc406Sopenharmony_ci} 400141cc406Sopenharmony_ci 401141cc406Sopenharmony_ciSANE_Status 402141cc406Sopenharmony_cikvs40xx_scan (struct scanner * s) 403141cc406Sopenharmony_ci{ 404141cc406Sopenharmony_ci struct cmd c = { 405141cc406Sopenharmony_ci {0}, 6, 406141cc406Sopenharmony_ci NULL, 0, 407141cc406Sopenharmony_ci CMD_NONE 408141cc406Sopenharmony_ci }; 409141cc406Sopenharmony_ci c.cmd[0] = SCAN; 410141cc406Sopenharmony_ci return send_command (s, &c); 411141cc406Sopenharmony_ci} 412141cc406Sopenharmony_ci 413141cc406Sopenharmony_ciSANE_Status 414141cc406Sopenharmony_cihopper_down (struct scanner * s) 415141cc406Sopenharmony_ci{ 416141cc406Sopenharmony_ci struct cmd c = { 417141cc406Sopenharmony_ci {0}, 10, 418141cc406Sopenharmony_ci NULL, 0, 419141cc406Sopenharmony_ci CMD_NONE 420141cc406Sopenharmony_ci }; 421141cc406Sopenharmony_ci c.cmd[0] = HOPPER_DOWN; 422141cc406Sopenharmony_ci c.cmd[2] = 5; 423141cc406Sopenharmony_ci 424141cc406Sopenharmony_ci if (s->id == KV_S7075C) 425141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 426141cc406Sopenharmony_ci return send_command (s, &c); 427141cc406Sopenharmony_ci} 428141cc406Sopenharmony_ci 429141cc406Sopenharmony_ciSANE_Status 430141cc406Sopenharmony_cistop_adf (struct scanner * s) 431141cc406Sopenharmony_ci{ 432141cc406Sopenharmony_ci struct cmd c = { 433141cc406Sopenharmony_ci {0}, 10, 434141cc406Sopenharmony_ci NULL, 0, 435141cc406Sopenharmony_ci CMD_NONE 436141cc406Sopenharmony_ci }; 437141cc406Sopenharmony_ci c.cmd[0] = STOP_ADF; 438141cc406Sopenharmony_ci c.cmd[2] = 0x8b; 439141cc406Sopenharmony_ci return send_command (s, &c); 440141cc406Sopenharmony_ci} 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_ciSANE_Status 443141cc406Sopenharmony_cikvs40xx_document_exist (struct scanner * s) 444141cc406Sopenharmony_ci{ 445141cc406Sopenharmony_ci SANE_Status status; 446141cc406Sopenharmony_ci struct cmd c = { 447141cc406Sopenharmony_ci {0}, 10, 448141cc406Sopenharmony_ci NULL, 6, 449141cc406Sopenharmony_ci CMD_IN 450141cc406Sopenharmony_ci }; 451141cc406Sopenharmony_ci u8 *d; 452141cc406Sopenharmony_ci c.cmd[0] = READ_10; 453141cc406Sopenharmony_ci c.cmd[2] = 0x81; 454141cc406Sopenharmony_ci set24 (c.cmd + 6, c.data_size); 455141cc406Sopenharmony_ci status = send_command (s, &c); 456141cc406Sopenharmony_ci if (status) 457141cc406Sopenharmony_ci return status; 458141cc406Sopenharmony_ci d = c.data; 459141cc406Sopenharmony_ci if (d[0] & 0x20) 460141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 461141cc406Sopenharmony_ci 462141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 463141cc406Sopenharmony_ci} 464141cc406Sopenharmony_ci 465141cc406Sopenharmony_ciSANE_Status 466141cc406Sopenharmony_cikvs40xx_read_picture_element (struct scanner * s, unsigned side, 467141cc406Sopenharmony_ci SANE_Parameters * p) 468141cc406Sopenharmony_ci{ 469141cc406Sopenharmony_ci SANE_Status status; 470141cc406Sopenharmony_ci struct cmd c = { 471141cc406Sopenharmony_ci {0}, 10, 472141cc406Sopenharmony_ci NULL, 16, 473141cc406Sopenharmony_ci CMD_IN 474141cc406Sopenharmony_ci }; 475141cc406Sopenharmony_ci u32 *data; 476141cc406Sopenharmony_ci c.cmd[0] = READ_10; 477141cc406Sopenharmony_ci c.cmd[2] = 0x80; 478141cc406Sopenharmony_ci c.cmd[5] = side; 479141cc406Sopenharmony_ci set24 (c.cmd + 6, c.data_size); 480141cc406Sopenharmony_ci 481141cc406Sopenharmony_ci status = send_command (s, &c); 482141cc406Sopenharmony_ci if (status) 483141cc406Sopenharmony_ci return status; 484141cc406Sopenharmony_ci data = (u32 *) c.data; 485141cc406Sopenharmony_ci p->pixels_per_line = be2cpu32 (data[0]); 486141cc406Sopenharmony_ci p->lines = be2cpu32 (data[1]); 487141cc406Sopenharmony_ci 488141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 489141cc406Sopenharmony_ci} 490141cc406Sopenharmony_ci 491141cc406Sopenharmony_ciSANE_Status 492141cc406Sopenharmony_ciget_buffer_status (struct scanner * s, unsigned *data_avalible) 493141cc406Sopenharmony_ci{ 494141cc406Sopenharmony_ci SANE_Status status; 495141cc406Sopenharmony_ci struct cmd c = { 496141cc406Sopenharmony_ci {0}, 10, 497141cc406Sopenharmony_ci NULL, 12, 498141cc406Sopenharmony_ci CMD_IN 499141cc406Sopenharmony_ci }; 500141cc406Sopenharmony_ci c.cmd[0] = GET_BUFFER_STATUS; 501141cc406Sopenharmony_ci c.cmd[7] = 12; 502141cc406Sopenharmony_ci 503141cc406Sopenharmony_ci status = send_command (s, &c); 504141cc406Sopenharmony_ci if (status) 505141cc406Sopenharmony_ci return status; 506141cc406Sopenharmony_ci *data_avalible = get24 ((unsigned char *)c.data + 9); 507141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 508141cc406Sopenharmony_ci} 509141cc406Sopenharmony_ci 510141cc406Sopenharmony_ciSANE_Status 511141cc406Sopenharmony_cikvs40xx_read_image_data (struct scanner * s, unsigned page, unsigned side, 512141cc406Sopenharmony_ci void *buf, unsigned max_size, unsigned *size) 513141cc406Sopenharmony_ci{ 514141cc406Sopenharmony_ci SANE_Status status; 515141cc406Sopenharmony_ci struct cmd c = { 516141cc406Sopenharmony_ci {0}, 10, 517141cc406Sopenharmony_ci NULL, 0, 518141cc406Sopenharmony_ci CMD_IN 519141cc406Sopenharmony_ci }; 520141cc406Sopenharmony_ci c.data_size = max_size < MAX_READ_DATA_SIZE ? max_size : MAX_READ_DATA_SIZE; 521141cc406Sopenharmony_ci c.cmd[0] = READ_10; 522141cc406Sopenharmony_ci c.cmd[4] = page; 523141cc406Sopenharmony_ci c.cmd[5] = side; 524141cc406Sopenharmony_ci 525141cc406Sopenharmony_ci set24 (c.cmd + 6, c.data_size); 526141cc406Sopenharmony_ci *size = 0; 527141cc406Sopenharmony_ci status = send_command (s, &c); 528141cc406Sopenharmony_ci 529141cc406Sopenharmony_ci if (status && status != SANE_STATUS_EOF && status != INCORRECT_LENGTH) 530141cc406Sopenharmony_ci return status; 531141cc406Sopenharmony_ci 532141cc406Sopenharmony_ci *size = c.data_size; 533141cc406Sopenharmony_ci memcpy (buf, c.data, *size); 534141cc406Sopenharmony_ci return status; 535141cc406Sopenharmony_ci} 536141cc406Sopenharmony_ci 537141cc406Sopenharmony_ciSANE_Status 538141cc406Sopenharmony_ciread_support_info (struct scanner * s, struct support_info * inf) 539141cc406Sopenharmony_ci{ 540141cc406Sopenharmony_ci SANE_Status st; 541141cc406Sopenharmony_ci struct cmd c = { 542141cc406Sopenharmony_ci {0}, 10, 543141cc406Sopenharmony_ci NULL, sizeof (*inf), 544141cc406Sopenharmony_ci CMD_IN 545141cc406Sopenharmony_ci }; 546141cc406Sopenharmony_ci 547141cc406Sopenharmony_ci c.cmd[0] = READ_10; 548141cc406Sopenharmony_ci c.cmd[2] = SUPPORT_INFO; 549141cc406Sopenharmony_ci set24 (c.cmd + 6, c.data_size); 550141cc406Sopenharmony_ci 551141cc406Sopenharmony_ci st = send_command (s, &c); 552141cc406Sopenharmony_ci if (st) 553141cc406Sopenharmony_ci return st; 554141cc406Sopenharmony_ci memcpy (inf, c.data, sizeof (*inf)); 555141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 556141cc406Sopenharmony_ci} 557141cc406Sopenharmony_ci 558141cc406Sopenharmony_ciSANE_Status 559141cc406Sopenharmony_ciinquiry (struct scanner * s, char *id) 560141cc406Sopenharmony_ci{ 561141cc406Sopenharmony_ci int i; 562141cc406Sopenharmony_ci SANE_Status st; 563141cc406Sopenharmony_ci struct cmd c = { 564141cc406Sopenharmony_ci {0}, 5, 565141cc406Sopenharmony_ci NULL, 0x60, 566141cc406Sopenharmony_ci CMD_IN 567141cc406Sopenharmony_ci }; 568141cc406Sopenharmony_ci 569141cc406Sopenharmony_ci c.cmd[0] = INQUIRY; 570141cc406Sopenharmony_ci c.cmd[4] = c.data_size; 571141cc406Sopenharmony_ci 572141cc406Sopenharmony_ci st = send_command (s, &c); 573141cc406Sopenharmony_ci if (st) 574141cc406Sopenharmony_ci return st; 575141cc406Sopenharmony_ci memcpy (id, (unsigned char *)c.data + 16, 16); 576141cc406Sopenharmony_ci for (i = 0; i < 15 && id[i] != ' '; i++); 577141cc406Sopenharmony_ci id[i] = 0; 578141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 579141cc406Sopenharmony_ci} 580