1141cc406Sopenharmony_ci/* 2141cc406Sopenharmony_ci * SANE backend for Xerox Phaser 3200MFP et al. 3141cc406Sopenharmony_ci * Copyright 2008-2016 ABC <abc@telekom.ru> 4141cc406Sopenharmony_ci * 5141cc406Sopenharmony_ci * Network Scanners Support 6141cc406Sopenharmony_ci * Copyright 2010 Alexander Kuznetsov <acca(at)cpan.org> 7141cc406Sopenharmony_ci * 8141cc406Sopenharmony_ci * Color scanning on Samsung M2870 model and Xerox Cognac 3215 & 3225 9141cc406Sopenharmony_ci * models by Laxmeesh Onkar Markod <m.laxmeesh@samsung.com> 10141cc406Sopenharmony_ci * 11141cc406Sopenharmony_ci * This program is licensed under GPL + SANE exception. 12141cc406Sopenharmony_ci * More info at http://www.sane-project.org/license.html 13141cc406Sopenharmony_ci */ 14141cc406Sopenharmony_ci 15141cc406Sopenharmony_ci#define DEBUG_NOT_STATIC 16141cc406Sopenharmony_ci#define BACKEND_NAME xerox_mfp 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci#include "../include/sane/config.h" 19141cc406Sopenharmony_ci#include "../include/lassert.h" 20141cc406Sopenharmony_ci#include <ctype.h> 21141cc406Sopenharmony_ci#include <stdlib.h> 22141cc406Sopenharmony_ci#include <string.h> 23141cc406Sopenharmony_ci#include <errno.h> 24141cc406Sopenharmony_ci#include <fcntl.h> 25141cc406Sopenharmony_ci#include <math.h> 26141cc406Sopenharmony_ci#include <unistd.h> 27141cc406Sopenharmony_ci#include <sys/time.h> 28141cc406Sopenharmony_ci#include <sys/types.h> 29141cc406Sopenharmony_ci#include "../include/sane/sane.h" 30141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 31141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 32141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h" 33141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 34141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 35141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 36141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 37141cc406Sopenharmony_ci#include <jpeglib.h> 38141cc406Sopenharmony_ci#endif 39141cc406Sopenharmony_ci#include "xerox_mfp.h" 40141cc406Sopenharmony_ci 41141cc406Sopenharmony_ci#define BACKEND_BUILD 13 42141cc406Sopenharmony_ci#define XEROX_CONFIG_FILE "xerox_mfp.conf" 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL; /* sane_get_devices array */ 45141cc406Sopenharmony_cistatic struct device *devices_head = NULL; /* sane_get_devices list */ 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_cienum { TRANSPORT_USB, TRANSPORT_TCP, TRANSPORTS_MAX }; 48141cc406Sopenharmony_citransport available_transports[TRANSPORTS_MAX] = { 49141cc406Sopenharmony_ci { "usb", usb_dev_request, usb_dev_open, usb_dev_close, usb_configure_device }, 50141cc406Sopenharmony_ci { "tcp", tcp_dev_request, tcp_dev_open, tcp_dev_close, tcp_configure_device }, 51141cc406Sopenharmony_ci}; 52141cc406Sopenharmony_ci 53141cc406Sopenharmony_cistatic int resolv_state(int state) 54141cc406Sopenharmony_ci{ 55141cc406Sopenharmony_ci if (state & STATE_DOCUMENT_JAM) 56141cc406Sopenharmony_ci return SANE_STATUS_JAMMED; 57141cc406Sopenharmony_ci if (state & STATE_NO_DOCUMENT) 58141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 59141cc406Sopenharmony_ci if (state & STATE_COVER_OPEN) 60141cc406Sopenharmony_ci return SANE_STATUS_COVER_OPEN; 61141cc406Sopenharmony_ci if (state & STATE_INVALID_AREA) 62141cc406Sopenharmony_ci return SANE_STATUS_INVAL; /* sane_start: implies SANE_INFO_RELOAD_OPTIONS */ 63141cc406Sopenharmony_ci if (state & STATE_WARMING) 64141cc406Sopenharmony_ci#ifdef SANE_STATUS_WARMING_UP 65141cc406Sopenharmony_ci return SANE_STATUS_WARMING_UP; 66141cc406Sopenharmony_ci#else 67141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 68141cc406Sopenharmony_ci#endif 69141cc406Sopenharmony_ci if (state & STATE_LOCKING) 70141cc406Sopenharmony_ci#ifdef SANE_STATUS_HW_LOCKED 71141cc406Sopenharmony_ci return SANE_STATUS_HW_LOCKED; 72141cc406Sopenharmony_ci#else 73141cc406Sopenharmony_ci return SANE_STATUS_JAMMED; 74141cc406Sopenharmony_ci#endif 75141cc406Sopenharmony_ci if (state & ~STATE_NO_ERROR) 76141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 77141cc406Sopenharmony_ci return 0; 78141cc406Sopenharmony_ci} 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_cistatic char *str_cmd(int cmd) 81141cc406Sopenharmony_ci{ 82141cc406Sopenharmony_ci switch (cmd) { 83141cc406Sopenharmony_ci case CMD_ABORT: return "ABORT"; 84141cc406Sopenharmony_ci case CMD_INQUIRY: return "INQUIRY"; 85141cc406Sopenharmony_ci case CMD_RESERVE_UNIT: return "RESERVE_UNIT"; 86141cc406Sopenharmony_ci case CMD_RELEASE_UNIT: return "RELEASE_UNIT"; 87141cc406Sopenharmony_ci case CMD_SET_WINDOW: return "SET_WINDOW"; 88141cc406Sopenharmony_ci case CMD_READ: return "READ"; 89141cc406Sopenharmony_ci case CMD_READ_IMAGE: return "READ_IMAGE"; 90141cc406Sopenharmony_ci case CMD_OBJECT_POSITION: return "OBJECT_POSITION"; 91141cc406Sopenharmony_ci } 92141cc406Sopenharmony_ci return "unknown"; 93141cc406Sopenharmony_ci} 94141cc406Sopenharmony_ci 95141cc406Sopenharmony_ci#define MAX_DUMP 70 96141cc406Sopenharmony_ciconst char *encTmpFileName = "/tmp/stmp_enc.tmp"; 97141cc406Sopenharmony_ci 98141cc406Sopenharmony_ci/* 99141cc406Sopenharmony_ci * Decode jpeg from `infilename` into dev->decData of dev->decDataSize size. 100141cc406Sopenharmony_ci */ 101141cc406Sopenharmony_cistatic int decompress(struct device __sane_unused__ *dev, 102141cc406Sopenharmony_ci const char __sane_unused__ *infilename) 103141cc406Sopenharmony_ci{ 104141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 105141cc406Sopenharmony_ci int rc; 106141cc406Sopenharmony_ci int row_stride, width, height, pixel_size; 107141cc406Sopenharmony_ci struct jpeg_decompress_struct cinfo; 108141cc406Sopenharmony_ci struct jpeg_error_mgr jerr; 109141cc406Sopenharmony_ci unsigned long bmp_size = 0; 110141cc406Sopenharmony_ci FILE *pInfile = NULL; 111141cc406Sopenharmony_ci JSAMPARRAY buffer; 112141cc406Sopenharmony_ci 113141cc406Sopenharmony_ci if ((pInfile = fopen(infilename, "rb")) == NULL) { 114141cc406Sopenharmony_ci fprintf(stderr, "can't open %s\n", infilename); 115141cc406Sopenharmony_ci return -1; 116141cc406Sopenharmony_ci } 117141cc406Sopenharmony_ci 118141cc406Sopenharmony_ci cinfo.err = jpeg_std_error(&jerr); 119141cc406Sopenharmony_ci 120141cc406Sopenharmony_ci jpeg_create_decompress(&cinfo); 121141cc406Sopenharmony_ci 122141cc406Sopenharmony_ci jpeg_stdio_src(&cinfo, pInfile); 123141cc406Sopenharmony_ci 124141cc406Sopenharmony_ci rc = jpeg_read_header(&cinfo, TRUE); 125141cc406Sopenharmony_ci if (rc != 1) { 126141cc406Sopenharmony_ci jpeg_destroy_decompress(&cinfo); 127141cc406Sopenharmony_ci fclose(pInfile); 128141cc406Sopenharmony_ci return -1; 129141cc406Sopenharmony_ci } 130141cc406Sopenharmony_ci 131141cc406Sopenharmony_ci jpeg_start_decompress(&cinfo); 132141cc406Sopenharmony_ci 133141cc406Sopenharmony_ci width = cinfo.output_width; 134141cc406Sopenharmony_ci height = cinfo.output_height; 135141cc406Sopenharmony_ci pixel_size = cinfo.output_components; 136141cc406Sopenharmony_ci bmp_size = width * height * pixel_size; 137141cc406Sopenharmony_ci assert(bmp_size <= POST_DATASIZE); 138141cc406Sopenharmony_ci dev->decDataSize = bmp_size; 139141cc406Sopenharmony_ci 140141cc406Sopenharmony_ci row_stride = width * pixel_size; 141141cc406Sopenharmony_ci 142141cc406Sopenharmony_ci buffer = (*cinfo.mem->alloc_sarray) 143141cc406Sopenharmony_ci ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); 144141cc406Sopenharmony_ci 145141cc406Sopenharmony_ci while (cinfo.output_scanline < cinfo.output_height) { 146141cc406Sopenharmony_ci buffer[0] = dev->decData + \ 147141cc406Sopenharmony_ci (cinfo.output_scanline) * row_stride; 148141cc406Sopenharmony_ci jpeg_read_scanlines(&cinfo, buffer, 1); 149141cc406Sopenharmony_ci } 150141cc406Sopenharmony_ci jpeg_finish_decompress(&cinfo); 151141cc406Sopenharmony_ci jpeg_destroy_decompress(&cinfo); 152141cc406Sopenharmony_ci fclose(pInfile); 153141cc406Sopenharmony_ci return 0; 154141cc406Sopenharmony_ci#else 155141cc406Sopenharmony_ci return -1; 156141cc406Sopenharmony_ci#endif 157141cc406Sopenharmony_ci} 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci/* copy from decoded jpeg image (dev->decData) into user's buffer (pDest) */ 160141cc406Sopenharmony_ci/* returns 0 if there is no data to copy */ 161141cc406Sopenharmony_cistatic int copy_decompress_data(struct device *dev, unsigned char *pDest, int maxlen, int *destLen) 162141cc406Sopenharmony_ci{ 163141cc406Sopenharmony_ci int data_size = 0; 164141cc406Sopenharmony_ci 165141cc406Sopenharmony_ci if (destLen) 166141cc406Sopenharmony_ci *destLen = 0; 167141cc406Sopenharmony_ci if (!dev->decDataSize) 168141cc406Sopenharmony_ci return 0; 169141cc406Sopenharmony_ci data_size = dev->decDataSize - dev->currentDecDataIndex; 170141cc406Sopenharmony_ci if (data_size > maxlen) 171141cc406Sopenharmony_ci data_size = maxlen; 172141cc406Sopenharmony_ci if (data_size && pDest) { 173141cc406Sopenharmony_ci memcpy(pDest, dev->decData + dev->currentDecDataIndex, data_size); 174141cc406Sopenharmony_ci if (destLen) 175141cc406Sopenharmony_ci *destLen = data_size; 176141cc406Sopenharmony_ci dev->currentDecDataIndex += data_size; 177141cc406Sopenharmony_ci } 178141cc406Sopenharmony_ci if (dev->decDataSize == dev->currentDecDataIndex) { 179141cc406Sopenharmony_ci dev->currentDecDataIndex = 0; 180141cc406Sopenharmony_ci dev->decDataSize = 0; 181141cc406Sopenharmony_ci } 182141cc406Sopenharmony_ci return 1; 183141cc406Sopenharmony_ci} 184141cc406Sopenharmony_ci 185141cc406Sopenharmony_cistatic int decompress_tempfile(struct device *dev) 186141cc406Sopenharmony_ci{ 187141cc406Sopenharmony_ci decompress(dev, encTmpFileName); 188141cc406Sopenharmony_ci remove(encTmpFileName); 189141cc406Sopenharmony_ci return 0; 190141cc406Sopenharmony_ci} 191141cc406Sopenharmony_ci 192141cc406Sopenharmony_cistatic int dump_to_tmp_file(struct device *dev) 193141cc406Sopenharmony_ci{ 194141cc406Sopenharmony_ci unsigned char *pSrc = dev->data; 195141cc406Sopenharmony_ci int srcLen = dev->datalen; 196141cc406Sopenharmony_ci FILE *pInfile; 197141cc406Sopenharmony_ci if ((pInfile = fopen(encTmpFileName, "a")) == NULL) { 198141cc406Sopenharmony_ci fprintf(stderr, "can't open %s\n", encTmpFileName); 199141cc406Sopenharmony_ci return 0; 200141cc406Sopenharmony_ci } 201141cc406Sopenharmony_ci 202141cc406Sopenharmony_ci fwrite(pSrc, 1, srcLen, pInfile); 203141cc406Sopenharmony_ci fclose(pInfile); 204141cc406Sopenharmony_ci return srcLen; 205141cc406Sopenharmony_ci} 206141cc406Sopenharmony_ci 207141cc406Sopenharmony_cistatic int isSupportedDevice(struct device __sane_unused__ *dev) 208141cc406Sopenharmony_ci{ 209141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 210141cc406Sopenharmony_ci /* Checking device which supports JPEG Lossy compression for color scanning*/ 211141cc406Sopenharmony_ci if (dev->compressionTypes & (1 << 6)) { 212141cc406Sopenharmony_ci /* blacklist malfunctioning device(s) */ 213141cc406Sopenharmony_ci if (!strncmp(dev->sane.model, "SCX-4500W", 9) || 214141cc406Sopenharmony_ci !strncmp(dev->sane.model, "C460", 4) || 215141cc406Sopenharmony_ci !!strstr(dev->sane.model, "CLX-3170") || 216141cc406Sopenharmony_ci !!strstr(dev->sane.model, "4x24") || 217141cc406Sopenharmony_ci !!strstr(dev->sane.model, "4x28") || 218141cc406Sopenharmony_ci !strncmp(dev->sane.model, "M288x", 5)) 219141cc406Sopenharmony_ci return 0; 220141cc406Sopenharmony_ci return 1; 221141cc406Sopenharmony_ci } else 222141cc406Sopenharmony_ci return 0; 223141cc406Sopenharmony_ci#else 224141cc406Sopenharmony_ci return 0; 225141cc406Sopenharmony_ci#endif 226141cc406Sopenharmony_ci} 227141cc406Sopenharmony_ci 228141cc406Sopenharmony_cistatic int isJPEGEnabled(struct device __sane_unused__ *dev) 229141cc406Sopenharmony_ci{ 230141cc406Sopenharmony_ci return isSupportedDevice(dev) && dev->compressionEnabled; 231141cc406Sopenharmony_ci} 232141cc406Sopenharmony_ci 233141cc406Sopenharmony_cistatic void dbg_dump(struct device *dev) 234141cc406Sopenharmony_ci{ 235141cc406Sopenharmony_ci int i; 236141cc406Sopenharmony_ci char dbuf[MAX_DUMP * 3 + 1], *dptr = dbuf; 237141cc406Sopenharmony_ci int nzlen = dev->reslen; 238141cc406Sopenharmony_ci int dlen = MIN(dev->reslen, MAX_DUMP); 239141cc406Sopenharmony_ci 240141cc406Sopenharmony_ci for (i = dev->reslen - 1; i >= 0; i--, nzlen--) 241141cc406Sopenharmony_ci if (dev->res[i] != 0) 242141cc406Sopenharmony_ci break; 243141cc406Sopenharmony_ci 244141cc406Sopenharmony_ci dlen = MIN(dlen, nzlen + 1); 245141cc406Sopenharmony_ci 246141cc406Sopenharmony_ci for (i = 0; i < dlen; i++, dptr += 3) 247141cc406Sopenharmony_ci sprintf(dptr, " %02x", dev->res[i]); 248141cc406Sopenharmony_ci 249141cc406Sopenharmony_ci DBG(5, "[%lu]%s%s\n", (u_long)dev->reslen, dbuf, 250141cc406Sopenharmony_ci (dlen < (int)dev->reslen)? "..." : ""); 251141cc406Sopenharmony_ci} 252141cc406Sopenharmony_ci 253141cc406Sopenharmony_ci/* one command to device */ 254141cc406Sopenharmony_ci/* return 0: on error, 1: success */ 255141cc406Sopenharmony_cistatic int dev_command(struct device *dev, SANE_Byte *cmd, size_t reqlen) 256141cc406Sopenharmony_ci{ 257141cc406Sopenharmony_ci SANE_Status status; 258141cc406Sopenharmony_ci size_t sendlen = cmd[3] + 4; 259141cc406Sopenharmony_ci SANE_Byte *res = dev->res; 260141cc406Sopenharmony_ci 261141cc406Sopenharmony_ci 262141cc406Sopenharmony_ci assert(reqlen <= sizeof(dev->res)); /* requested len */ 263141cc406Sopenharmony_ci dev->reslen = sizeof(dev->res); /* doing full buffer to flush stalled commands */ 264141cc406Sopenharmony_ci 265141cc406Sopenharmony_ci if (cmd[2] == CMD_SET_WINDOW) { 266141cc406Sopenharmony_ci /* Set Window have wrong packet length, huh. */ 267141cc406Sopenharmony_ci sendlen = 25; 268141cc406Sopenharmony_ci } 269141cc406Sopenharmony_ci 270141cc406Sopenharmony_ci if (cmd[2] == CMD_READ_IMAGE) { 271141cc406Sopenharmony_ci /* Read Image is raw data, don't need to read response */ 272141cc406Sopenharmony_ci res = NULL; 273141cc406Sopenharmony_ci } 274141cc406Sopenharmony_ci 275141cc406Sopenharmony_ci dev->state = 0; 276141cc406Sopenharmony_ci DBG(4, ":: dev_command(%s[%#x], %lu)\n", str_cmd(cmd[2]), cmd[2], 277141cc406Sopenharmony_ci (u_long)reqlen); 278141cc406Sopenharmony_ci status = dev->io->dev_request(dev, cmd, sendlen, res, &dev->reslen); 279141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 280141cc406Sopenharmony_ci DBG(1, "%s: dev_request: %s\n", __func__, sane_strstatus(status)); 281141cc406Sopenharmony_ci dev->state = SANE_STATUS_IO_ERROR; 282141cc406Sopenharmony_ci return 0; 283141cc406Sopenharmony_ci } 284141cc406Sopenharmony_ci 285141cc406Sopenharmony_ci if (!res) { 286141cc406Sopenharmony_ci /* if not need response just return success */ 287141cc406Sopenharmony_ci return 1; 288141cc406Sopenharmony_ci } 289141cc406Sopenharmony_ci 290141cc406Sopenharmony_ci /* normal command reply, some sanity checking */ 291141cc406Sopenharmony_ci if (dev->reslen < reqlen) { 292141cc406Sopenharmony_ci DBG(1, "%s: illegal response len %lu, need %lu\n", 293141cc406Sopenharmony_ci __func__, (u_long)dev->reslen, (u_long)reqlen); 294141cc406Sopenharmony_ci dev->state = SANE_STATUS_IO_ERROR; 295141cc406Sopenharmony_ci return 0; 296141cc406Sopenharmony_ci } else { 297141cc406Sopenharmony_ci size_t pktlen; /* len specified in packet */ 298141cc406Sopenharmony_ci 299141cc406Sopenharmony_ci if (DBG_LEVEL > 3) 300141cc406Sopenharmony_ci dbg_dump(dev); 301141cc406Sopenharmony_ci 302141cc406Sopenharmony_ci if (dev->res[0] != RES_CODE) { 303141cc406Sopenharmony_ci DBG(2, "%s: illegal data header %02x\n", __func__, dev->res[0]); 304141cc406Sopenharmony_ci dev->state = SANE_STATUS_IO_ERROR; 305141cc406Sopenharmony_ci return 0; 306141cc406Sopenharmony_ci } 307141cc406Sopenharmony_ci pktlen = dev->res[2] + 3; 308141cc406Sopenharmony_ci if (dev->reslen != pktlen) { 309141cc406Sopenharmony_ci DBG(2, "%s: illegal response len %lu, should be %lu\n", 310141cc406Sopenharmony_ci __func__, (u_long)pktlen, (u_long)dev->reslen); 311141cc406Sopenharmony_ci dev->state = SANE_STATUS_IO_ERROR; 312141cc406Sopenharmony_ci return 0; 313141cc406Sopenharmony_ci } 314141cc406Sopenharmony_ci if (dev->reslen > reqlen) 315141cc406Sopenharmony_ci DBG(2, "%s: too big packet len %lu, need %lu\n", 316141cc406Sopenharmony_ci __func__, (u_long)dev->reslen, (u_long)reqlen); 317141cc406Sopenharmony_ci } 318141cc406Sopenharmony_ci 319141cc406Sopenharmony_ci dev->state = 0; 320141cc406Sopenharmony_ci if (cmd[2] == CMD_SET_WINDOW || 321141cc406Sopenharmony_ci cmd[2] == CMD_OBJECT_POSITION || 322141cc406Sopenharmony_ci cmd[2] == CMD_READ || 323141cc406Sopenharmony_ci cmd[2] == CMD_RESERVE_UNIT) { 324141cc406Sopenharmony_ci if (dev->res[1] == STATUS_BUSY) 325141cc406Sopenharmony_ci dev->state = SANE_STATUS_DEVICE_BUSY; 326141cc406Sopenharmony_ci else if (dev->res[1] == STATUS_CANCEL) 327141cc406Sopenharmony_ci dev->state = SANE_STATUS_CANCELLED; 328141cc406Sopenharmony_ci else if (dev->res[1] == STATUS_CHECK) 329141cc406Sopenharmony_ci dev->state = resolv_state((cmd[2] == CMD_READ)? 330141cc406Sopenharmony_ci (dev->res[12] << 8 | dev->res[13]) : 331141cc406Sopenharmony_ci (dev->res[4] << 8 | dev->res[5])); 332141cc406Sopenharmony_ci 333141cc406Sopenharmony_ci if (dev->state) 334141cc406Sopenharmony_ci DBG(3, "%s(%s[%#x]): => %d: %s\n", 335141cc406Sopenharmony_ci __func__, str_cmd(cmd[2]), cmd[2], 336141cc406Sopenharmony_ci dev->state, sane_strstatus(dev->state)); 337141cc406Sopenharmony_ci } 338141cc406Sopenharmony_ci 339141cc406Sopenharmony_ci return 1; 340141cc406Sopenharmony_ci} 341141cc406Sopenharmony_ci 342141cc406Sopenharmony_ci/* one short command to device */ 343141cc406Sopenharmony_cistatic int dev_cmd(struct device *dev, SANE_Byte command) 344141cc406Sopenharmony_ci{ 345141cc406Sopenharmony_ci SANE_Byte cmd[4] = { REQ_CODE_A, REQ_CODE_B }; 346141cc406Sopenharmony_ci cmd[2] = command; 347141cc406Sopenharmony_ci return dev_command(dev, cmd, (command == CMD_INQUIRY)? 70 : 32); 348141cc406Sopenharmony_ci} 349141cc406Sopenharmony_ci 350141cc406Sopenharmony_ci/* stop scanning operation. return previous status */ 351141cc406Sopenharmony_cistatic SANE_Status dev_stop(struct device *dev) 352141cc406Sopenharmony_ci{ 353141cc406Sopenharmony_ci int state = dev->state; 354141cc406Sopenharmony_ci 355141cc406Sopenharmony_ci DBG(3, "%s: %p, scanning %d, reserved %d\n", __func__, 356141cc406Sopenharmony_ci (void *)dev, dev->scanning, dev->reserved); 357141cc406Sopenharmony_ci dev->scanning = 0; 358141cc406Sopenharmony_ci 359141cc406Sopenharmony_ci /* release */ 360141cc406Sopenharmony_ci if (!dev->reserved) 361141cc406Sopenharmony_ci return state; 362141cc406Sopenharmony_ci dev->reserved = 0; 363141cc406Sopenharmony_ci dev_cmd(dev, CMD_RELEASE_UNIT); 364141cc406Sopenharmony_ci DBG(3, "total image %d*%d size %d (win %d*%d), %d*%d %d data: %d, out %d bytes\n", 365141cc406Sopenharmony_ci dev->para.pixels_per_line, dev->para.lines, 366141cc406Sopenharmony_ci dev->total_img_size, 367141cc406Sopenharmony_ci dev->win_width, dev->win_len, 368141cc406Sopenharmony_ci dev->pixels_per_line, dev->ulines, dev->blocks, 369141cc406Sopenharmony_ci dev->total_data_size, dev->total_out_size); 370141cc406Sopenharmony_ci dev->state = state; 371141cc406Sopenharmony_ci return state; 372141cc406Sopenharmony_ci} 373141cc406Sopenharmony_ci 374141cc406Sopenharmony_ciSANE_Status ret_cancel(struct device *dev, SANE_Status ret) 375141cc406Sopenharmony_ci{ 376141cc406Sopenharmony_ci dev_cmd(dev, CMD_ABORT); 377141cc406Sopenharmony_ci if (dev->scanning) { 378141cc406Sopenharmony_ci dev_stop(dev); 379141cc406Sopenharmony_ci dev->state = SANE_STATUS_CANCELLED; 380141cc406Sopenharmony_ci } 381141cc406Sopenharmony_ci return ret; 382141cc406Sopenharmony_ci} 383141cc406Sopenharmony_ci 384141cc406Sopenharmony_cistatic int cancelled(struct device *dev) 385141cc406Sopenharmony_ci{ 386141cc406Sopenharmony_ci if (dev->cancel) 387141cc406Sopenharmony_ci return ret_cancel(dev, 1); 388141cc406Sopenharmony_ci return 0; 389141cc406Sopenharmony_ci} 390141cc406Sopenharmony_ci 391141cc406Sopenharmony_ci/* issue command and wait until scanner is not busy */ 392141cc406Sopenharmony_ci/* return 0 on error/blocking, 1 is ok and ready */ 393141cc406Sopenharmony_cistatic int dev_cmd_wait(struct device *dev, int cmd) 394141cc406Sopenharmony_ci{ 395141cc406Sopenharmony_ci int sleeptime = 10; 396141cc406Sopenharmony_ci 397141cc406Sopenharmony_ci do { 398141cc406Sopenharmony_ci if (cancelled(dev)) 399141cc406Sopenharmony_ci return 0; 400141cc406Sopenharmony_ci if (!dev_cmd(dev, cmd)) { 401141cc406Sopenharmony_ci dev->state = SANE_STATUS_IO_ERROR; 402141cc406Sopenharmony_ci return 0; 403141cc406Sopenharmony_ci } else if (dev->state) { 404141cc406Sopenharmony_ci if (dev->state != SANE_STATUS_DEVICE_BUSY) 405141cc406Sopenharmony_ci return 0; 406141cc406Sopenharmony_ci else { 407141cc406Sopenharmony_ci if (dev->non_blocking) { 408141cc406Sopenharmony_ci dev->state = SANE_STATUS_GOOD; 409141cc406Sopenharmony_ci return 0; 410141cc406Sopenharmony_ci } else { 411141cc406Sopenharmony_ci if (sleeptime > 1000) 412141cc406Sopenharmony_ci sleeptime = 1000; 413141cc406Sopenharmony_ci DBG(4, "(%s) sleeping(%d ms).. [%x %x]\n", 414141cc406Sopenharmony_ci str_cmd(cmd), sleeptime, dev->res[4], dev->res[5]); 415141cc406Sopenharmony_ci usleep(sleeptime * 1000); 416141cc406Sopenharmony_ci if (sleeptime < 1000) 417141cc406Sopenharmony_ci sleeptime *= (sleeptime < 100)? 10 : 2; 418141cc406Sopenharmony_ci } 419141cc406Sopenharmony_ci } /* BUSY */ 420141cc406Sopenharmony_ci } 421141cc406Sopenharmony_ci } while (dev->state == SANE_STATUS_DEVICE_BUSY); 422141cc406Sopenharmony_ci 423141cc406Sopenharmony_ci return 1; 424141cc406Sopenharmony_ci} 425141cc406Sopenharmony_ci 426141cc406Sopenharmony_cistatic int inq_dpi_bits[] = { 427141cc406Sopenharmony_ci 75, 150, 0, 0, 428141cc406Sopenharmony_ci 200, 300, 0, 0, 429141cc406Sopenharmony_ci 600, 0, 0, 1200, 430141cc406Sopenharmony_ci 100, 0, 0, 2400, 431141cc406Sopenharmony_ci 0, 4800, 0, 9600 432141cc406Sopenharmony_ci}; 433141cc406Sopenharmony_ci 434141cc406Sopenharmony_cistatic int res_dpi_codes[] = { 435141cc406Sopenharmony_ci 75, 0, 150, 0, 436141cc406Sopenharmony_ci 0, 300, 0, 600, 437141cc406Sopenharmony_ci 1200, 200, 100, 2400, 438141cc406Sopenharmony_ci 4800, 9600 439141cc406Sopenharmony_ci}; 440141cc406Sopenharmony_ci 441141cc406Sopenharmony_cistatic int SANE_Word_sort(const void *a, const void *b) 442141cc406Sopenharmony_ci{ 443141cc406Sopenharmony_ci return *(const SANE_Word *)a - *(const SANE_Word *)b; 444141cc406Sopenharmony_ci} 445141cc406Sopenharmony_ci 446141cc406Sopenharmony_ci/* resolve inquired dpi list to dpi_list array */ 447141cc406Sopenharmony_cistatic void resolv_inq_dpi(struct device *dev) 448141cc406Sopenharmony_ci{ 449141cc406Sopenharmony_ci unsigned int i; 450141cc406Sopenharmony_ci int res = dev->resolutions; 451141cc406Sopenharmony_ci 452141cc406Sopenharmony_ci assert(sizeof(inq_dpi_bits) < sizeof(dev->dpi_list)); 453141cc406Sopenharmony_ci for (i = 0; i < sizeof(inq_dpi_bits) / sizeof(int); i++) 454141cc406Sopenharmony_ci if (inq_dpi_bits[i] && (res & (1 << i))) 455141cc406Sopenharmony_ci dev->dpi_list[++dev->dpi_list[0]] = inq_dpi_bits[i]; 456141cc406Sopenharmony_ci qsort(&dev->dpi_list[1], dev->dpi_list[0], sizeof(SANE_Word), SANE_Word_sort); 457141cc406Sopenharmony_ci} 458141cc406Sopenharmony_ci 459141cc406Sopenharmony_cistatic unsigned int dpi_to_code(int dpi) 460141cc406Sopenharmony_ci{ 461141cc406Sopenharmony_ci unsigned int i; 462141cc406Sopenharmony_ci 463141cc406Sopenharmony_ci for (i = 0; i < sizeof(res_dpi_codes) / sizeof(int); i++) { 464141cc406Sopenharmony_ci if (dpi == res_dpi_codes[i]) 465141cc406Sopenharmony_ci return i; 466141cc406Sopenharmony_ci } 467141cc406Sopenharmony_ci return 0; 468141cc406Sopenharmony_ci} 469141cc406Sopenharmony_ci 470141cc406Sopenharmony_cistatic int string_match_index(const SANE_String_Const s[], SANE_String m) 471141cc406Sopenharmony_ci{ 472141cc406Sopenharmony_ci int i; 473141cc406Sopenharmony_ci 474141cc406Sopenharmony_ci for (i = 0; *s; i++) { 475141cc406Sopenharmony_ci SANE_String_Const x = *s++; 476141cc406Sopenharmony_ci if (strcasecmp(x, m) == 0) 477141cc406Sopenharmony_ci return i; 478141cc406Sopenharmony_ci } 479141cc406Sopenharmony_ci return 0; 480141cc406Sopenharmony_ci} 481141cc406Sopenharmony_ci 482141cc406Sopenharmony_cistatic SANE_String string_match(const SANE_String_Const s[], SANE_String m) 483141cc406Sopenharmony_ci{ 484141cc406Sopenharmony_ci return UNCONST(s[string_match_index(s, m)]); 485141cc406Sopenharmony_ci} 486141cc406Sopenharmony_ci 487141cc406Sopenharmony_cistatic size_t max_string_size(SANE_String_Const s[]) 488141cc406Sopenharmony_ci{ 489141cc406Sopenharmony_ci size_t max = 0; 490141cc406Sopenharmony_ci 491141cc406Sopenharmony_ci while (*s) { 492141cc406Sopenharmony_ci size_t size = strlen(*s++) + 1; 493141cc406Sopenharmony_ci if (size > max) 494141cc406Sopenharmony_ci max = size; 495141cc406Sopenharmony_ci } 496141cc406Sopenharmony_ci return max; 497141cc406Sopenharmony_ci} 498141cc406Sopenharmony_ci 499141cc406Sopenharmony_cistatic SANE_String_Const doc_sources[] = { 500141cc406Sopenharmony_ci "Flatbed", "ADF", "Auto", NULL 501141cc406Sopenharmony_ci}; 502141cc406Sopenharmony_ci 503141cc406Sopenharmony_cistatic int doc_source_to_code[] = { 504141cc406Sopenharmony_ci 0x40, 0x20, 0x80 505141cc406Sopenharmony_ci}; 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_cistatic SANE_String_Const scan_modes[] = { 508141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_LINEART, 509141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_HALFTONE, 510141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_GRAY, 511141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_COLOR, 512141cc406Sopenharmony_ci NULL 513141cc406Sopenharmony_ci}; 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_cistatic int scan_mode_to_code[] = { 516141cc406Sopenharmony_ci 0x00, 0x01, 0x03, 0x05 517141cc406Sopenharmony_ci}; 518141cc406Sopenharmony_ci 519141cc406Sopenharmony_cistatic SANE_Range threshold = { 520141cc406Sopenharmony_ci SANE_FIX(30), SANE_FIX(70), SANE_FIX(10) 521141cc406Sopenharmony_ci}; 522141cc406Sopenharmony_ci 523141cc406Sopenharmony_cistatic void reset_options(struct device *dev) 524141cc406Sopenharmony_ci{ 525141cc406Sopenharmony_ci dev->val[OPT_RESOLUTION].w = 150; 526141cc406Sopenharmony_ci dev->val[OPT_MODE].s = string_match(scan_modes, SANE_VALUE_SCAN_MODE_COLOR); 527141cc406Sopenharmony_ci 528141cc406Sopenharmony_ci /* if docs loaded in adf use it as default source, flatbed otherwise */ 529141cc406Sopenharmony_ci dev->val[OPT_SOURCE].s = UNCONST(doc_sources[(dev->doc_loaded)? 1 : 0]); 530141cc406Sopenharmony_ci 531141cc406Sopenharmony_ci dev->val[OPT_THRESHOLD].w = SANE_FIX(50); 532141cc406Sopenharmony_ci 533141cc406Sopenharmony_ci /* this is reported maximum window size, will be fixed later */ 534141cc406Sopenharmony_ci dev->win_x_range.min = SANE_FIX(0); 535141cc406Sopenharmony_ci dev->win_x_range.max = SANE_FIX((double)dev->max_win_width / PNT_PER_MM); 536141cc406Sopenharmony_ci dev->win_x_range.quant = SANE_FIX(1); 537141cc406Sopenharmony_ci dev->win_y_range.min = SANE_FIX(0); 538141cc406Sopenharmony_ci dev->win_y_range.max = SANE_FIX((double)dev->max_win_len / PNT_PER_MM); 539141cc406Sopenharmony_ci dev->win_y_range.quant = SANE_FIX(1); 540141cc406Sopenharmony_ci dev->val[OPT_SCAN_TL_X].w = dev->win_x_range.min; 541141cc406Sopenharmony_ci dev->val[OPT_SCAN_TL_Y].w = dev->win_y_range.min; 542141cc406Sopenharmony_ci dev->val[OPT_SCAN_BR_X].w = dev->win_x_range.max; 543141cc406Sopenharmony_ci dev->val[OPT_SCAN_BR_Y].w = dev->win_y_range.max; 544141cc406Sopenharmony_ci} 545141cc406Sopenharmony_ci 546141cc406Sopenharmony_cistatic void init_options(struct device *dev) 547141cc406Sopenharmony_ci{ 548141cc406Sopenharmony_ci int i; 549141cc406Sopenharmony_ci 550141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; i++) { 551141cc406Sopenharmony_ci dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 552141cc406Sopenharmony_ci dev->opt[i].size = sizeof(SANE_Word); 553141cc406Sopenharmony_ci dev->opt[i].type = SANE_TYPE_FIXED; 554141cc406Sopenharmony_ci dev->val[i].s = NULL; 555141cc406Sopenharmony_ci } 556141cc406Sopenharmony_ci 557141cc406Sopenharmony_ci dev->opt[OPT_NUMOPTIONS].name = SANE_NAME_NUM_OPTIONS; 558141cc406Sopenharmony_ci dev->opt[OPT_NUMOPTIONS].title = SANE_TITLE_NUM_OPTIONS; 559141cc406Sopenharmony_ci dev->opt[OPT_NUMOPTIONS].desc = SANE_DESC_NUM_OPTIONS; 560141cc406Sopenharmony_ci dev->opt[OPT_NUMOPTIONS].type = SANE_TYPE_INT; 561141cc406Sopenharmony_ci dev->opt[OPT_NUMOPTIONS].cap = SANE_CAP_SOFT_DETECT; 562141cc406Sopenharmony_ci dev->val[OPT_NUMOPTIONS].w = NUM_OPTIONS; 563141cc406Sopenharmony_ci 564141cc406Sopenharmony_ci dev->opt[OPT_GROUP_STD].name = SANE_NAME_STANDARD; 565141cc406Sopenharmony_ci dev->opt[OPT_GROUP_STD].title = SANE_TITLE_STANDARD; 566141cc406Sopenharmony_ci dev->opt[OPT_GROUP_STD].desc = SANE_DESC_STANDARD; 567141cc406Sopenharmony_ci dev->opt[OPT_GROUP_STD].type = SANE_TYPE_GROUP; 568141cc406Sopenharmony_ci dev->opt[OPT_GROUP_STD].cap = 0; 569141cc406Sopenharmony_ci 570141cc406Sopenharmony_ci dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; 571141cc406Sopenharmony_ci dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; 572141cc406Sopenharmony_ci dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; 573141cc406Sopenharmony_ci dev->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; 574141cc406Sopenharmony_ci dev->opt[OPT_RESOLUTION].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; 575141cc406Sopenharmony_ci dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; 576141cc406Sopenharmony_ci dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; 577141cc406Sopenharmony_ci dev->opt[OPT_RESOLUTION].constraint.word_list = dev->dpi_list; 578141cc406Sopenharmony_ci 579141cc406Sopenharmony_ci dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; 580141cc406Sopenharmony_ci dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; 581141cc406Sopenharmony_ci dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; 582141cc406Sopenharmony_ci dev->opt[OPT_MODE].type = SANE_TYPE_STRING; 583141cc406Sopenharmony_ci dev->opt[OPT_MODE].size = max_string_size(scan_modes); 584141cc406Sopenharmony_ci dev->opt[OPT_MODE].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; 585141cc406Sopenharmony_ci dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 586141cc406Sopenharmony_ci dev->opt[OPT_MODE].constraint.string_list = scan_modes; 587141cc406Sopenharmony_ci 588141cc406Sopenharmony_ci dev->opt[OPT_THRESHOLD].name = SANE_NAME_HIGHLIGHT; 589141cc406Sopenharmony_ci dev->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; 590141cc406Sopenharmony_ci dev->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; 591141cc406Sopenharmony_ci dev->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; 592141cc406Sopenharmony_ci dev->opt[OPT_THRESHOLD].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; 593141cc406Sopenharmony_ci dev->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; 594141cc406Sopenharmony_ci dev->opt[OPT_THRESHOLD].constraint.range = &threshold; 595141cc406Sopenharmony_ci 596141cc406Sopenharmony_ci dev->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; 597141cc406Sopenharmony_ci dev->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; 598141cc406Sopenharmony_ci dev->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; 599141cc406Sopenharmony_ci dev->opt[OPT_SOURCE].type = SANE_TYPE_STRING; 600141cc406Sopenharmony_ci dev->opt[OPT_SOURCE].size = max_string_size(doc_sources); 601141cc406Sopenharmony_ci dev->opt[OPT_SOURCE].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; 602141cc406Sopenharmony_ci dev->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 603141cc406Sopenharmony_ci dev->opt[OPT_SOURCE].constraint.string_list = doc_sources; 604141cc406Sopenharmony_ci 605141cc406Sopenharmony_ci dev->opt[OPT_JPEG].name = "jpeg"; 606141cc406Sopenharmony_ci dev->opt[OPT_JPEG].title = SANE_I18N("jpeg compression"); 607141cc406Sopenharmony_ci dev->opt[OPT_JPEG].desc = SANE_I18N("JPEG Image Compression"); 608141cc406Sopenharmony_ci dev->opt[OPT_JPEG].unit = SANE_UNIT_NONE; 609141cc406Sopenharmony_ci dev->opt[OPT_JPEG].type = SANE_TYPE_BOOL; 610141cc406Sopenharmony_ci dev->opt[OPT_JPEG].cap |= SANE_CAP_ADVANCED; 611141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 612141cc406Sopenharmony_ci dev->compressionEnabled = SANE_TRUE; 613141cc406Sopenharmony_ci if (!isSupportedDevice(dev)) 614141cc406Sopenharmony_ci dev->opt[OPT_JPEG].cap |= SANE_CAP_INACTIVE; 615141cc406Sopenharmony_ci dev->val[OPT_JPEG].b = SANE_TRUE; 616141cc406Sopenharmony_ci#else 617141cc406Sopenharmony_ci dev->opt[OPT_JPEG].cap |= SANE_CAP_INACTIVE; 618141cc406Sopenharmony_ci dev->val[OPT_JPEG].b = SANE_FALSE; 619141cc406Sopenharmony_ci#endif 620141cc406Sopenharmony_ci 621141cc406Sopenharmony_ci dev->opt[OPT_GROUP_GEO].name = SANE_NAME_GEOMETRY; 622141cc406Sopenharmony_ci dev->opt[OPT_GROUP_GEO].title = SANE_TITLE_GEOMETRY; 623141cc406Sopenharmony_ci dev->opt[OPT_GROUP_GEO].desc = SANE_DESC_GEOMETRY; 624141cc406Sopenharmony_ci dev->opt[OPT_GROUP_GEO].type = SANE_TYPE_GROUP; 625141cc406Sopenharmony_ci dev->opt[OPT_GROUP_GEO].cap = 0; 626141cc406Sopenharmony_ci 627141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_X].name = SANE_NAME_SCAN_TL_X; 628141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_X].title = SANE_TITLE_SCAN_TL_X; 629141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_X].desc = SANE_DESC_SCAN_TL_X; 630141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_X].unit = SANE_UNIT_MM; 631141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 632141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_X].constraint.range = &dev->win_x_range; 633141cc406Sopenharmony_ci 634141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_Y].name = SANE_NAME_SCAN_TL_Y; 635141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 636141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 637141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_Y].unit = SANE_UNIT_MM; 638141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 639141cc406Sopenharmony_ci dev->opt[OPT_SCAN_TL_Y].constraint.range = &dev->win_y_range; 640141cc406Sopenharmony_ci 641141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_X].name = SANE_NAME_SCAN_BR_X; 642141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_X].title = SANE_TITLE_SCAN_BR_X; 643141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_X].desc = SANE_DESC_SCAN_BR_X; 644141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_X].unit = SANE_UNIT_MM; 645141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 646141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_X].constraint.range = &dev->win_x_range; 647141cc406Sopenharmony_ci 648141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_Y].name = SANE_NAME_SCAN_BR_Y; 649141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 650141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 651141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_Y].unit = SANE_UNIT_MM; 652141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 653141cc406Sopenharmony_ci dev->opt[OPT_SCAN_BR_Y].constraint.range = &dev->win_y_range; 654141cc406Sopenharmony_ci} 655141cc406Sopenharmony_ci 656141cc406Sopenharmony_ci/* fill parameters from options */ 657141cc406Sopenharmony_cistatic void set_parameters(struct device *dev) 658141cc406Sopenharmony_ci{ 659141cc406Sopenharmony_ci double px_to_len; 660141cc406Sopenharmony_ci 661141cc406Sopenharmony_ci dev->para.last_frame = SANE_TRUE; 662141cc406Sopenharmony_ci dev->para.lines = -1; 663141cc406Sopenharmony_ci px_to_len = 1200.0 / dev->val[OPT_RESOLUTION].w; 664141cc406Sopenharmony_ci#define BETTER_BASEDPI 1 665141cc406Sopenharmony_ci /* tests prove that 1200dpi base is very inexact 666141cc406Sopenharmony_ci * so I calculated better values for each axis */ 667141cc406Sopenharmony_ci#if BETTER_BASEDPI 668141cc406Sopenharmony_ci px_to_len = 1180.0 / dev->val[OPT_RESOLUTION].w; 669141cc406Sopenharmony_ci#endif 670141cc406Sopenharmony_ci dev->para.pixels_per_line = dev->win_width / px_to_len; 671141cc406Sopenharmony_ci dev->para.bytes_per_line = dev->para.pixels_per_line; 672141cc406Sopenharmony_ci 673141cc406Sopenharmony_ci DBG(5, dev->val[OPT_JPEG].b ? "JPEG compression enabled\n" : "JPEG compression disabled\n" ); 674141cc406Sopenharmony_ci dev->compressionEnabled = dev->val[OPT_JPEG].b; 675141cc406Sopenharmony_ci 676141cc406Sopenharmony_ci if (!isJPEGEnabled(dev)) { 677141cc406Sopenharmony_ci#if BETTER_BASEDPI 678141cc406Sopenharmony_ci px_to_len = 1213.9 / dev->val[OPT_RESOLUTION].w; 679141cc406Sopenharmony_ci#endif 680141cc406Sopenharmony_ci } 681141cc406Sopenharmony_ci dev->para.lines = dev->win_len / px_to_len; 682141cc406Sopenharmony_ci if (dev->composition == MODE_LINEART || 683141cc406Sopenharmony_ci dev->composition == MODE_HALFTONE) { 684141cc406Sopenharmony_ci dev->para.format = SANE_FRAME_GRAY; 685141cc406Sopenharmony_ci dev->para.depth = 1; 686141cc406Sopenharmony_ci dev->para.bytes_per_line = (dev->para.pixels_per_line + 7) / 8; 687141cc406Sopenharmony_ci } else if (dev->composition == MODE_GRAY8) { 688141cc406Sopenharmony_ci dev->para.format = SANE_FRAME_GRAY; 689141cc406Sopenharmony_ci dev->para.depth = 8; 690141cc406Sopenharmony_ci dev->para.bytes_per_line = dev->para.pixels_per_line; 691141cc406Sopenharmony_ci } else if (dev->composition == MODE_RGB24) { 692141cc406Sopenharmony_ci dev->para.format = SANE_FRAME_RGB; 693141cc406Sopenharmony_ci dev->para.depth = 8; 694141cc406Sopenharmony_ci dev->para.bytes_per_line *= 3; 695141cc406Sopenharmony_ci } else { 696141cc406Sopenharmony_ci /* this will never happen */ 697141cc406Sopenharmony_ci DBG(1, "%s: impossible image composition %d\n", 698141cc406Sopenharmony_ci __func__, dev->composition); 699141cc406Sopenharmony_ci dev->para.format = SANE_FRAME_GRAY; 700141cc406Sopenharmony_ci dev->para.depth = 8; 701141cc406Sopenharmony_ci } 702141cc406Sopenharmony_ci} 703141cc406Sopenharmony_ci 704141cc406Sopenharmony_ci/* resolve all options related to scan window */ 705141cc406Sopenharmony_ci/* called after option changed and in set_window */ 706141cc406Sopenharmony_cistatic int fix_window(struct device *dev) 707141cc406Sopenharmony_ci{ 708141cc406Sopenharmony_ci double win_width_mm, win_len_mm; 709141cc406Sopenharmony_ci int i; 710141cc406Sopenharmony_ci int threshold = SANE_UNFIX(dev->val[OPT_THRESHOLD].w); 711141cc406Sopenharmony_ci 712141cc406Sopenharmony_ci dev->resolution = dpi_to_code(dev->val[OPT_RESOLUTION].w); 713141cc406Sopenharmony_ci dev->composition = scan_mode_to_code[string_match_index(scan_modes, dev->val[OPT_MODE].s)]; 714141cc406Sopenharmony_ci 715141cc406Sopenharmony_ci if (dev->composition == MODE_LINEART || 716141cc406Sopenharmony_ci dev->composition == MODE_HALFTONE) { 717141cc406Sopenharmony_ci dev->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE; 718141cc406Sopenharmony_ci } else { 719141cc406Sopenharmony_ci dev->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; 720141cc406Sopenharmony_ci } 721141cc406Sopenharmony_ci if (threshold < 30) { 722141cc406Sopenharmony_ci dev->val[OPT_THRESHOLD].w = SANE_FIX(30); 723141cc406Sopenharmony_ci } else if (threshold > 70) { 724141cc406Sopenharmony_ci dev->val[OPT_THRESHOLD].w = SANE_FIX(70); 725141cc406Sopenharmony_ci } 726141cc406Sopenharmony_ci threshold = SANE_UNFIX(dev->val[OPT_THRESHOLD].w); 727141cc406Sopenharmony_ci dev->threshold = (threshold - 30) / 10; 728141cc406Sopenharmony_ci dev->val[OPT_THRESHOLD].w = SANE_FIX(dev->threshold * 10 + 30); 729141cc406Sopenharmony_ci 730141cc406Sopenharmony_ci dev->doc_source = doc_source_to_code[string_match_index(doc_sources, dev->val[OPT_SOURCE].s)]; 731141cc406Sopenharmony_ci 732141cc406Sopenharmony_ci /* max window len is dependent of document source */ 733141cc406Sopenharmony_ci if (dev->doc_source == DOC_FLATBED || 734141cc406Sopenharmony_ci (dev->doc_source == DOC_AUTO && !dev->doc_loaded)) 735141cc406Sopenharmony_ci dev->max_len = dev->max_len_fb; 736141cc406Sopenharmony_ci else 737141cc406Sopenharmony_ci dev->max_len = dev->max_len_adf; 738141cc406Sopenharmony_ci 739141cc406Sopenharmony_ci /* parameters */ 740141cc406Sopenharmony_ci dev->win_y_range.max = SANE_FIX((double)dev->max_len / PNT_PER_MM); 741141cc406Sopenharmony_ci 742141cc406Sopenharmony_ci /* window sanity checking */ 743141cc406Sopenharmony_ci for (i = OPT_SCAN_TL_X; i <= OPT_SCAN_BR_Y; i++) { 744141cc406Sopenharmony_ci if (dev->val[i].w < dev->opt[i].constraint.range->min) 745141cc406Sopenharmony_ci dev->val[i].w = dev->opt[i].constraint.range->min; 746141cc406Sopenharmony_ci if (dev->val[i].w > dev->opt[i].constraint.range->max) 747141cc406Sopenharmony_ci dev->val[i].w = dev->opt[i].constraint.range->max; 748141cc406Sopenharmony_ci } 749141cc406Sopenharmony_ci 750141cc406Sopenharmony_ci if (dev->val[OPT_SCAN_TL_X].w > dev->val[OPT_SCAN_BR_X].w) 751141cc406Sopenharmony_ci SWAP_Word(dev->val[OPT_SCAN_TL_X].w, dev->val[OPT_SCAN_BR_X].w); 752141cc406Sopenharmony_ci if (dev->val[OPT_SCAN_TL_Y].w > dev->val[OPT_SCAN_BR_Y].w) 753141cc406Sopenharmony_ci SWAP_Word(dev->val[OPT_SCAN_TL_Y].w, dev->val[OPT_SCAN_BR_Y].w); 754141cc406Sopenharmony_ci 755141cc406Sopenharmony_ci /* recalculate millimeters to inches */ 756141cc406Sopenharmony_ci dev->win_off_x = SANE_UNFIX(dev->val[OPT_SCAN_TL_X].w) / MM_PER_INCH; 757141cc406Sopenharmony_ci dev->win_off_y = SANE_UNFIX(dev->val[OPT_SCAN_TL_Y].w) / MM_PER_INCH; 758141cc406Sopenharmony_ci 759141cc406Sopenharmony_ci /* calc win size in mm */ 760141cc406Sopenharmony_ci win_width_mm = SANE_UNFIX(dev->val[OPT_SCAN_BR_X].w) - 761141cc406Sopenharmony_ci SANE_UNFIX(dev->val[OPT_SCAN_TL_X].w); 762141cc406Sopenharmony_ci win_len_mm = SANE_UNFIX(dev->val[OPT_SCAN_BR_Y].w) - 763141cc406Sopenharmony_ci SANE_UNFIX(dev->val[OPT_SCAN_TL_Y].w); 764141cc406Sopenharmony_ci /* convert mm to 1200 dpi points */ 765141cc406Sopenharmony_ci dev->win_width = (int)(win_width_mm * PNT_PER_MM); 766141cc406Sopenharmony_ci dev->win_len = (int)(win_len_mm * PNT_PER_MM); 767141cc406Sopenharmony_ci 768141cc406Sopenharmony_ci /* don't scan if window is zero size */ 769141cc406Sopenharmony_ci if (!dev->win_width || !dev->win_len) { 770141cc406Sopenharmony_ci /* "The scan cannot be started with the current set of options." */ 771141cc406Sopenharmony_ci dev->state = SANE_STATUS_INVAL; 772141cc406Sopenharmony_ci return 0; 773141cc406Sopenharmony_ci } 774141cc406Sopenharmony_ci 775141cc406Sopenharmony_ci return 1; 776141cc406Sopenharmony_ci} 777141cc406Sopenharmony_ci 778141cc406Sopenharmony_cistatic int dev_set_window(struct device *dev) 779141cc406Sopenharmony_ci{ 780141cc406Sopenharmony_ci SANE_Byte cmd[0x19] = { 781141cc406Sopenharmony_ci REQ_CODE_A, REQ_CODE_B, CMD_SET_WINDOW, 0x13, MSG_SCANNING_PARAM 782141cc406Sopenharmony_ci }; 783141cc406Sopenharmony_ci 784141cc406Sopenharmony_ci if (!fix_window(dev)) 785141cc406Sopenharmony_ci return 0; 786141cc406Sopenharmony_ci 787141cc406Sopenharmony_ci cmd[0x05] = dev->win_width >> 24; 788141cc406Sopenharmony_ci cmd[0x06] = dev->win_width >> 16; 789141cc406Sopenharmony_ci cmd[0x07] = dev->win_width >> 8; 790141cc406Sopenharmony_ci cmd[0x08] = dev->win_width; 791141cc406Sopenharmony_ci cmd[0x09] = dev->win_len >> 24; 792141cc406Sopenharmony_ci cmd[0x0a] = dev->win_len >> 16; 793141cc406Sopenharmony_ci cmd[0x0b] = dev->win_len >> 8; 794141cc406Sopenharmony_ci cmd[0x0c] = dev->win_len; 795141cc406Sopenharmony_ci cmd[0x0d] = dev->resolution; /* x */ 796141cc406Sopenharmony_ci cmd[0x0e] = dev->resolution; /* y */ 797141cc406Sopenharmony_ci cmd[0x0f] = (SANE_Byte)floor(dev->win_off_x); 798141cc406Sopenharmony_ci cmd[0x10] = (SANE_Byte)((dev->win_off_x - floor(dev->win_off_x)) * 100); 799141cc406Sopenharmony_ci cmd[0x11] = (SANE_Byte)floor(dev->win_off_y); 800141cc406Sopenharmony_ci cmd[0x12] = (SANE_Byte)((dev->win_off_y - floor(dev->win_off_y)) * 100); 801141cc406Sopenharmony_ci cmd[0x13] = dev->composition; 802141cc406Sopenharmony_ci /* Set to JPEG Lossy Compression, if mode is color (only for supported model)... 803141cc406Sopenharmony_ci * else go with Uncompressed (For backard compatibility with old models )*/ 804141cc406Sopenharmony_ci if (dev->composition == MODE_RGB24) { 805141cc406Sopenharmony_ci if (isJPEGEnabled(dev)) { 806141cc406Sopenharmony_ci cmd[0x14] = 0x6; 807141cc406Sopenharmony_ci } 808141cc406Sopenharmony_ci } 809141cc406Sopenharmony_ci cmd[0x16] = dev->threshold; 810141cc406Sopenharmony_ci cmd[0x17] = dev->doc_source; 811141cc406Sopenharmony_ci 812141cc406Sopenharmony_ci DBG(5, "OFF xi: %02x%02x yi: %02x%02x," 813141cc406Sopenharmony_ci " WIN xp: %02x%02x%02x%02x yp %02x%02x%02x%02x," 814141cc406Sopenharmony_ci " MAX %08x %08x\n", 815141cc406Sopenharmony_ci cmd[0x0f], cmd[0x10], cmd[0x11], cmd[0x12], 816141cc406Sopenharmony_ci cmd[0x05], cmd[0x06], cmd[0x07], cmd[0x08], 817141cc406Sopenharmony_ci cmd[0x09], cmd[0x0a], cmd[0x0b], cmd[0x0c], 818141cc406Sopenharmony_ci dev->max_win_width, dev->max_win_len); 819141cc406Sopenharmony_ci 820141cc406Sopenharmony_ci return dev_command(dev, cmd, 32); 821141cc406Sopenharmony_ci} 822141cc406Sopenharmony_ci 823141cc406Sopenharmony_cistatic SANE_Status 824141cc406Sopenharmony_cidev_inquiry(struct device *dev) 825141cc406Sopenharmony_ci{ 826141cc406Sopenharmony_ci SANE_Byte *ptr; 827141cc406Sopenharmony_ci SANE_Char *optr, *xptr; 828141cc406Sopenharmony_ci 829141cc406Sopenharmony_ci if (!dev_cmd(dev, CMD_INQUIRY)) 830141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 831141cc406Sopenharmony_ci ptr = dev->res; 832141cc406Sopenharmony_ci if (ptr[3] != MSG_PRODUCT_INFO) { 833141cc406Sopenharmony_ci DBG(1, "%s: illegal INQUIRY response %02x\n", __func__, ptr[3]); 834141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 835141cc406Sopenharmony_ci } 836141cc406Sopenharmony_ci 837141cc406Sopenharmony_ci /* parse reported manufacturer/product names */ 838141cc406Sopenharmony_ci dev->sane.vendor = optr = (SANE_Char *) malloc(33); 839141cc406Sopenharmony_ci for (ptr += 4; ptr < &dev->res[0x24] && *ptr && *ptr != ' ';) 840141cc406Sopenharmony_ci *optr++ = *ptr++; 841141cc406Sopenharmony_ci *optr++ = 0; 842141cc406Sopenharmony_ci 843141cc406Sopenharmony_ci for (; ptr < &dev->res[0x24] && (!*ptr || *ptr == ' '); ptr++) 844141cc406Sopenharmony_ci /* skip spaces */; 845141cc406Sopenharmony_ci 846141cc406Sopenharmony_ci dev->sane.model = optr = (SANE_Char *) malloc(33); 847141cc406Sopenharmony_ci xptr = optr; /* is last non space character + 1 */ 848141cc406Sopenharmony_ci for (; ptr < &dev->res[0x24] && *ptr;) { 849141cc406Sopenharmony_ci if (*ptr != ' ') 850141cc406Sopenharmony_ci xptr = optr + 1; 851141cc406Sopenharmony_ci *optr++ = *ptr++; 852141cc406Sopenharmony_ci } 853141cc406Sopenharmony_ci *optr++ = 0; 854141cc406Sopenharmony_ci *xptr = 0; 855141cc406Sopenharmony_ci 856141cc406Sopenharmony_ci DBG(1, "%s: found %s/%s\n", __func__, dev->sane.vendor, dev->sane.model); 857141cc406Sopenharmony_ci dev->sane.type = strdup("multi-function peripheral"); 858141cc406Sopenharmony_ci 859141cc406Sopenharmony_ci dev->resolutions = dev->res[0x37] << 16 | 860141cc406Sopenharmony_ci dev->res[0x24] << 8 | 861141cc406Sopenharmony_ci dev->res[0x25]; 862141cc406Sopenharmony_ci dev->compositions = dev->res[0x27]; 863141cc406Sopenharmony_ci dev->max_win_width = dev->res[0x28] << 24 | 864141cc406Sopenharmony_ci dev->res[0x29] << 16 | 865141cc406Sopenharmony_ci dev->res[0x2a] << 8 | 866141cc406Sopenharmony_ci dev->res[0x2b]; 867141cc406Sopenharmony_ci dev->max_win_len = dev->res[0x2c] << 24 | 868141cc406Sopenharmony_ci dev->res[0x2d] << 16 | 869141cc406Sopenharmony_ci dev->res[0x2e] << 8 | 870141cc406Sopenharmony_ci dev->res[0x2f]; 871141cc406Sopenharmony_ci dev->max_len_adf = dev->res[0x38] << 24 | 872141cc406Sopenharmony_ci dev->res[0x39] << 16 | 873141cc406Sopenharmony_ci dev->res[0x3a] << 8 | 874141cc406Sopenharmony_ci dev->res[0x3b]; 875141cc406Sopenharmony_ci dev->max_len_fb = dev->res[0x3c] << 24 | 876141cc406Sopenharmony_ci dev->res[0x3d] << 16 | 877141cc406Sopenharmony_ci dev->res[0x3e] << 8 | 878141cc406Sopenharmony_ci dev->res[0x3f]; 879141cc406Sopenharmony_ci dev->line_order = dev->res[0x31]; 880141cc406Sopenharmony_ci dev->compressionTypes = dev->res[0x32]; 881141cc406Sopenharmony_ci dev->doc_loaded = (dev->res[0x35] == 0x02) && 882141cc406Sopenharmony_ci (dev->res[0x26] & 0x03); 883141cc406Sopenharmony_ci 884141cc406Sopenharmony_ci init_options(dev); 885141cc406Sopenharmony_ci reset_options(dev); 886141cc406Sopenharmony_ci fix_window(dev); 887141cc406Sopenharmony_ci set_parameters(dev); 888141cc406Sopenharmony_ci resolv_inq_dpi(dev); 889141cc406Sopenharmony_ci 890141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 891141cc406Sopenharmony_ci} 892141cc406Sopenharmony_ci 893141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 894141cc406Sopenharmony_cisane_get_option_descriptor(SANE_Handle h, SANE_Int opt) 895141cc406Sopenharmony_ci{ 896141cc406Sopenharmony_ci struct device *dev = h; 897141cc406Sopenharmony_ci 898141cc406Sopenharmony_ci DBG(3, "%s: %p, %d\n", __func__, h, opt); 899141cc406Sopenharmony_ci if (opt >= NUM_OPTIONS || opt < 0) 900141cc406Sopenharmony_ci return NULL; 901141cc406Sopenharmony_ci return &dev->opt[opt]; 902141cc406Sopenharmony_ci} 903141cc406Sopenharmony_ci 904141cc406Sopenharmony_ciSANE_Status 905141cc406Sopenharmony_cisane_control_option(SANE_Handle h, SANE_Int opt, SANE_Action act, 906141cc406Sopenharmony_ci void *val, SANE_Word *info) 907141cc406Sopenharmony_ci{ 908141cc406Sopenharmony_ci struct device *dev = h; 909141cc406Sopenharmony_ci 910141cc406Sopenharmony_ci DBG(3, "%s: %p, %d, <%d>, %p, %p\n", __func__, h, opt, act, val, (void *)info); 911141cc406Sopenharmony_ci if (!dev || opt >= NUM_OPTIONS || opt < 0) 912141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 913141cc406Sopenharmony_ci 914141cc406Sopenharmony_ci if (info) 915141cc406Sopenharmony_ci *info = 0; 916141cc406Sopenharmony_ci 917141cc406Sopenharmony_ci if (act == SANE_ACTION_GET_VALUE) { /* GET */ 918141cc406Sopenharmony_ci if (dev->opt[opt].type == SANE_TYPE_STRING) 919141cc406Sopenharmony_ci strcpy(val, dev->val[opt].s); 920141cc406Sopenharmony_ci else 921141cc406Sopenharmony_ci *(SANE_Word *)val = dev->val[opt].w; 922141cc406Sopenharmony_ci } else if (act == SANE_ACTION_SET_VALUE) { /* SET */ 923141cc406Sopenharmony_ci SANE_Parameters xpara = dev->para; 924141cc406Sopenharmony_ci SANE_Option_Descriptor xopt[NUM_OPTIONS]; 925141cc406Sopenharmony_ci Option_Value xval[NUM_OPTIONS]; 926141cc406Sopenharmony_ci int i; 927141cc406Sopenharmony_ci 928141cc406Sopenharmony_ci if (dev->opt[opt].constraint_type == SANE_CONSTRAINT_STRING_LIST) { 929141cc406Sopenharmony_ci dev->val[opt].s = string_match(dev->opt[opt].constraint.string_list, val); 930141cc406Sopenharmony_ci if (info && strcasecmp(dev->val[opt].s, val)) 931141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 932141cc406Sopenharmony_ci } else if (opt == OPT_RESOLUTION) 933141cc406Sopenharmony_ci dev->val[opt].w = res_dpi_codes[dpi_to_code(*(SANE_Word *)val)]; 934141cc406Sopenharmony_ci else 935141cc406Sopenharmony_ci dev->val[opt].w = *(SANE_Word *)val; 936141cc406Sopenharmony_ci 937141cc406Sopenharmony_ci memcpy(&xopt, &dev->opt, sizeof(xopt)); 938141cc406Sopenharmony_ci memcpy(&xval, &dev->val, sizeof(xval)); 939141cc406Sopenharmony_ci fix_window(dev); 940141cc406Sopenharmony_ci set_parameters(dev); 941141cc406Sopenharmony_ci 942141cc406Sopenharmony_ci /* check for side effects */ 943141cc406Sopenharmony_ci if (info) { 944141cc406Sopenharmony_ci if (memcmp(&xpara, &dev->para, sizeof(xpara))) 945141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 946141cc406Sopenharmony_ci if (memcmp(&xopt, &dev->opt, sizeof(xopt))) 947141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 948141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; i++) 949141cc406Sopenharmony_ci if (xval[i].w != dev->val[i].w) { 950141cc406Sopenharmony_ci if (i == opt) 951141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 952141cc406Sopenharmony_ci else 953141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS; 954141cc406Sopenharmony_ci } 955141cc406Sopenharmony_ci } 956141cc406Sopenharmony_ci } 957141cc406Sopenharmony_ci 958141cc406Sopenharmony_ci DBG(4, "%s: %d, <%d> => %08x, %x\n", __func__, opt, act, 959141cc406Sopenharmony_ci val? *(SANE_Word *)val : 0, info? *info : 0); 960141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 961141cc406Sopenharmony_ci} 962141cc406Sopenharmony_ci 963141cc406Sopenharmony_cistatic void 964141cc406Sopenharmony_cidev_free(struct device *dev) 965141cc406Sopenharmony_ci{ 966141cc406Sopenharmony_ci if (!dev) 967141cc406Sopenharmony_ci return; 968141cc406Sopenharmony_ci 969141cc406Sopenharmony_ci if (dev->sane.name) 970141cc406Sopenharmony_ci free(UNCONST(dev->sane.name)); 971141cc406Sopenharmony_ci if (dev->sane.vendor) 972141cc406Sopenharmony_ci free(UNCONST(dev->sane.vendor)); 973141cc406Sopenharmony_ci if (dev->sane.model) 974141cc406Sopenharmony_ci free(UNCONST(dev->sane.model)); 975141cc406Sopenharmony_ci if (dev->sane.type) 976141cc406Sopenharmony_ci free(UNCONST(dev->sane.type)); 977141cc406Sopenharmony_ci if (dev->data) 978141cc406Sopenharmony_ci free(dev->data); 979141cc406Sopenharmony_ci if (dev->decData) { 980141cc406Sopenharmony_ci free(dev->decData); 981141cc406Sopenharmony_ci dev->decData = NULL; 982141cc406Sopenharmony_ci } 983141cc406Sopenharmony_ci memset(dev, 0, sizeof(*dev)); 984141cc406Sopenharmony_ci free(dev); 985141cc406Sopenharmony_ci} 986141cc406Sopenharmony_ci 987141cc406Sopenharmony_cistatic void 988141cc406Sopenharmony_cifree_devices(void) 989141cc406Sopenharmony_ci{ 990141cc406Sopenharmony_ci struct device *next; 991141cc406Sopenharmony_ci struct device *dev; 992141cc406Sopenharmony_ci 993141cc406Sopenharmony_ci if (devlist) { 994141cc406Sopenharmony_ci free(devlist); 995141cc406Sopenharmony_ci devlist = NULL; 996141cc406Sopenharmony_ci } 997141cc406Sopenharmony_ci for (dev = devices_head; dev; dev = next) { 998141cc406Sopenharmony_ci next = dev->next; 999141cc406Sopenharmony_ci dev_free(dev); 1000141cc406Sopenharmony_ci } 1001141cc406Sopenharmony_ci devices_head = NULL; 1002141cc406Sopenharmony_ci} 1003141cc406Sopenharmony_ci 1004141cc406Sopenharmony_cistatic transport *tr_from_devname(SANE_String_Const devname) 1005141cc406Sopenharmony_ci{ 1006141cc406Sopenharmony_ci if (strncmp("tcp", devname, 3) == 0) 1007141cc406Sopenharmony_ci return &available_transports[TRANSPORT_TCP]; 1008141cc406Sopenharmony_ci return &available_transports[TRANSPORT_USB]; 1009141cc406Sopenharmony_ci} 1010141cc406Sopenharmony_ci 1011141cc406Sopenharmony_cistatic SANE_Status 1012141cc406Sopenharmony_cilist_one_device(SANE_String_Const devname) 1013141cc406Sopenharmony_ci{ 1014141cc406Sopenharmony_ci struct device *dev; 1015141cc406Sopenharmony_ci SANE_Status status; 1016141cc406Sopenharmony_ci transport *tr; 1017141cc406Sopenharmony_ci 1018141cc406Sopenharmony_ci DBG(4, "%s: %s\n", __func__, devname); 1019141cc406Sopenharmony_ci 1020141cc406Sopenharmony_ci for (dev = devices_head; dev; dev = dev->next) { 1021141cc406Sopenharmony_ci if (strcmp(dev->sane.name, devname) == 0) 1022141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1023141cc406Sopenharmony_ci } 1024141cc406Sopenharmony_ci 1025141cc406Sopenharmony_ci tr = tr_from_devname(devname); 1026141cc406Sopenharmony_ci 1027141cc406Sopenharmony_ci dev = calloc(1, sizeof(struct device)); 1028141cc406Sopenharmony_ci if (dev == NULL) 1029141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1030141cc406Sopenharmony_ci 1031141cc406Sopenharmony_ci dev->sane.name = strdup(devname); 1032141cc406Sopenharmony_ci dev->io = tr; 1033141cc406Sopenharmony_ci status = tr->dev_open(dev); 1034141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1035141cc406Sopenharmony_ci dev_free(dev); 1036141cc406Sopenharmony_ci return status; 1037141cc406Sopenharmony_ci } 1038141cc406Sopenharmony_ci 1039141cc406Sopenharmony_ci /* status = dev_cmd (dev, CMD_ABORT);*/ 1040141cc406Sopenharmony_ci status = dev_inquiry(dev); 1041141cc406Sopenharmony_ci tr->dev_close(dev); 1042141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1043141cc406Sopenharmony_ci DBG(1, "%s: dev_inquiry(%s): %s\n", __func__, 1044141cc406Sopenharmony_ci dev->sane.name, sane_strstatus(status)); 1045141cc406Sopenharmony_ci dev_free(dev); 1046141cc406Sopenharmony_ci return status; 1047141cc406Sopenharmony_ci } 1048141cc406Sopenharmony_ci 1049141cc406Sopenharmony_ci /* good device, add it to list */ 1050141cc406Sopenharmony_ci dev->next = devices_head; 1051141cc406Sopenharmony_ci devices_head = dev; 1052141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1053141cc406Sopenharmony_ci} 1054141cc406Sopenharmony_ci 1055141cc406Sopenharmony_ci/* SANE API ignores return code of this callback */ 1056141cc406Sopenharmony_cistatic SANE_Status 1057141cc406Sopenharmony_cilist_conf_devices(SANEI_Config __sane_unused__ *config, const char *devname, 1058141cc406Sopenharmony_ci void __sane_unused__ *data) 1059141cc406Sopenharmony_ci{ 1060141cc406Sopenharmony_ci return tr_from_devname(devname)->configure_device(devname, list_one_device); 1061141cc406Sopenharmony_ci} 1062141cc406Sopenharmony_ci 1063141cc406Sopenharmony_ciSANE_Status 1064141cc406Sopenharmony_cisane_init(SANE_Int *version_code, SANE_Auth_Callback cb) 1065141cc406Sopenharmony_ci{ 1066141cc406Sopenharmony_ci DBG_INIT(); 1067141cc406Sopenharmony_ci DBG(2, "sane_init: Xerox backend (build %d), version %s null, authorize %s null\n", BACKEND_BUILD, 1068141cc406Sopenharmony_ci (version_code) ? "!=" : "==", (cb) ? "!=" : "=="); 1069141cc406Sopenharmony_ci 1070141cc406Sopenharmony_ci if (version_code) 1071141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BACKEND_BUILD); 1072141cc406Sopenharmony_ci 1073141cc406Sopenharmony_ci sanei_usb_init(); 1074141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1075141cc406Sopenharmony_ci} 1076141cc406Sopenharmony_ci 1077141cc406Sopenharmony_civoid 1078141cc406Sopenharmony_cisane_exit(void) 1079141cc406Sopenharmony_ci{ 1080141cc406Sopenharmony_ci struct device *dev; 1081141cc406Sopenharmony_ci 1082141cc406Sopenharmony_ci for (dev = devices_head; dev; dev = dev->next) 1083141cc406Sopenharmony_ci if (dev->dn != -1) 1084141cc406Sopenharmony_ci sane_close(dev); /* implies flush */ 1085141cc406Sopenharmony_ci 1086141cc406Sopenharmony_ci free_devices(); 1087141cc406Sopenharmony_ci} 1088141cc406Sopenharmony_ci 1089141cc406Sopenharmony_ciSANE_Status 1090141cc406Sopenharmony_cisane_get_devices(const SANE_Device *** device_list, SANE_Bool local) 1091141cc406Sopenharmony_ci{ 1092141cc406Sopenharmony_ci SANEI_Config config; 1093141cc406Sopenharmony_ci struct device *dev; 1094141cc406Sopenharmony_ci int dev_count; 1095141cc406Sopenharmony_ci int i; 1096141cc406Sopenharmony_ci 1097141cc406Sopenharmony_ci DBG(3, "%s: %p, %d\n", __func__, (const void *)device_list, local); 1098141cc406Sopenharmony_ci 1099141cc406Sopenharmony_ci if (devlist) { 1100141cc406Sopenharmony_ci if (device_list) 1101141cc406Sopenharmony_ci *device_list = devlist; 1102141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1103141cc406Sopenharmony_ci } 1104141cc406Sopenharmony_ci 1105141cc406Sopenharmony_ci free_devices(); 1106141cc406Sopenharmony_ci 1107141cc406Sopenharmony_ci config.count = 0; 1108141cc406Sopenharmony_ci config.descriptors = NULL; 1109141cc406Sopenharmony_ci config.values = NULL; 1110141cc406Sopenharmony_ci sanei_configure_attach(XEROX_CONFIG_FILE, &config, list_conf_devices, NULL); 1111141cc406Sopenharmony_ci 1112141cc406Sopenharmony_ci for (dev_count = 0, dev = devices_head; dev; dev = dev->next) 1113141cc406Sopenharmony_ci dev_count++; 1114141cc406Sopenharmony_ci 1115141cc406Sopenharmony_ci devlist = malloc((dev_count + 1) * sizeof(*devlist)); 1116141cc406Sopenharmony_ci if (!devlist) { 1117141cc406Sopenharmony_ci DBG(1, "%s: malloc: no memory\n", __func__); 1118141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1119141cc406Sopenharmony_ci } 1120141cc406Sopenharmony_ci 1121141cc406Sopenharmony_ci for (i = 0, dev = devices_head; dev; dev = dev->next) 1122141cc406Sopenharmony_ci devlist[i++] = &dev->sane; 1123141cc406Sopenharmony_ci devlist[i++] = NULL; 1124141cc406Sopenharmony_ci 1125141cc406Sopenharmony_ci if (device_list) 1126141cc406Sopenharmony_ci *device_list = devlist; 1127141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1128141cc406Sopenharmony_ci} 1129141cc406Sopenharmony_ci 1130141cc406Sopenharmony_civoid 1131141cc406Sopenharmony_cisane_close(SANE_Handle h) 1132141cc406Sopenharmony_ci{ 1133141cc406Sopenharmony_ci struct device *dev = h; 1134141cc406Sopenharmony_ci 1135141cc406Sopenharmony_ci if (!dev) 1136141cc406Sopenharmony_ci return; 1137141cc406Sopenharmony_ci 1138141cc406Sopenharmony_ci DBG(3, "%s: %p (%s)\n", __func__, (void *)dev, dev->sane.name); 1139141cc406Sopenharmony_ci dev->io->dev_close(dev); 1140141cc406Sopenharmony_ci} 1141141cc406Sopenharmony_ci 1142141cc406Sopenharmony_ciSANE_Status 1143141cc406Sopenharmony_cisane_open(SANE_String_Const name, SANE_Handle *h) 1144141cc406Sopenharmony_ci{ 1145141cc406Sopenharmony_ci struct device *dev; 1146141cc406Sopenharmony_ci 1147141cc406Sopenharmony_ci DBG(3, "%s: '%s'\n", __func__, name); 1148141cc406Sopenharmony_ci 1149141cc406Sopenharmony_ci if (!devlist) 1150141cc406Sopenharmony_ci sane_get_devices(NULL, SANE_TRUE); 1151141cc406Sopenharmony_ci 1152141cc406Sopenharmony_ci if (!name || !*name) { 1153141cc406Sopenharmony_ci /* special case of empty name: open first available device */ 1154141cc406Sopenharmony_ci for (dev = devices_head; dev; dev = dev->next) { 1155141cc406Sopenharmony_ci if (dev->dn != -1) { 1156141cc406Sopenharmony_ci if (sane_open(dev->sane.name, h) == SANE_STATUS_GOOD) 1157141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1158141cc406Sopenharmony_ci } 1159141cc406Sopenharmony_ci } 1160141cc406Sopenharmony_ci } else { 1161141cc406Sopenharmony_ci for (dev = devices_head; dev; dev = dev->next) { 1162141cc406Sopenharmony_ci if (strcmp(name, dev->sane.name) == 0) { 1163141cc406Sopenharmony_ci *h = dev; 1164141cc406Sopenharmony_ci return dev->io->dev_open(dev); 1165141cc406Sopenharmony_ci } 1166141cc406Sopenharmony_ci } 1167141cc406Sopenharmony_ci } 1168141cc406Sopenharmony_ci 1169141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1170141cc406Sopenharmony_ci} 1171141cc406Sopenharmony_ci 1172141cc406Sopenharmony_ciSANE_Status 1173141cc406Sopenharmony_cisane_get_parameters(SANE_Handle h, SANE_Parameters *para) 1174141cc406Sopenharmony_ci{ 1175141cc406Sopenharmony_ci struct device *dev = h; 1176141cc406Sopenharmony_ci 1177141cc406Sopenharmony_ci DBG(3, "%s: %p, %p\n", __func__, h, (void *)para); 1178141cc406Sopenharmony_ci if (!para) 1179141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1180141cc406Sopenharmony_ci 1181141cc406Sopenharmony_ci *para = dev->para; 1182141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1183141cc406Sopenharmony_ci} 1184141cc406Sopenharmony_ci 1185141cc406Sopenharmony_ci/* check if image data is ready, and wait if not */ 1186141cc406Sopenharmony_ci/* 1: image is acquired, 0: error or non_blocking mode */ 1187141cc406Sopenharmony_cistatic int dev_acquire(struct device *dev) 1188141cc406Sopenharmony_ci{ 1189141cc406Sopenharmony_ci if (!dev_cmd_wait(dev, CMD_READ)) 1190141cc406Sopenharmony_ci return 0; 1191141cc406Sopenharmony_ci 1192141cc406Sopenharmony_ci dev->state = SANE_STATUS_GOOD; 1193141cc406Sopenharmony_ci dev->vertical = dev->res[0x08] << 8 | dev->res[0x09]; 1194141cc406Sopenharmony_ci dev->horizontal = dev->res[0x0a] << 8 | dev->res[0x0b]; 1195141cc406Sopenharmony_ci dev->blocklen = dev->res[4] << 24 | 1196141cc406Sopenharmony_ci dev->res[5] << 16 | 1197141cc406Sopenharmony_ci dev->res[6] << 8 | 1198141cc406Sopenharmony_ci dev->res[7]; 1199141cc406Sopenharmony_ci dev->final_block = (dev->res[3] == MSG_END_BLOCK)? 1 : 0; 1200141cc406Sopenharmony_ci 1201141cc406Sopenharmony_ci dev->pixels_per_line = dev->horizontal; 1202141cc406Sopenharmony_ci dev->bytes_per_line = dev->horizontal; 1203141cc406Sopenharmony_ci 1204141cc406Sopenharmony_ci if (dev->composition == MODE_RGB24) 1205141cc406Sopenharmony_ci dev->bytes_per_line *= 3; 1206141cc406Sopenharmony_ci else if (dev->composition == MODE_LINEART || 1207141cc406Sopenharmony_ci dev->composition == MODE_HALFTONE) 1208141cc406Sopenharmony_ci dev->pixels_per_line *= 8; 1209141cc406Sopenharmony_ci 1210141cc406Sopenharmony_ci DBG(4, "acquiring, size per band v: %d, h: %d, %sblock: %d, slack: %d\n", 1211141cc406Sopenharmony_ci dev->vertical, dev->horizontal, dev->final_block? "last " : "", 1212141cc406Sopenharmony_ci dev->blocklen, dev->blocklen - (dev->vertical * dev->bytes_per_line)); 1213141cc406Sopenharmony_ci 1214141cc406Sopenharmony_ci if (dev->bytes_per_line > DATASIZE) { 1215141cc406Sopenharmony_ci DBG(1, "%s: unsupported line size: %d bytes > %d\n", 1216141cc406Sopenharmony_ci __func__, dev->bytes_per_line, DATASIZE); 1217141cc406Sopenharmony_ci ret_cancel(dev, SANE_STATUS_NO_MEM); 1218141cc406Sopenharmony_ci return 0; 1219141cc406Sopenharmony_ci } 1220141cc406Sopenharmony_ci 1221141cc406Sopenharmony_ci dev->reading = 0; /* need to issue READ_IMAGE */ 1222141cc406Sopenharmony_ci 1223141cc406Sopenharmony_ci dev->dataindex = 0; 1224141cc406Sopenharmony_ci dev->datalen = 0; 1225141cc406Sopenharmony_ci dev->dataoff = 0; 1226141cc406Sopenharmony_ci 1227141cc406Sopenharmony_ci return 1; 1228141cc406Sopenharmony_ci} 1229141cc406Sopenharmony_ci 1230141cc406Sopenharmony_cistatic int fill_slack(struct device *dev, SANE_Byte *buf, int maxlen) 1231141cc406Sopenharmony_ci{ 1232141cc406Sopenharmony_ci const int slack = dev->total_img_size - dev->total_out_size; 1233141cc406Sopenharmony_ci const int havelen = MIN(slack, maxlen); 1234141cc406Sopenharmony_ci int j; 1235141cc406Sopenharmony_ci 1236141cc406Sopenharmony_ci if (havelen <= 0) 1237141cc406Sopenharmony_ci return 0; 1238141cc406Sopenharmony_ci for (j = 0; j < havelen; j++) 1239141cc406Sopenharmony_ci buf[j] = 255; 1240141cc406Sopenharmony_ci return havelen; 1241141cc406Sopenharmony_ci} 1242141cc406Sopenharmony_ci 1243141cc406Sopenharmony_cistatic int copy_plain_trim(struct device *dev, SANE_Byte *buf, int maxlen, int *olenp) 1244141cc406Sopenharmony_ci{ 1245141cc406Sopenharmony_ci int j; 1246141cc406Sopenharmony_ci const int linesize = dev->bytes_per_line; 1247141cc406Sopenharmony_ci int k = dev->dataindex; 1248141cc406Sopenharmony_ci *olenp = 0; 1249141cc406Sopenharmony_ci for (j = 0; j < dev->datalen && *olenp < maxlen; j++, k++) { 1250141cc406Sopenharmony_ci const int x = k % linesize; 1251141cc406Sopenharmony_ci const int y = k / linesize; 1252141cc406Sopenharmony_ci if (y >= dev->vertical) 1253141cc406Sopenharmony_ci break; /* slack */ 1254141cc406Sopenharmony_ci if (x < dev->para.bytes_per_line && 1255141cc406Sopenharmony_ci (y + dev->y_off) < dev->para.lines) { 1256141cc406Sopenharmony_ci *buf++ = dev->data[(dev->dataoff + j) & DATAMASK]; 1257141cc406Sopenharmony_ci (*olenp)++; 1258141cc406Sopenharmony_ci } 1259141cc406Sopenharmony_ci } 1260141cc406Sopenharmony_ci dev->dataindex = k; 1261141cc406Sopenharmony_ci return j; 1262141cc406Sopenharmony_ci} 1263141cc406Sopenharmony_ci 1264141cc406Sopenharmony_ci/* return: how much data could be freed from cyclic buffer */ 1265141cc406Sopenharmony_ci/* convert from RRGGBB to RGBRGB */ 1266141cc406Sopenharmony_cistatic int copy_mix_bands_trim(struct device *dev, SANE_Byte *buf, int maxlen, int *olenp) 1267141cc406Sopenharmony_ci{ 1268141cc406Sopenharmony_ci int j; 1269141cc406Sopenharmony_ci 1270141cc406Sopenharmony_ci const int linesize = dev->bytes_per_line; /* caching real line size */ 1271141cc406Sopenharmony_ci 1272141cc406Sopenharmony_ci /* line number of the head of input buffer, 1273141cc406Sopenharmony_ci * input buffer is always aligned to whole line */ 1274141cc406Sopenharmony_ci const int y_off = dev->dataindex / linesize; 1275141cc406Sopenharmony_ci 1276141cc406Sopenharmony_ci int k = dev->dataindex; /* caching current index of input buffer */ 1277141cc406Sopenharmony_ci 1278141cc406Sopenharmony_ci /* can only copy as much as full lines we have */ 1279141cc406Sopenharmony_ci int havelen = dev->datalen / linesize * linesize - k % linesize; 1280141cc406Sopenharmony_ci 1281141cc406Sopenharmony_ci const int bands = 3; 1282141cc406Sopenharmony_ci *olenp = 0; 1283141cc406Sopenharmony_ci 1284141cc406Sopenharmony_ci /* while we have data && they can receive */ 1285141cc406Sopenharmony_ci for (j = 0; j < havelen && *olenp < maxlen; j++, k++) { 1286141cc406Sopenharmony_ci const int band = (k % bands) * dev->horizontal; 1287141cc406Sopenharmony_ci const int x = k % linesize / bands; 1288141cc406Sopenharmony_ci const int y = k / linesize - y_off; /* y relative to buffer head */ 1289141cc406Sopenharmony_ci const int y_rly = y + y_off + dev->y_off; /* global y */ 1290141cc406Sopenharmony_ci 1291141cc406Sopenharmony_ci if (x < dev->para.pixels_per_line && 1292141cc406Sopenharmony_ci y_rly < dev->para.lines) { 1293141cc406Sopenharmony_ci *buf++ = dev->data[(dev->dataoff + band + x + y * linesize) & DATAMASK]; 1294141cc406Sopenharmony_ci (*olenp)++; 1295141cc406Sopenharmony_ci } 1296141cc406Sopenharmony_ci } 1297141cc406Sopenharmony_ci dev->dataindex = k; 1298141cc406Sopenharmony_ci 1299141cc406Sopenharmony_ci /* how much full lines are finished */ 1300141cc406Sopenharmony_ci return (k / linesize - y_off) * linesize; 1301141cc406Sopenharmony_ci} 1302141cc406Sopenharmony_ci 1303141cc406Sopenharmony_ciSANE_Status 1304141cc406Sopenharmony_cisane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) 1305141cc406Sopenharmony_ci{ 1306141cc406Sopenharmony_ci SANE_Status status; 1307141cc406Sopenharmony_ci struct device *dev = h; 1308141cc406Sopenharmony_ci 1309141cc406Sopenharmony_ci DBG(3, "%s: %p, %p, %d, %p\n", __func__, h, (void *) buf, maxlen, (void *) lenp); 1310141cc406Sopenharmony_ci 1311141cc406Sopenharmony_ci if (lenp) 1312141cc406Sopenharmony_ci *lenp = 0; 1313141cc406Sopenharmony_ci if (!dev) 1314141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1315141cc406Sopenharmony_ci 1316141cc406Sopenharmony_ci if (!dev->scanning) 1317141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1318141cc406Sopenharmony_ci 1319141cc406Sopenharmony_ci /* if there is no data to read or output from buffer */ 1320141cc406Sopenharmony_ci if (!dev->blocklen && dev->datalen <= PADDING_SIZE) { 1321141cc406Sopenharmony_ci 1322141cc406Sopenharmony_ci /* copying uncompressed data */ 1323141cc406Sopenharmony_ci if (dev->composition == MODE_RGB24 && 1324141cc406Sopenharmony_ci isJPEGEnabled(dev) && 1325141cc406Sopenharmony_ci dev->decDataSize > 0) { 1326141cc406Sopenharmony_ci int diff = dev->total_img_size - dev->total_out_size; 1327141cc406Sopenharmony_ci int bufLen = (diff < maxlen) ? diff : maxlen; 1328141cc406Sopenharmony_ci if (diff && 1329141cc406Sopenharmony_ci copy_decompress_data(dev, buf, bufLen, lenp)) { 1330141cc406Sopenharmony_ci if (lenp) 1331141cc406Sopenharmony_ci dev->total_out_size += *lenp; 1332141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1333141cc406Sopenharmony_ci } 1334141cc406Sopenharmony_ci } 1335141cc406Sopenharmony_ci 1336141cc406Sopenharmony_ci /* and we don't need to acquire next block */ 1337141cc406Sopenharmony_ci if (dev->final_block) { 1338141cc406Sopenharmony_ci int slack = dev->total_img_size - dev->total_out_size; 1339141cc406Sopenharmony_ci 1340141cc406Sopenharmony_ci /* but we may need to fill slack */ 1341141cc406Sopenharmony_ci if (buf && lenp && slack > 0) { 1342141cc406Sopenharmony_ci *lenp = fill_slack(dev, buf, maxlen); 1343141cc406Sopenharmony_ci dev->total_out_size += *lenp; 1344141cc406Sopenharmony_ci DBG(9, "<> slack: %d, filled: %d, maxlen %d\n", 1345141cc406Sopenharmony_ci slack, *lenp, maxlen); 1346141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1347141cc406Sopenharmony_ci } else if (slack < 0) { 1348141cc406Sopenharmony_ci /* this will never happen */ 1349141cc406Sopenharmony_ci DBG(1, "image overflow %d bytes\n", dev->total_img_size - dev->total_out_size); 1350141cc406Sopenharmony_ci } 1351141cc406Sopenharmony_ci if (isJPEGEnabled(dev) && 1352141cc406Sopenharmony_ci dev->composition == MODE_RGB24) { 1353141cc406Sopenharmony_ci remove(encTmpFileName); 1354141cc406Sopenharmony_ci } 1355141cc406Sopenharmony_ci /* that's all */ 1356141cc406Sopenharmony_ci dev_stop(dev); 1357141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1358141cc406Sopenharmony_ci } 1359141cc406Sopenharmony_ci 1360141cc406Sopenharmony_ci /* queue next image block */ 1361141cc406Sopenharmony_ci if (!dev_acquire(dev)) 1362141cc406Sopenharmony_ci return dev->state; 1363141cc406Sopenharmony_ci } 1364141cc406Sopenharmony_ci 1365141cc406Sopenharmony_ci if (!dev->reading) { 1366141cc406Sopenharmony_ci if (cancelled(dev)) 1367141cc406Sopenharmony_ci return dev->state; 1368141cc406Sopenharmony_ci DBG(5, "READ_IMAGE\n"); 1369141cc406Sopenharmony_ci if (!dev_cmd(dev, CMD_READ_IMAGE)) 1370141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1371141cc406Sopenharmony_ci dev->reading++; 1372141cc406Sopenharmony_ci dev->ulines += dev->vertical; 1373141cc406Sopenharmony_ci dev->y_off = dev->ulines - dev->vertical; 1374141cc406Sopenharmony_ci dev->total_data_size += dev->blocklen; 1375141cc406Sopenharmony_ci dev->blocks++; 1376141cc406Sopenharmony_ci } 1377141cc406Sopenharmony_ci 1378141cc406Sopenharmony_ci do { 1379141cc406Sopenharmony_ci size_t datalen; 1380141cc406Sopenharmony_ci int clrlen; /* cleared lines len */ 1381141cc406Sopenharmony_ci int olen; /* output len */ 1382141cc406Sopenharmony_ci 1383141cc406Sopenharmony_ci /* read as much data into the buffer */ 1384141cc406Sopenharmony_ci datalen = DATAROOM(dev) & USB_BLOCK_MASK; 1385141cc406Sopenharmony_ci while (datalen && dev->blocklen) { 1386141cc406Sopenharmony_ci SANE_Byte *rbuf = dev->data + DATATAIL(dev); 1387141cc406Sopenharmony_ci 1388141cc406Sopenharmony_ci DBG(9, "<> request len: %lu, [%d, %d; %d]\n", 1389141cc406Sopenharmony_ci (u_long)datalen, dev->dataoff, DATATAIL(dev), dev->datalen); 1390141cc406Sopenharmony_ci if ((status = dev->io->dev_request(dev, NULL, 0, rbuf, &datalen)) != 1391141cc406Sopenharmony_ci SANE_STATUS_GOOD) 1392141cc406Sopenharmony_ci return status; 1393141cc406Sopenharmony_ci dev->datalen += datalen; 1394141cc406Sopenharmony_ci dev->blocklen -= datalen; 1395141cc406Sopenharmony_ci DBG(9, "<> got %lu, [%d, %d; %d]\n", 1396141cc406Sopenharmony_ci (u_long)datalen, dev->dataoff, DATATAIL(dev), dev->datalen); 1397141cc406Sopenharmony_ci if (dev->blocklen < 0) 1398141cc406Sopenharmony_ci return ret_cancel(dev, SANE_STATUS_IO_ERROR); 1399141cc406Sopenharmony_ci 1400141cc406Sopenharmony_ci datalen = DATAROOM(dev) & USB_BLOCK_MASK; 1401141cc406Sopenharmony_ci } 1402141cc406Sopenharmony_ci 1403141cc406Sopenharmony_ci if (buf && lenp) { /* read mode */ 1404141cc406Sopenharmony_ci /* copy will do minimal of valid data */ 1405141cc406Sopenharmony_ci if (dev->para.format == SANE_FRAME_RGB && dev->line_order) { 1406141cc406Sopenharmony_ci if (isJPEGEnabled(dev)) { 1407141cc406Sopenharmony_ci clrlen = dump_to_tmp_file(dev); 1408141cc406Sopenharmony_ci /* decompress after reading entire block data*/ 1409141cc406Sopenharmony_ci if (0 == dev->blocklen) { 1410141cc406Sopenharmony_ci decompress_tempfile(dev); 1411141cc406Sopenharmony_ci } 1412141cc406Sopenharmony_ci copy_decompress_data(dev, buf, maxlen, &olen); 1413141cc406Sopenharmony_ci } else { 1414141cc406Sopenharmony_ci clrlen = copy_mix_bands_trim(dev, buf, maxlen, &olen); 1415141cc406Sopenharmony_ci } 1416141cc406Sopenharmony_ci } else 1417141cc406Sopenharmony_ci clrlen = copy_plain_trim(dev, buf, maxlen, &olen); 1418141cc406Sopenharmony_ci 1419141cc406Sopenharmony_ci dev->datalen -= clrlen; 1420141cc406Sopenharmony_ci dev->dataoff = (dev->dataoff + clrlen) & DATAMASK; 1421141cc406Sopenharmony_ci buf += olen; 1422141cc406Sopenharmony_ci maxlen -= olen; 1423141cc406Sopenharmony_ci *lenp += olen; 1424141cc406Sopenharmony_ci dev->total_out_size += olen; 1425141cc406Sopenharmony_ci 1426141cc406Sopenharmony_ci DBG(9, "<> olen: %d, clrlen: %d, blocklen: %d/%d, maxlen %d (%d %d %d)\n", 1427141cc406Sopenharmony_ci olen, clrlen, dev->blocklen, dev->datalen, maxlen, 1428141cc406Sopenharmony_ci dev->dataindex / dev->bytes_per_line + dev->y_off, 1429141cc406Sopenharmony_ci dev->y_off, dev->para.lines); 1430141cc406Sopenharmony_ci 1431141cc406Sopenharmony_ci /* slack beyond last line */ 1432141cc406Sopenharmony_ci if (dev->dataindex / dev->bytes_per_line + dev->y_off >= dev->para.lines) { 1433141cc406Sopenharmony_ci dev->datalen = 0; 1434141cc406Sopenharmony_ci dev->dataoff = 0; 1435141cc406Sopenharmony_ci } 1436141cc406Sopenharmony_ci 1437141cc406Sopenharmony_ci if (!clrlen || maxlen <= 0) 1438141cc406Sopenharmony_ci break; 1439141cc406Sopenharmony_ci } else { /* flush mode */ 1440141cc406Sopenharmony_ci dev->datalen = 0; 1441141cc406Sopenharmony_ci dev->dataoff = 0; 1442141cc406Sopenharmony_ci } 1443141cc406Sopenharmony_ci 1444141cc406Sopenharmony_ci } while (dev->blocklen); 1445141cc406Sopenharmony_ci 1446141cc406Sopenharmony_ci if (lenp) 1447141cc406Sopenharmony_ci DBG(9, " ==> %d\n", *lenp); 1448141cc406Sopenharmony_ci 1449141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1450141cc406Sopenharmony_ci} 1451141cc406Sopenharmony_ci 1452141cc406Sopenharmony_ciSANE_Status 1453141cc406Sopenharmony_cisane_start(SANE_Handle h) 1454141cc406Sopenharmony_ci{ 1455141cc406Sopenharmony_ci struct device *dev = h; 1456141cc406Sopenharmony_ci 1457141cc406Sopenharmony_ci DBG(3, "%s: %p\n", __func__, h); 1458141cc406Sopenharmony_ci 1459141cc406Sopenharmony_ci dev->cancel = 0; 1460141cc406Sopenharmony_ci dev->scanning = 0; 1461141cc406Sopenharmony_ci dev->total_img_size = 0; 1462141cc406Sopenharmony_ci dev->total_out_size = 0; 1463141cc406Sopenharmony_ci dev->total_data_size = 0; 1464141cc406Sopenharmony_ci dev->blocks = 0; 1465141cc406Sopenharmony_ci 1466141cc406Sopenharmony_ci if (!dev->reserved) { 1467141cc406Sopenharmony_ci if (!dev_cmd_wait(dev, CMD_RESERVE_UNIT)) 1468141cc406Sopenharmony_ci return dev->state; 1469141cc406Sopenharmony_ci dev->reserved++; 1470141cc406Sopenharmony_ci } 1471141cc406Sopenharmony_ci 1472141cc406Sopenharmony_ci if (!dev_set_window(dev) || 1473141cc406Sopenharmony_ci (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY)) 1474141cc406Sopenharmony_ci return dev_stop(dev); 1475141cc406Sopenharmony_ci 1476141cc406Sopenharmony_ci if (!dev_cmd_wait(dev, CMD_OBJECT_POSITION)) 1477141cc406Sopenharmony_ci return dev_stop(dev); 1478141cc406Sopenharmony_ci 1479141cc406Sopenharmony_ci if (!dev_cmd(dev, CMD_READ) || 1480141cc406Sopenharmony_ci (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY)) 1481141cc406Sopenharmony_ci return dev_stop(dev); 1482141cc406Sopenharmony_ci 1483141cc406Sopenharmony_ci dev->scanning = 1; 1484141cc406Sopenharmony_ci dev->final_block = 0; 1485141cc406Sopenharmony_ci dev->blocklen = 0; 1486141cc406Sopenharmony_ci dev->pixels_per_line = 0; 1487141cc406Sopenharmony_ci dev->bytes_per_line = 0; 1488141cc406Sopenharmony_ci dev->ulines = 0; 1489141cc406Sopenharmony_ci 1490141cc406Sopenharmony_ci set_parameters(dev); 1491141cc406Sopenharmony_ci 1492141cc406Sopenharmony_ci if (!dev->data && !(dev->data = malloc(DATASIZE))) 1493141cc406Sopenharmony_ci return ret_cancel(dev, SANE_STATUS_NO_MEM); 1494141cc406Sopenharmony_ci 1495141cc406Sopenharmony_ci /* this is for jpeg mode only */ 1496141cc406Sopenharmony_ci if (!dev->decData && !(dev->decData = malloc(POST_DATASIZE))) 1497141cc406Sopenharmony_ci return ret_cancel(dev, SANE_STATUS_NO_MEM); 1498141cc406Sopenharmony_ci 1499141cc406Sopenharmony_ci if (!dev_acquire(dev)) 1500141cc406Sopenharmony_ci return dev->state; 1501141cc406Sopenharmony_ci 1502141cc406Sopenharmony_ci /* make sure to have dev->para <= of real size */ 1503141cc406Sopenharmony_ci if (dev->para.pixels_per_line > dev->pixels_per_line) { 1504141cc406Sopenharmony_ci dev->para.pixels_per_line = dev->pixels_per_line; 1505141cc406Sopenharmony_ci dev->para.bytes_per_line = dev->pixels_per_line; 1506141cc406Sopenharmony_ci } 1507141cc406Sopenharmony_ci 1508141cc406Sopenharmony_ci if (dev->composition == MODE_RGB24) 1509141cc406Sopenharmony_ci dev->para.bytes_per_line = dev->para.pixels_per_line * 3; 1510141cc406Sopenharmony_ci else if (dev->composition == MODE_LINEART || 1511141cc406Sopenharmony_ci dev->composition == MODE_HALFTONE) { 1512141cc406Sopenharmony_ci dev->para.bytes_per_line = (dev->para.pixels_per_line + 7) / 8; 1513141cc406Sopenharmony_ci dev->para.pixels_per_line = dev->para.bytes_per_line * 8; 1514141cc406Sopenharmony_ci } else { 1515141cc406Sopenharmony_ci dev->para.bytes_per_line = dev->para.pixels_per_line; 1516141cc406Sopenharmony_ci } 1517141cc406Sopenharmony_ci 1518141cc406Sopenharmony_ci dev->total_img_size = dev->para.bytes_per_line * dev->para.lines; 1519141cc406Sopenharmony_ci 1520141cc406Sopenharmony_ci if (isJPEGEnabled(dev) && 1521141cc406Sopenharmony_ci dev->composition == MODE_RGB24) { 1522141cc406Sopenharmony_ci int fd; 1523141cc406Sopenharmony_ci remove(encTmpFileName); 1524141cc406Sopenharmony_ci 1525141cc406Sopenharmony_ci /* Precreate temporary file in exclusive mode. */ 1526141cc406Sopenharmony_ci fd = open(encTmpFileName, O_CREAT|O_EXCL, 0600); 1527141cc406Sopenharmony_ci if (fd == -1) { 1528141cc406Sopenharmony_ci DBG(3, "%s: %p, can't create temporary file %s: %s\n", __func__, 1529141cc406Sopenharmony_ci (void *)dev, encTmpFileName, strerror(errno)); 1530141cc406Sopenharmony_ci return ret_cancel(dev, SANE_STATUS_ACCESS_DENIED); 1531141cc406Sopenharmony_ci } 1532141cc406Sopenharmony_ci close(fd); 1533141cc406Sopenharmony_ci } 1534141cc406Sopenharmony_ci dev->currentDecDataIndex = 0; 1535141cc406Sopenharmony_ci 1536141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1537141cc406Sopenharmony_ci} 1538141cc406Sopenharmony_ci 1539141cc406Sopenharmony_ciSANE_Status sane_set_io_mode(SANE_Handle h, SANE_Bool non_blocking) 1540141cc406Sopenharmony_ci{ 1541141cc406Sopenharmony_ci struct device *dev = h; 1542141cc406Sopenharmony_ci 1543141cc406Sopenharmony_ci DBG(3, "%s: %p, %d\n", __func__, h, non_blocking); 1544141cc406Sopenharmony_ci 1545141cc406Sopenharmony_ci if (non_blocking) 1546141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1547141cc406Sopenharmony_ci 1548141cc406Sopenharmony_ci dev->non_blocking = non_blocking; 1549141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1550141cc406Sopenharmony_ci} 1551141cc406Sopenharmony_ci 1552141cc406Sopenharmony_ciSANE_Status sane_get_select_fd(SANE_Handle h, SANE_Int *fdp) 1553141cc406Sopenharmony_ci{ 1554141cc406Sopenharmony_ci DBG(3, "%s: %p, %p\n", __func__, h, (void *)fdp); 1555141cc406Sopenharmony_ci /* supporting of this will require thread creation */ 1556141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1557141cc406Sopenharmony_ci} 1558141cc406Sopenharmony_ci 1559141cc406Sopenharmony_civoid sane_cancel(SANE_Handle h) 1560141cc406Sopenharmony_ci{ 1561141cc406Sopenharmony_ci struct device *dev = h; 1562141cc406Sopenharmony_ci 1563141cc406Sopenharmony_ci DBG(3, "%s: %p\n", __func__, h); 1564141cc406Sopenharmony_ci dev->cancel = 1; 1565141cc406Sopenharmony_ci} 1566141cc406Sopenharmony_ci 1567141cc406Sopenharmony_ci/* xerox_mfp.c */ 1568