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#define DEBUG_NOT_STATIC 10141cc406Sopenharmony_ci#define BUILD 2 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci#include "../include/sane/config.h" 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci#include <string.h> 15141cc406Sopenharmony_ci#include <unistd.h> 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#include "../include/sane/saneopts.h" 21141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 22141cc406Sopenharmony_ci#include "../include/lassert.h" 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci#include "kvs20xx.h" 25141cc406Sopenharmony_ci#include "kvs20xx_cmd.h" 26141cc406Sopenharmony_ci 27141cc406Sopenharmony_cistruct known_device 28141cc406Sopenharmony_ci{ 29141cc406Sopenharmony_ci const SANE_Int id; 30141cc406Sopenharmony_ci const SANE_Device scanner; 31141cc406Sopenharmony_ci}; 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_cistatic const struct known_device known_devices[] = { 34141cc406Sopenharmony_ci { 35141cc406Sopenharmony_ci KV_S2025C, 36141cc406Sopenharmony_ci { "", "MATSHITA", "KV-S2025C", "sheetfed scanner" }, 37141cc406Sopenharmony_ci }, 38141cc406Sopenharmony_ci { 39141cc406Sopenharmony_ci KV_S2045C, 40141cc406Sopenharmony_ci { "", "MATSHITA", "KV-S2045C", "sheetfed scanner" }, 41141cc406Sopenharmony_ci }, 42141cc406Sopenharmony_ci { 43141cc406Sopenharmony_ci KV_S2026C, 44141cc406Sopenharmony_ci { "", "MATSHITA", "KV-S2026C", "sheetfed scanner" }, 45141cc406Sopenharmony_ci }, 46141cc406Sopenharmony_ci { 47141cc406Sopenharmony_ci KV_S2046C, 48141cc406Sopenharmony_ci { "", "MATSHITA", "KV-S2046C", "sheetfed scanner" }, 49141cc406Sopenharmony_ci }, 50141cc406Sopenharmony_ci { 51141cc406Sopenharmony_ci KV_S2028C, 52141cc406Sopenharmony_ci { "", "MATSHITA", "KV-S2028C", "sheetfed scanner" }, 53141cc406Sopenharmony_ci }, 54141cc406Sopenharmony_ci { 55141cc406Sopenharmony_ci KV_S2048C, 56141cc406Sopenharmony_ci { "", "MATSHITA", "KV-S2048C", "sheetfed scanner" }, 57141cc406Sopenharmony_ci }, 58141cc406Sopenharmony_ci}; 59141cc406Sopenharmony_ci 60141cc406Sopenharmony_ciSANE_Status 61141cc406Sopenharmony_cisane_init (SANE_Int __sane_unused__ * version_code, 62141cc406Sopenharmony_ci SANE_Auth_Callback __sane_unused__ authorize) 63141cc406Sopenharmony_ci{ 64141cc406Sopenharmony_ci DBG_INIT (); 65141cc406Sopenharmony_ci DBG (DBG_INFO, "This is panasonic kvs20xx driver\n"); 66141cc406Sopenharmony_ci 67141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD); 68141cc406Sopenharmony_ci 69141cc406Sopenharmony_ci /* Initialize USB */ 70141cc406Sopenharmony_ci sanei_usb_init (); 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 73141cc406Sopenharmony_ci} 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ci/* 76141cc406Sopenharmony_ci * List of available devices, allocated by sane_get_devices, released 77141cc406Sopenharmony_ci * by sane_exit() 78141cc406Sopenharmony_ci */ 79141cc406Sopenharmony_cistatic SANE_Device **devlist = NULL; 80141cc406Sopenharmony_cistatic unsigned curr_scan_dev = 0; 81141cc406Sopenharmony_ci 82141cc406Sopenharmony_civoid 83141cc406Sopenharmony_cisane_exit (void) 84141cc406Sopenharmony_ci{ 85141cc406Sopenharmony_ci if (devlist) 86141cc406Sopenharmony_ci { 87141cc406Sopenharmony_ci int i; 88141cc406Sopenharmony_ci for (i = 0; devlist[i]; i++) 89141cc406Sopenharmony_ci { 90141cc406Sopenharmony_ci free ((void *) devlist[i]->name); 91141cc406Sopenharmony_ci free ((void *) devlist[i]); 92141cc406Sopenharmony_ci } 93141cc406Sopenharmony_ci free ((void *) devlist); 94141cc406Sopenharmony_ci devlist = NULL; 95141cc406Sopenharmony_ci } 96141cc406Sopenharmony_ci} 97141cc406Sopenharmony_ci 98141cc406Sopenharmony_cistatic SANE_Status 99141cc406Sopenharmony_ciattach (SANE_String_Const devname) 100141cc406Sopenharmony_ci{ 101141cc406Sopenharmony_ci int i = 0; 102141cc406Sopenharmony_ci if (devlist) 103141cc406Sopenharmony_ci { 104141cc406Sopenharmony_ci for (; devlist[i]; i++); 105141cc406Sopenharmony_ci devlist = realloc (devlist, sizeof (SANE_Device *) * (i + 1)); 106141cc406Sopenharmony_ci if (!devlist) 107141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 108141cc406Sopenharmony_ci } 109141cc406Sopenharmony_ci else 110141cc406Sopenharmony_ci { 111141cc406Sopenharmony_ci devlist = malloc (sizeof (SANE_Device *) * 2); 112141cc406Sopenharmony_ci if (!devlist) 113141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 114141cc406Sopenharmony_ci } 115141cc406Sopenharmony_ci devlist[i] = malloc (sizeof (SANE_Device)); 116141cc406Sopenharmony_ci if (!devlist[i]) 117141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 118141cc406Sopenharmony_ci memcpy (devlist[i], &known_devices[curr_scan_dev].scanner, 119141cc406Sopenharmony_ci sizeof (SANE_Device)); 120141cc406Sopenharmony_ci devlist[i]->name = strdup (devname); 121141cc406Sopenharmony_ci /* terminate device list with NULL entry: */ 122141cc406Sopenharmony_ci devlist[i + 1] = 0; 123141cc406Sopenharmony_ci DBG (DBG_INFO, "%s device attached\n", devname); 124141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 125141cc406Sopenharmony_ci} 126141cc406Sopenharmony_ci 127141cc406Sopenharmony_ci/* Get device list */ 128141cc406Sopenharmony_ciSANE_Status 129141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, 130141cc406Sopenharmony_ci SANE_Bool __sane_unused__ local_only) 131141cc406Sopenharmony_ci{ 132141cc406Sopenharmony_ci if (devlist) 133141cc406Sopenharmony_ci { 134141cc406Sopenharmony_ci int i; 135141cc406Sopenharmony_ci for (i = 0; devlist[i]; i++) 136141cc406Sopenharmony_ci { 137141cc406Sopenharmony_ci free ((void *) devlist[i]->name); 138141cc406Sopenharmony_ci free ((void *) devlist[i]); 139141cc406Sopenharmony_ci } 140141cc406Sopenharmony_ci free ((void *) devlist); 141141cc406Sopenharmony_ci devlist = NULL; 142141cc406Sopenharmony_ci } 143141cc406Sopenharmony_ci 144141cc406Sopenharmony_ci for (curr_scan_dev = 0; 145141cc406Sopenharmony_ci curr_scan_dev < sizeof (known_devices) / sizeof (known_devices[0]); 146141cc406Sopenharmony_ci curr_scan_dev++) 147141cc406Sopenharmony_ci { 148141cc406Sopenharmony_ci sanei_usb_find_devices (PANASONIC_ID, 149141cc406Sopenharmony_ci known_devices[curr_scan_dev].id, attach); 150141cc406Sopenharmony_ci } 151141cc406Sopenharmony_ci for (curr_scan_dev = 0; 152141cc406Sopenharmony_ci curr_scan_dev < sizeof (known_devices) / sizeof (known_devices[0]); 153141cc406Sopenharmony_ci curr_scan_dev++) 154141cc406Sopenharmony_ci { 155141cc406Sopenharmony_ci sanei_scsi_find_devices (known_devices[curr_scan_dev].scanner.vendor, 156141cc406Sopenharmony_ci known_devices[curr_scan_dev].scanner.model, 157141cc406Sopenharmony_ci NULL, -1, -1, -1, -1, attach); 158141cc406Sopenharmony_ci } 159141cc406Sopenharmony_ci if(device_list) 160141cc406Sopenharmony_ci *device_list = (const SANE_Device **) devlist; 161141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 162141cc406Sopenharmony_ci} 163141cc406Sopenharmony_ci 164141cc406Sopenharmony_ci/* Open device, return the device handle */ 165141cc406Sopenharmony_ciSANE_Status 166141cc406Sopenharmony_cisane_open (SANE_String_Const devname, SANE_Handle * handle) 167141cc406Sopenharmony_ci{ 168141cc406Sopenharmony_ci unsigned i, j, id = 0; 169141cc406Sopenharmony_ci struct scanner *s; 170141cc406Sopenharmony_ci SANE_Int h, bus; 171141cc406Sopenharmony_ci SANE_Status st; 172141cc406Sopenharmony_ci if (!devlist) 173141cc406Sopenharmony_ci { 174141cc406Sopenharmony_ci st = sane_get_devices (NULL, 0); 175141cc406Sopenharmony_ci if (st) 176141cc406Sopenharmony_ci return st; 177141cc406Sopenharmony_ci } 178141cc406Sopenharmony_ci for (i = 0; devlist[i]; i++) 179141cc406Sopenharmony_ci { 180141cc406Sopenharmony_ci if (!strcmp (devlist[i]->name, devname)) 181141cc406Sopenharmony_ci break; 182141cc406Sopenharmony_ci } 183141cc406Sopenharmony_ci if (!devlist[i]) 184141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 185141cc406Sopenharmony_ci for (j = 0; j < sizeof (known_devices) / sizeof (known_devices[0]); j++) 186141cc406Sopenharmony_ci { 187141cc406Sopenharmony_ci if (!strcmp (devlist[i]->model, known_devices[j].scanner.model)) 188141cc406Sopenharmony_ci { 189141cc406Sopenharmony_ci id = known_devices[j].id; 190141cc406Sopenharmony_ci break; 191141cc406Sopenharmony_ci } 192141cc406Sopenharmony_ci } 193141cc406Sopenharmony_ci 194141cc406Sopenharmony_ci st = sanei_usb_open (devname, &h); 195141cc406Sopenharmony_ci if (st == SANE_STATUS_ACCESS_DENIED) 196141cc406Sopenharmony_ci return st; 197141cc406Sopenharmony_ci if (st) 198141cc406Sopenharmony_ci { 199141cc406Sopenharmony_ci st = sanei_scsi_open (devname, &h, kvs20xx_sense_handler, NULL); 200141cc406Sopenharmony_ci if (st) 201141cc406Sopenharmony_ci { 202141cc406Sopenharmony_ci return st; 203141cc406Sopenharmony_ci } 204141cc406Sopenharmony_ci bus = SCSI; 205141cc406Sopenharmony_ci } 206141cc406Sopenharmony_ci else 207141cc406Sopenharmony_ci { 208141cc406Sopenharmony_ci bus = USB; 209141cc406Sopenharmony_ci st = sanei_usb_claim_interface (h, 0); 210141cc406Sopenharmony_ci if (st) 211141cc406Sopenharmony_ci { 212141cc406Sopenharmony_ci sanei_usb_close (h); 213141cc406Sopenharmony_ci return st; 214141cc406Sopenharmony_ci } 215141cc406Sopenharmony_ci } 216141cc406Sopenharmony_ci 217141cc406Sopenharmony_ci s = malloc (sizeof (struct scanner)); 218141cc406Sopenharmony_ci if (!s) 219141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 220141cc406Sopenharmony_ci memset (s, 0, sizeof (struct scanner)); 221141cc406Sopenharmony_ci s->buffer = malloc (MAX_READ_DATA_SIZE + BULK_HEADER_SIZE); 222141cc406Sopenharmony_ci if (!s->buffer) 223141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 224141cc406Sopenharmony_ci s->file = h; 225141cc406Sopenharmony_ci s->bus = bus; 226141cc406Sopenharmony_ci s->id = id; 227141cc406Sopenharmony_ci kvs20xx_init_options (s); 228141cc406Sopenharmony_ci *handle = s; 229141cc406Sopenharmony_ci for (i = 0; i < 3; i++) 230141cc406Sopenharmony_ci { 231141cc406Sopenharmony_ci st = kvs20xx_test_unit_ready (s); 232141cc406Sopenharmony_ci if (st) 233141cc406Sopenharmony_ci { 234141cc406Sopenharmony_ci if (s->bus == SCSI) 235141cc406Sopenharmony_ci { 236141cc406Sopenharmony_ci sanei_scsi_close (s->file); 237141cc406Sopenharmony_ci st = sanei_scsi_open (devname, &h, kvs20xx_sense_handler, NULL); 238141cc406Sopenharmony_ci if (st) 239141cc406Sopenharmony_ci return st; 240141cc406Sopenharmony_ci } 241141cc406Sopenharmony_ci else 242141cc406Sopenharmony_ci { 243141cc406Sopenharmony_ci sanei_usb_release_interface (s->file, 0); 244141cc406Sopenharmony_ci sanei_usb_close (s->file); 245141cc406Sopenharmony_ci st = sanei_usb_open (devname, &h); 246141cc406Sopenharmony_ci if (st) 247141cc406Sopenharmony_ci return st; 248141cc406Sopenharmony_ci st = sanei_usb_claim_interface (h, 0); 249141cc406Sopenharmony_ci if (st) 250141cc406Sopenharmony_ci { 251141cc406Sopenharmony_ci sanei_usb_close (h); 252141cc406Sopenharmony_ci return st; 253141cc406Sopenharmony_ci } 254141cc406Sopenharmony_ci } 255141cc406Sopenharmony_ci s->file = h; 256141cc406Sopenharmony_ci } 257141cc406Sopenharmony_ci else 258141cc406Sopenharmony_ci break; 259141cc406Sopenharmony_ci } 260141cc406Sopenharmony_ci if (i == 3) 261141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 262141cc406Sopenharmony_ci 263141cc406Sopenharmony_ci st = kvs20xx_set_timeout (s, s->val[FEED_TIMEOUT].w); 264141cc406Sopenharmony_ci if (st) 265141cc406Sopenharmony_ci { 266141cc406Sopenharmony_ci sane_close (s); 267141cc406Sopenharmony_ci return st; 268141cc406Sopenharmony_ci } 269141cc406Sopenharmony_ci 270141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 271141cc406Sopenharmony_ci} 272141cc406Sopenharmony_ci 273141cc406Sopenharmony_ci/* Close device */ 274141cc406Sopenharmony_civoid 275141cc406Sopenharmony_cisane_close (SANE_Handle handle) 276141cc406Sopenharmony_ci{ 277141cc406Sopenharmony_ci struct scanner *s = (struct scanner *) handle; 278141cc406Sopenharmony_ci int i; 279141cc406Sopenharmony_ci if (s->bus == USB) 280141cc406Sopenharmony_ci { 281141cc406Sopenharmony_ci sanei_usb_release_interface (s->file, 0); 282141cc406Sopenharmony_ci sanei_usb_close (s->file); 283141cc406Sopenharmony_ci } 284141cc406Sopenharmony_ci else 285141cc406Sopenharmony_ci sanei_scsi_close (s->file); 286141cc406Sopenharmony_ci 287141cc406Sopenharmony_ci for (i = 1; i < NUM_OPTIONS; i++) 288141cc406Sopenharmony_ci { 289141cc406Sopenharmony_ci if (s->opt[i].type == SANE_TYPE_STRING && s->val[i].s) 290141cc406Sopenharmony_ci free (s->val[i].s); 291141cc406Sopenharmony_ci } 292141cc406Sopenharmony_ci if (s->data) 293141cc406Sopenharmony_ci free (s->data); 294141cc406Sopenharmony_ci free (s->buffer); 295141cc406Sopenharmony_ci free (s); 296141cc406Sopenharmony_ci 297141cc406Sopenharmony_ci} 298141cc406Sopenharmony_ci 299141cc406Sopenharmony_ci/* Get option descriptor */ 300141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 301141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 302141cc406Sopenharmony_ci{ 303141cc406Sopenharmony_ci struct scanner *s = handle; 304141cc406Sopenharmony_ci 305141cc406Sopenharmony_ci if ((unsigned) option >= NUM_OPTIONS || option < 0) 306141cc406Sopenharmony_ci return NULL; 307141cc406Sopenharmony_ci return s->opt + option; 308141cc406Sopenharmony_ci} 309141cc406Sopenharmony_ci 310141cc406Sopenharmony_cistatic SANE_Status 311141cc406Sopenharmony_ciwait_document (struct scanner *s) 312141cc406Sopenharmony_ci{ 313141cc406Sopenharmony_ci SANE_Status st; 314141cc406Sopenharmony_ci int i; 315141cc406Sopenharmony_ci if (!strcmp ("off", s->val[MANUALFEED].s)) 316141cc406Sopenharmony_ci return kvs20xx_document_exist (s); 317141cc406Sopenharmony_ci 318141cc406Sopenharmony_ci for (i = 0; i < s->val[FEED_TIMEOUT].w; i++) 319141cc406Sopenharmony_ci { 320141cc406Sopenharmony_ci st = kvs20xx_document_exist (s); 321141cc406Sopenharmony_ci if (st != SANE_STATUS_NO_DOCS) 322141cc406Sopenharmony_ci return st; 323141cc406Sopenharmony_ci sleep (1); 324141cc406Sopenharmony_ci } 325141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 326141cc406Sopenharmony_ci} 327141cc406Sopenharmony_ci 328141cc406Sopenharmony_ci/* Start scanning */ 329141cc406Sopenharmony_ciSANE_Status 330141cc406Sopenharmony_cisane_start (SANE_Handle handle) 331141cc406Sopenharmony_ci{ 332141cc406Sopenharmony_ci struct scanner *s = (struct scanner *) handle; 333141cc406Sopenharmony_ci SANE_Status st; 334141cc406Sopenharmony_ci int duplex = s->val[DUPLEX].w; 335141cc406Sopenharmony_ci 336141cc406Sopenharmony_ci if (!s->scanning) 337141cc406Sopenharmony_ci { 338141cc406Sopenharmony_ci unsigned dummy_length; 339141cc406Sopenharmony_ci st = kvs20xx_test_unit_ready (s); 340141cc406Sopenharmony_ci if (st) 341141cc406Sopenharmony_ci return st; 342141cc406Sopenharmony_ci 343141cc406Sopenharmony_ci st = wait_document (s); 344141cc406Sopenharmony_ci if (st) 345141cc406Sopenharmony_ci return st; 346141cc406Sopenharmony_ci 347141cc406Sopenharmony_ci st = kvs20xx_reset_window (s); 348141cc406Sopenharmony_ci if (st) 349141cc406Sopenharmony_ci return st; 350141cc406Sopenharmony_ci st = kvs20xx_set_window (s, SIDE_FRONT); 351141cc406Sopenharmony_ci if (st) 352141cc406Sopenharmony_ci return st; 353141cc406Sopenharmony_ci if (duplex) 354141cc406Sopenharmony_ci { 355141cc406Sopenharmony_ci st = kvs20xx_set_window (s, SIDE_BACK); 356141cc406Sopenharmony_ci if (st) 357141cc406Sopenharmony_ci return st; 358141cc406Sopenharmony_ci } 359141cc406Sopenharmony_ci st = kvs20xx_scan (s); 360141cc406Sopenharmony_ci if (st) 361141cc406Sopenharmony_ci return st; 362141cc406Sopenharmony_ci 363141cc406Sopenharmony_ci st = kvs20xx_read_picture_element (s, SIDE_FRONT, &s->params); 364141cc406Sopenharmony_ci if (st) 365141cc406Sopenharmony_ci return st; 366141cc406Sopenharmony_ci if (duplex) 367141cc406Sopenharmony_ci { 368141cc406Sopenharmony_ci st = get_adjust_data (s, &dummy_length); 369141cc406Sopenharmony_ci if (st) 370141cc406Sopenharmony_ci return st; 371141cc406Sopenharmony_ci } 372141cc406Sopenharmony_ci else 373141cc406Sopenharmony_ci { 374141cc406Sopenharmony_ci dummy_length = 0; 375141cc406Sopenharmony_ci } 376141cc406Sopenharmony_ci s->scanning = 1; 377141cc406Sopenharmony_ci s->page = 0; 378141cc406Sopenharmony_ci s->read = 0; 379141cc406Sopenharmony_ci s->side = SIDE_FRONT; 380141cc406Sopenharmony_ci sane_get_parameters (s, NULL); 381141cc406Sopenharmony_ci s->saved_dummy_size = s->dummy_size = dummy_length 382141cc406Sopenharmony_ci ? (dummy_length * s->val[RESOLUTION].w / 1200 - 1) 383141cc406Sopenharmony_ci * s->params.bytes_per_line : 0; 384141cc406Sopenharmony_ci s->side_size = s->params.lines * s->params.bytes_per_line; 385141cc406Sopenharmony_ci 386141cc406Sopenharmony_ci s->data = realloc (s->data, duplex ? s->side_size * 2 : s->side_size); 387141cc406Sopenharmony_ci if (!s->data) 388141cc406Sopenharmony_ci { 389141cc406Sopenharmony_ci s->scanning = 0; 390141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 391141cc406Sopenharmony_ci } 392141cc406Sopenharmony_ci } 393141cc406Sopenharmony_ci 394141cc406Sopenharmony_ci if (duplex) 395141cc406Sopenharmony_ci { 396141cc406Sopenharmony_ci unsigned side = SIDE_FRONT; 397141cc406Sopenharmony_ci unsigned read, mx; 398141cc406Sopenharmony_ci if (s->side == SIDE_FRONT && s->read == s->side_size - s->dummy_size) 399141cc406Sopenharmony_ci { 400141cc406Sopenharmony_ci s->side = SIDE_BACK; 401141cc406Sopenharmony_ci s->read = s->dummy_size; 402141cc406Sopenharmony_ci s->dummy_size = 0; 403141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 404141cc406Sopenharmony_ci } 405141cc406Sopenharmony_ci s->read = 0; 406141cc406Sopenharmony_ci s->dummy_size = s->saved_dummy_size; 407141cc406Sopenharmony_ci s->side = SIDE_FRONT; 408141cc406Sopenharmony_ci st = kvs20xx_document_exist (s); 409141cc406Sopenharmony_ci if (st) 410141cc406Sopenharmony_ci return st; 411141cc406Sopenharmony_ci for (mx = s->side_size * 2; !st; mx -= read, side ^= SIDE_BACK) 412141cc406Sopenharmony_ci st = kvs20xx_read_image_data (s, s->page, side, 413141cc406Sopenharmony_ci &s->data[s->side_size * 2 - mx], mx, 414141cc406Sopenharmony_ci &read); 415141cc406Sopenharmony_ci } 416141cc406Sopenharmony_ci else 417141cc406Sopenharmony_ci { 418141cc406Sopenharmony_ci unsigned read, mx; 419141cc406Sopenharmony_ci s->read = 0; 420141cc406Sopenharmony_ci st = kvs20xx_document_exist (s); 421141cc406Sopenharmony_ci if (st) 422141cc406Sopenharmony_ci return st; 423141cc406Sopenharmony_ci DBG (DBG_INFO, "start: %d\n", s->page); 424141cc406Sopenharmony_ci 425141cc406Sopenharmony_ci for (mx = s->side_size; !st; mx -= read) 426141cc406Sopenharmony_ci st = kvs20xx_read_image_data (s, s->page, SIDE_FRONT, 427141cc406Sopenharmony_ci &s->data[s->side_size - mx], mx, &read); 428141cc406Sopenharmony_ci } 429141cc406Sopenharmony_ci if (st && st != SANE_STATUS_EOF) 430141cc406Sopenharmony_ci { 431141cc406Sopenharmony_ci s->scanning = 0; 432141cc406Sopenharmony_ci return st; 433141cc406Sopenharmony_ci } 434141cc406Sopenharmony_ci s->page++; 435141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 436141cc406Sopenharmony_ci} 437141cc406Sopenharmony_ci 438141cc406Sopenharmony_ciinline static void 439141cc406Sopenharmony_cimemcpy24 (u8 * dest, u8 * src, unsigned size, unsigned ls) 440141cc406Sopenharmony_ci{ 441141cc406Sopenharmony_ci unsigned i; 442141cc406Sopenharmony_ci for (i = 0; i < size; i++) 443141cc406Sopenharmony_ci { 444141cc406Sopenharmony_ci dest[i * 3] = src[i]; 445141cc406Sopenharmony_ci dest[i * 3 + 1] = src[i + ls]; 446141cc406Sopenharmony_ci dest[i * 3 + 2] = src[i + 2 * ls]; 447141cc406Sopenharmony_ci } 448141cc406Sopenharmony_ci} 449141cc406Sopenharmony_ci 450141cc406Sopenharmony_ciSANE_Status 451141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, 452141cc406Sopenharmony_ci SANE_Int max_len, SANE_Int * len) 453141cc406Sopenharmony_ci{ 454141cc406Sopenharmony_ci struct scanner *s = (struct scanner *) handle; 455141cc406Sopenharmony_ci int duplex = s->val[DUPLEX].w; 456141cc406Sopenharmony_ci int color = !strcmp (s->val[MODE].s, SANE_VALUE_SCAN_MODE_COLOR); 457141cc406Sopenharmony_ci int rest = s->side_size - s->read - s->dummy_size; 458141cc406Sopenharmony_ci *len = 0; 459141cc406Sopenharmony_ci 460141cc406Sopenharmony_ci if (!s->scanning || !rest) 461141cc406Sopenharmony_ci { 462141cc406Sopenharmony_ci if (strcmp (s->val[FEEDER_MODE].s, SANE_I18N ("continuous"))) 463141cc406Sopenharmony_ci { 464141cc406Sopenharmony_ci if (!duplex || s->side == SIDE_BACK) 465141cc406Sopenharmony_ci s->scanning = 0; 466141cc406Sopenharmony_ci } 467141cc406Sopenharmony_ci return SANE_STATUS_EOF; 468141cc406Sopenharmony_ci } 469141cc406Sopenharmony_ci 470141cc406Sopenharmony_ci *len = max_len < rest ? max_len : rest; 471141cc406Sopenharmony_ci if (duplex && (s->id == KV_S2025C 472141cc406Sopenharmony_ci || s->id == KV_S2026C || s->id == KV_S2028C)) 473141cc406Sopenharmony_ci { 474141cc406Sopenharmony_ci if (color) 475141cc406Sopenharmony_ci { 476141cc406Sopenharmony_ci unsigned ls = s->params.bytes_per_line; 477141cc406Sopenharmony_ci unsigned i, a = s->side == SIDE_FRONT ? 0 : ls / 3; 478141cc406Sopenharmony_ci u8 *data; 479141cc406Sopenharmony_ci *len = (*len / ls) * ls; 480141cc406Sopenharmony_ci for (i = 0, data = s->data + s->read * 2 + a; 481141cc406Sopenharmony_ci i < *len / ls; buf += ls, data += 2 * ls, i++) 482141cc406Sopenharmony_ci memcpy24 (buf, data, ls / 3, ls * 2 / 3); 483141cc406Sopenharmony_ci } 484141cc406Sopenharmony_ci else 485141cc406Sopenharmony_ci { 486141cc406Sopenharmony_ci unsigned ls = s->params.bytes_per_line; 487141cc406Sopenharmony_ci unsigned i = s->side == SIDE_FRONT ? 0 : ls; 488141cc406Sopenharmony_ci unsigned head = ls - (s->read % ls); 489141cc406Sopenharmony_ci unsigned tail = (*len - head) % ls; 490141cc406Sopenharmony_ci unsigned lines = (*len - head) / ls; 491141cc406Sopenharmony_ci u8 *data = s->data + (s->read / ls) * ls * 2 + i + s->read % ls; 492141cc406Sopenharmony_ci assert (data <= s->data + s->side_size * 2); 493141cc406Sopenharmony_ci memcpy (buf, data, head); 494141cc406Sopenharmony_ci for (i = 0, buf += head, data += head + (head ? ls : 0); 495141cc406Sopenharmony_ci i < lines; buf += ls, data += ls * 2, i++) 496141cc406Sopenharmony_ci { 497141cc406Sopenharmony_ci assert (data <= s->data + s->side_size * 2); 498141cc406Sopenharmony_ci memcpy (buf, data, ls); 499141cc406Sopenharmony_ci } 500141cc406Sopenharmony_ci assert ((data <= s->data + s->side_size * 2) || !tail); 501141cc406Sopenharmony_ci memcpy (buf, data, tail); 502141cc406Sopenharmony_ci } 503141cc406Sopenharmony_ci s->read += *len; 504141cc406Sopenharmony_ci } 505141cc406Sopenharmony_ci else 506141cc406Sopenharmony_ci { 507141cc406Sopenharmony_ci if (color) 508141cc406Sopenharmony_ci { 509141cc406Sopenharmony_ci unsigned i, ls = s->params.bytes_per_line; 510141cc406Sopenharmony_ci u8 *data = s->data + s->read; 511141cc406Sopenharmony_ci *len = (*len / ls) * ls; 512141cc406Sopenharmony_ci for (i = 0; i < *len / ls; buf += ls, data += ls, i++) 513141cc406Sopenharmony_ci memcpy24 (buf, data, ls / 3, ls / 3); 514141cc406Sopenharmony_ci } 515141cc406Sopenharmony_ci else 516141cc406Sopenharmony_ci { 517141cc406Sopenharmony_ci memcpy (buf, s->data + s->read, *len); 518141cc406Sopenharmony_ci } 519141cc406Sopenharmony_ci s->read += *len; 520141cc406Sopenharmony_ci } 521141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 522141cc406Sopenharmony_ci} 523141cc406Sopenharmony_ci 524141cc406Sopenharmony_civoid 525141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 526141cc406Sopenharmony_ci{ 527141cc406Sopenharmony_ci struct scanner *s = (struct scanner *) handle; 528141cc406Sopenharmony_ci s->scanning = 0; 529141cc406Sopenharmony_ci} 530141cc406Sopenharmony_ci 531141cc406Sopenharmony_ciSANE_Status 532141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle __sane_unused__ h, SANE_Bool __sane_unused__ m) 533141cc406Sopenharmony_ci{ 534141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 535141cc406Sopenharmony_ci} 536141cc406Sopenharmony_ci 537141cc406Sopenharmony_ciSANE_Status 538141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle __sane_unused__ h, 539141cc406Sopenharmony_ci SANE_Int __sane_unused__ * fd) 540141cc406Sopenharmony_ci{ 541141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 542141cc406Sopenharmony_ci} 543