1141cc406Sopenharmony_ci/* 2141cc406Sopenharmony_ci Copyright (C) 2008, Panasonic Russia Ltd. 3141cc406Sopenharmony_ci Copyright (C) 2010, m. allan noah 4141cc406Sopenharmony_ci*/ 5141cc406Sopenharmony_ci/* 6141cc406Sopenharmony_ci Panasonic KV-S20xx USB-SCSI scanners. 7141cc406Sopenharmony_ci*/ 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci#include "../include/sane/config.h" 10141cc406Sopenharmony_ci 11141cc406Sopenharmony_ci#include <string.h> 12141cc406Sopenharmony_ci/*#include <unistd.h>*/ 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 15141cc406Sopenharmony_ci#define BACKEND_NAME kvs20xx 16141cc406Sopenharmony_ci 17141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 18141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h" 19141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci#include "kvs20xx.h" 22141cc406Sopenharmony_ci#include "kvs20xx_cmd.h" 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_cistatic SANE_Status 25141cc406Sopenharmony_ciusb_send_command (struct scanner *s, struct cmd *c, struct response *r, 26141cc406Sopenharmony_ci void *buf) 27141cc406Sopenharmony_ci{ 28141cc406Sopenharmony_ci SANE_Status st; 29141cc406Sopenharmony_ci struct bulk_header *h = (struct bulk_header *) buf; 30141cc406Sopenharmony_ci u8 resp[sizeof (*h) + STATUS_SIZE]; 31141cc406Sopenharmony_ci size_t sz = sizeof (*h) + MAX_CMD_SIZE; 32141cc406Sopenharmony_ci memset (h, 0, sz); 33141cc406Sopenharmony_ci h->length = cpu2be32 (sz); 34141cc406Sopenharmony_ci h->type = cpu2be16 (COMMAND_BLOCK); 35141cc406Sopenharmony_ci h->code = cpu2be16 (COMMAND_CODE); 36141cc406Sopenharmony_ci memcpy (h + 1, c->cmd, c->cmd_size); 37141cc406Sopenharmony_ci 38141cc406Sopenharmony_ci st = sanei_usb_write_bulk (s->file, (const SANE_Byte *) h, &sz); 39141cc406Sopenharmony_ci if (st) 40141cc406Sopenharmony_ci return st; 41141cc406Sopenharmony_ci if (sz != sizeof (*h) + MAX_CMD_SIZE) 42141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 43141cc406Sopenharmony_ci if (c->dir == CMD_IN) 44141cc406Sopenharmony_ci { 45141cc406Sopenharmony_ci sz = sizeof (*h) + c->data_size; 46141cc406Sopenharmony_ci st = sanei_usb_read_bulk (s->file, (SANE_Byte *) h, &sz); 47141cc406Sopenharmony_ci c->data = h + 1; 48141cc406Sopenharmony_ci c->data_size = sz - sizeof (*h); 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_ci if (st || sz < sizeof (*h)) 51141cc406Sopenharmony_ci { 52141cc406Sopenharmony_ci st = sanei_usb_release_interface (s->file, 0); 53141cc406Sopenharmony_ci if (st) 54141cc406Sopenharmony_ci return st; 55141cc406Sopenharmony_ci st = sanei_usb_claim_interface (s->file, 0); 56141cc406Sopenharmony_ci if (st) 57141cc406Sopenharmony_ci return st; 58141cc406Sopenharmony_ci r->status = CHECK_CONDITION; 59141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 60141cc406Sopenharmony_ci } 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci } 63141cc406Sopenharmony_ci else if (c->dir == CMD_OUT) 64141cc406Sopenharmony_ci { 65141cc406Sopenharmony_ci sz = sizeof (*h) + c->data_size; 66141cc406Sopenharmony_ci memset (h, 0, sizeof (*h)); 67141cc406Sopenharmony_ci h->length = cpu2be32 (sizeof (*h) + c->data_size); 68141cc406Sopenharmony_ci h->type = cpu2be16 (DATA_BLOCK); 69141cc406Sopenharmony_ci h->code = cpu2be16 (DATA_CODE); 70141cc406Sopenharmony_ci memcpy (h + 1, c->data, c->data_size); 71141cc406Sopenharmony_ci st = sanei_usb_write_bulk (s->file, (const SANE_Byte *) h, &sz); 72141cc406Sopenharmony_ci if (st) 73141cc406Sopenharmony_ci return st; 74141cc406Sopenharmony_ci } 75141cc406Sopenharmony_ci sz = sizeof (resp); 76141cc406Sopenharmony_ci st = sanei_usb_read_bulk (s->file, resp, &sz); 77141cc406Sopenharmony_ci if (st || sz != sizeof (resp)) 78141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 79141cc406Sopenharmony_ci r->status = be2cpu32 (*((u32 *) (resp + sizeof (*h)))); 80141cc406Sopenharmony_ci return st; 81141cc406Sopenharmony_ci} 82141cc406Sopenharmony_ci 83141cc406Sopenharmony_ciSANE_Status 84141cc406Sopenharmony_cikvs20xx_sense_handler (int __sane_unused__ fd, 85141cc406Sopenharmony_ci u_char * sense_buffer, void __sane_unused__ * arg) 86141cc406Sopenharmony_ci{ 87141cc406Sopenharmony_ci unsigned i; 88141cc406Sopenharmony_ci SANE_Status st = SANE_STATUS_GOOD; 89141cc406Sopenharmony_ci for (i = 0; i < sizeof (s_errors) / sizeof (s_errors[0]); i++) 90141cc406Sopenharmony_ci if ((sense_buffer[2] & 0xf) == s_errors[i].sense 91141cc406Sopenharmony_ci && sense_buffer[12] == s_errors[i].asc 92141cc406Sopenharmony_ci && sense_buffer[13] == s_errors[i].ascq) 93141cc406Sopenharmony_ci { 94141cc406Sopenharmony_ci st = s_errors[i].st; 95141cc406Sopenharmony_ci break; 96141cc406Sopenharmony_ci } 97141cc406Sopenharmony_ci if (st == SANE_STATUS_GOOD && sense_buffer[2] & END_OF_MEDIUM) 98141cc406Sopenharmony_ci st = SANE_STATUS_EOF; 99141cc406Sopenharmony_ci if (i == sizeof (s_errors) / sizeof (s_errors[0])) 100141cc406Sopenharmony_ci st = SANE_STATUS_IO_ERROR; 101141cc406Sopenharmony_ci DBG (DBG_ERR, 102141cc406Sopenharmony_ci "send_command: CHECK_CONDITION: sense:0x%x ASC:0x%x ASCQ:0x%x\n", 103141cc406Sopenharmony_ci sense_buffer[2], sense_buffer[12], sense_buffer[13]); 104141cc406Sopenharmony_ci 105141cc406Sopenharmony_ci return st; 106141cc406Sopenharmony_ci} 107141cc406Sopenharmony_ci 108141cc406Sopenharmony_cistatic SANE_Status 109141cc406Sopenharmony_cisend_command (struct scanner * s, struct cmd * c) 110141cc406Sopenharmony_ci{ 111141cc406Sopenharmony_ci SANE_Status st = SANE_STATUS_GOOD; 112141cc406Sopenharmony_ci if (s->bus == USB) 113141cc406Sopenharmony_ci { 114141cc406Sopenharmony_ci struct response r; 115141cc406Sopenharmony_ci memset (&r, 0, sizeof (r)); 116141cc406Sopenharmony_ci st = usb_send_command (s, c, &r, s->buffer); 117141cc406Sopenharmony_ci if (st) 118141cc406Sopenharmony_ci return st; 119141cc406Sopenharmony_ci if (r.status) 120141cc406Sopenharmony_ci { 121141cc406Sopenharmony_ci u8 b[sizeof (struct bulk_header) + RESPONSE_SIZE]; 122141cc406Sopenharmony_ci struct cmd c2 = { 123141cc406Sopenharmony_ci {0}, 124141cc406Sopenharmony_ci 6, 125141cc406Sopenharmony_ci 0, 126141cc406Sopenharmony_ci RESPONSE_SIZE, 127141cc406Sopenharmony_ci CMD_IN 128141cc406Sopenharmony_ci }; 129141cc406Sopenharmony_ci c2.cmd[0] = REQUEST_SENSE; 130141cc406Sopenharmony_ci c2.cmd[4] = RESPONSE_SIZE; 131141cc406Sopenharmony_ci st = usb_send_command (s, &c2, &r, b); 132141cc406Sopenharmony_ci if (st) 133141cc406Sopenharmony_ci return st; 134141cc406Sopenharmony_ci st = kvs20xx_sense_handler (0, b + sizeof (struct bulk_header), NULL); 135141cc406Sopenharmony_ci } 136141cc406Sopenharmony_ci } 137141cc406Sopenharmony_ci else 138141cc406Sopenharmony_ci { 139141cc406Sopenharmony_ci if (c->dir == CMD_OUT) 140141cc406Sopenharmony_ci { 141141cc406Sopenharmony_ci memcpy (s->buffer, c->cmd, c->cmd_size); 142141cc406Sopenharmony_ci memcpy (s->buffer + c->cmd_size, c->data, c->data_size); 143141cc406Sopenharmony_ci st = sanei_scsi_cmd (s->file, s->buffer, c->cmd_size + c->data_size, 144141cc406Sopenharmony_ci NULL, NULL); 145141cc406Sopenharmony_ci } 146141cc406Sopenharmony_ci else if (c->dir == CMD_IN) 147141cc406Sopenharmony_ci { 148141cc406Sopenharmony_ci c->data = s->buffer; 149141cc406Sopenharmony_ci st = sanei_scsi_cmd (s->file, c->cmd, c->cmd_size, 150141cc406Sopenharmony_ci c->data, (size_t *) & c->data_size); 151141cc406Sopenharmony_ci } 152141cc406Sopenharmony_ci else 153141cc406Sopenharmony_ci { 154141cc406Sopenharmony_ci st = sanei_scsi_cmd (s->file, c->cmd, c->cmd_size, NULL, NULL); 155141cc406Sopenharmony_ci } 156141cc406Sopenharmony_ci } 157141cc406Sopenharmony_ci return st; 158141cc406Sopenharmony_ci} 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_ciSANE_Status 161141cc406Sopenharmony_cikvs20xx_test_unit_ready (struct scanner * s) 162141cc406Sopenharmony_ci{ 163141cc406Sopenharmony_ci struct cmd c = { 164141cc406Sopenharmony_ci {0}, 165141cc406Sopenharmony_ci 6, 166141cc406Sopenharmony_ci 0, 167141cc406Sopenharmony_ci 0, 168141cc406Sopenharmony_ci CMD_NONE 169141cc406Sopenharmony_ci }; 170141cc406Sopenharmony_ci c.cmd[0] = TEST_UNIT_READY; 171141cc406Sopenharmony_ci if (send_command (s, &c)) 172141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 173141cc406Sopenharmony_ci 174141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 175141cc406Sopenharmony_ci} 176141cc406Sopenharmony_ci 177141cc406Sopenharmony_ciSANE_Status 178141cc406Sopenharmony_cikvs20xx_set_timeout (struct scanner * s, int timeout) 179141cc406Sopenharmony_ci{ 180141cc406Sopenharmony_ci u16 t = cpu2be16 ((u16) timeout); 181141cc406Sopenharmony_ci struct cmd c = { 182141cc406Sopenharmony_ci {0}, 183141cc406Sopenharmony_ci 10, 184141cc406Sopenharmony_ci 0, 185141cc406Sopenharmony_ci 0, 186141cc406Sopenharmony_ci CMD_OUT 187141cc406Sopenharmony_ci }; 188141cc406Sopenharmony_ci c.cmd[0] = SET_TIMEOUT; 189141cc406Sopenharmony_ci c.cmd[2] = 0x8d; 190141cc406Sopenharmony_ci copy16 (c.cmd + 7, cpu2be16 (sizeof (t))); 191141cc406Sopenharmony_ci 192141cc406Sopenharmony_ci c.data = &t; 193141cc406Sopenharmony_ci c.data_size = sizeof (t); 194141cc406Sopenharmony_ci 195141cc406Sopenharmony_ci if (s->bus == USB) 196141cc406Sopenharmony_ci sanei_usb_set_timeout (timeout * 1000); 197141cc406Sopenharmony_ci 198141cc406Sopenharmony_ci return send_command (s, &c); 199141cc406Sopenharmony_ci} 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_ciSANE_Status 202141cc406Sopenharmony_cikvs20xx_set_window (struct scanner * s, int wnd_id) 203141cc406Sopenharmony_ci{ 204141cc406Sopenharmony_ci struct window wnd; 205141cc406Sopenharmony_ci struct cmd c = { 206141cc406Sopenharmony_ci {0}, 207141cc406Sopenharmony_ci 10, 208141cc406Sopenharmony_ci 0, 209141cc406Sopenharmony_ci 0, 210141cc406Sopenharmony_ci CMD_OUT 211141cc406Sopenharmony_ci }; 212141cc406Sopenharmony_ci c.cmd[0] = SET_WINDOW; 213141cc406Sopenharmony_ci copy16 (c.cmd + 7, cpu2be16 (sizeof (wnd))); 214141cc406Sopenharmony_ci 215141cc406Sopenharmony_ci c.data = &wnd; 216141cc406Sopenharmony_ci c.data_size = sizeof (wnd); 217141cc406Sopenharmony_ci 218141cc406Sopenharmony_ci kvs20xx_init_window (s, &wnd, wnd_id); 219141cc406Sopenharmony_ci 220141cc406Sopenharmony_ci return send_command (s, &c); 221141cc406Sopenharmony_ci} 222141cc406Sopenharmony_ci 223141cc406Sopenharmony_ciSANE_Status 224141cc406Sopenharmony_cikvs20xx_reset_window (struct scanner * s) 225141cc406Sopenharmony_ci{ 226141cc406Sopenharmony_ci struct cmd c = { 227141cc406Sopenharmony_ci {0}, 228141cc406Sopenharmony_ci 10, 229141cc406Sopenharmony_ci 0, 230141cc406Sopenharmony_ci 0, 231141cc406Sopenharmony_ci CMD_NONE 232141cc406Sopenharmony_ci }; 233141cc406Sopenharmony_ci c.cmd[0] = SET_WINDOW; 234141cc406Sopenharmony_ci 235141cc406Sopenharmony_ci return send_command (s, &c); 236141cc406Sopenharmony_ci} 237141cc406Sopenharmony_ci 238141cc406Sopenharmony_ciSANE_Status 239141cc406Sopenharmony_cikvs20xx_scan (struct scanner * s) 240141cc406Sopenharmony_ci{ 241141cc406Sopenharmony_ci struct cmd c = { 242141cc406Sopenharmony_ci {0}, 243141cc406Sopenharmony_ci 6, 244141cc406Sopenharmony_ci 0, 245141cc406Sopenharmony_ci 0, 246141cc406Sopenharmony_ci CMD_NONE 247141cc406Sopenharmony_ci }; 248141cc406Sopenharmony_ci c.cmd[0] = SCAN; 249141cc406Sopenharmony_ci return send_command (s, &c); 250141cc406Sopenharmony_ci} 251141cc406Sopenharmony_ci 252141cc406Sopenharmony_ciSANE_Status 253141cc406Sopenharmony_cikvs20xx_document_exist (struct scanner * s) 254141cc406Sopenharmony_ci{ 255141cc406Sopenharmony_ci SANE_Status status; 256141cc406Sopenharmony_ci struct cmd c = { 257141cc406Sopenharmony_ci {0}, 258141cc406Sopenharmony_ci 10, 259141cc406Sopenharmony_ci 0, 260141cc406Sopenharmony_ci 6, 261141cc406Sopenharmony_ci CMD_IN, 262141cc406Sopenharmony_ci }; 263141cc406Sopenharmony_ci u8 *d; 264141cc406Sopenharmony_ci c.cmd[0] = READ_10; 265141cc406Sopenharmony_ci c.cmd[2] = 0x81; 266141cc406Sopenharmony_ci set24 (c.cmd + 6, c.data_size); 267141cc406Sopenharmony_ci status = send_command (s, &c); 268141cc406Sopenharmony_ci if (status) 269141cc406Sopenharmony_ci return status; 270141cc406Sopenharmony_ci d = c.data; 271141cc406Sopenharmony_ci if (d[0] & 0x20) 272141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 273141cc406Sopenharmony_ci 274141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 275141cc406Sopenharmony_ci} 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ciSANE_Status 278141cc406Sopenharmony_cikvs20xx_read_picture_element (struct scanner * s, unsigned side, 279141cc406Sopenharmony_ci SANE_Parameters * p) 280141cc406Sopenharmony_ci{ 281141cc406Sopenharmony_ci SANE_Status status; 282141cc406Sopenharmony_ci struct cmd c = { 283141cc406Sopenharmony_ci {0}, 284141cc406Sopenharmony_ci 10, 285141cc406Sopenharmony_ci 0, 286141cc406Sopenharmony_ci 16, 287141cc406Sopenharmony_ci CMD_IN 288141cc406Sopenharmony_ci }; 289141cc406Sopenharmony_ci u32 *data; 290141cc406Sopenharmony_ci c.cmd[0] = READ_10; 291141cc406Sopenharmony_ci c.cmd[2] = 0x80; 292141cc406Sopenharmony_ci c.cmd[5] = side; 293141cc406Sopenharmony_ci set24 (c.cmd + 6, c.data_size); 294141cc406Sopenharmony_ci 295141cc406Sopenharmony_ci status = send_command (s, &c); 296141cc406Sopenharmony_ci if (status) 297141cc406Sopenharmony_ci return status; 298141cc406Sopenharmony_ci data = (u32 *) c.data; 299141cc406Sopenharmony_ci p->pixels_per_line = be2cpu32 (data[0]); 300141cc406Sopenharmony_ci p->lines = be2cpu32 (data[1]); 301141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 302141cc406Sopenharmony_ci} 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ciSANE_Status 305141cc406Sopenharmony_cikvs20xx_read_image_data (struct scanner * s, unsigned page, unsigned side, 306141cc406Sopenharmony_ci void *buf, unsigned max_size, unsigned *size) 307141cc406Sopenharmony_ci{ 308141cc406Sopenharmony_ci SANE_Status status; 309141cc406Sopenharmony_ci struct cmd c = { 310141cc406Sopenharmony_ci {0}, 311141cc406Sopenharmony_ci 10, 312141cc406Sopenharmony_ci 0, 313141cc406Sopenharmony_ci 0, 314141cc406Sopenharmony_ci CMD_IN 315141cc406Sopenharmony_ci }; 316141cc406Sopenharmony_ci c.cmd[0] = READ_10; 317141cc406Sopenharmony_ci c.cmd[4] = page; 318141cc406Sopenharmony_ci c.cmd[5] = side; 319141cc406Sopenharmony_ci 320141cc406Sopenharmony_ci c.data_size = max_size < MAX_READ_DATA_SIZE ? max_size : MAX_READ_DATA_SIZE; 321141cc406Sopenharmony_ci 322141cc406Sopenharmony_ci set24 (c.cmd + 6, c.data_size); 323141cc406Sopenharmony_ci status = send_command (s, &c); 324141cc406Sopenharmony_ci 325141cc406Sopenharmony_ci if (status && status != SANE_STATUS_EOF) 326141cc406Sopenharmony_ci return status; 327141cc406Sopenharmony_ci 328141cc406Sopenharmony_ci *size = c.data_size; 329141cc406Sopenharmony_ci DBG (DBG_INFO, "kvs20xx_read_image_data: read %d, status %d\n", *size, status); 330141cc406Sopenharmony_ci memcpy (buf, c.data, *size); 331141cc406Sopenharmony_ci return status; 332141cc406Sopenharmony_ci} 333141cc406Sopenharmony_ci 334141cc406Sopenharmony_ciSANE_Status 335141cc406Sopenharmony_ciget_adjust_data (struct scanner * s, unsigned *dummy_length) 336141cc406Sopenharmony_ci{ 337141cc406Sopenharmony_ci SANE_Status status; 338141cc406Sopenharmony_ci struct cmd c = { 339141cc406Sopenharmony_ci {0}, 340141cc406Sopenharmony_ci 10, 341141cc406Sopenharmony_ci 0, 342141cc406Sopenharmony_ci 40, 343141cc406Sopenharmony_ci CMD_IN 344141cc406Sopenharmony_ci }; 345141cc406Sopenharmony_ci u16 *data; 346141cc406Sopenharmony_ci 347141cc406Sopenharmony_ci c.cmd[0] = GET_ADJUST_DATA; 348141cc406Sopenharmony_ci c.cmd[2] = 0x9b; 349141cc406Sopenharmony_ci c.cmd[8] = 40; 350141cc406Sopenharmony_ci status = send_command (s, &c); 351141cc406Sopenharmony_ci if (status) 352141cc406Sopenharmony_ci return status; 353141cc406Sopenharmony_ci data = (u16 *) c.data; 354141cc406Sopenharmony_ci *dummy_length = be2cpu16 (data[0]); 355141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 356141cc406Sopenharmony_ci} 357