1141cc406Sopenharmony_ci/* 2141cc406Sopenharmony_ci * magicolor.c - SANE library for Magicolor scanners. 3141cc406Sopenharmony_ci * 4141cc406Sopenharmony_ci * (C) 2010 Reinhold Kainhofer <reinhold@kainhofer.com> 5141cc406Sopenharmony_ci * 6141cc406Sopenharmony_ci * Based on the epson2 sane backend: 7141cc406Sopenharmony_ci * Based on Kazuhiro Sasayama previous 8141cc406Sopenharmony_ci * Work on epson.[ch] file from the SANE package. 9141cc406Sopenharmony_ci * Please see those files for additional copyrights. 10141cc406Sopenharmony_ci * Copyright (C) 2006-10 Tower Technologies 11141cc406Sopenharmony_ci * Author: Alessandro Zummo <a.zummo@towertech.it> 12141cc406Sopenharmony_ci * 13141cc406Sopenharmony_ci * This file is part of the SANE package. 14141cc406Sopenharmony_ci * 15141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or 16141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as 17141cc406Sopenharmony_ci * published by the Free Software Foundation, version 2. 18141cc406Sopenharmony_ci */ 19141cc406Sopenharmony_ci 20141cc406Sopenharmony_ci#define MAGICOLOR_VERSION 0 21141cc406Sopenharmony_ci#define MAGICOLOR_REVISION 0 22141cc406Sopenharmony_ci#define MAGICOLOR_BUILD 1 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci/* debugging levels: 25141cc406Sopenharmony_ci * 26141cc406Sopenharmony_ci * 127 mc_recv buffer 27141cc406Sopenharmony_ci * 125 mc_send buffer 28141cc406Sopenharmony_ci * 35 fine-grained status and progress 29141cc406Sopenharmony_ci * 30 sane_read 30141cc406Sopenharmony_ci * 25 setvalue, getvalue, control_option 31141cc406Sopenharmony_ci * 20 low-level (I/O) mc_* functions 32141cc406Sopenharmony_ci * 15 mid-level mc_* functions 33141cc406Sopenharmony_ci * 10 high-level cmd_* functions 34141cc406Sopenharmony_ci * 7 open/close/attach 35141cc406Sopenharmony_ci * 6 print_params 36141cc406Sopenharmony_ci * 5 basic functions 37141cc406Sopenharmony_ci * 3 status info and progress 38141cc406Sopenharmony_ci * 2 scanner info and capabilities 39141cc406Sopenharmony_ci * 1 errors & warnings 40141cc406Sopenharmony_ci */ 41141cc406Sopenharmony_ci 42141cc406Sopenharmony_ci#include "sane/config.h" 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_ci#include <limits.h> 45141cc406Sopenharmony_ci#include <stdio.h> 46141cc406Sopenharmony_ci#include <string.h> 47141cc406Sopenharmony_ci#include <stdlib.h> 48141cc406Sopenharmony_ci#include <ctype.h> 49141cc406Sopenharmony_ci#include <fcntl.h> 50141cc406Sopenharmony_ci#include <unistd.h> 51141cc406Sopenharmony_ci#include <errno.h> 52141cc406Sopenharmony_ci#include <sys/time.h> 53141cc406Sopenharmony_ci#include <math.h> 54141cc406Sopenharmony_ci#include <poll.h> 55141cc406Sopenharmony_ci#include <sys/types.h> 56141cc406Sopenharmony_ci#ifdef HAVE_SYS_SOCKET_H 57141cc406Sopenharmony_ci#include <sys/socket.h> 58141cc406Sopenharmony_ci#endif 59141cc406Sopenharmony_ci 60141cc406Sopenharmony_ci 61141cc406Sopenharmony_ci#if HAVE_LIBSNMP 62141cc406Sopenharmony_ci#include <net-snmp/net-snmp-config.h> 63141cc406Sopenharmony_ci#include <net-snmp/net-snmp-includes.h> 64141cc406Sopenharmony_ci#include <net-snmp/library/snmp_transport.h> 65141cc406Sopenharmony_ci#include <arpa/inet.h> 66141cc406Sopenharmony_ci#endif 67141cc406Sopenharmony_ci 68141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 69141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 70141cc406Sopenharmony_ci#include "../include/sane/sanei_tcp.h" 71141cc406Sopenharmony_ci#include "../include/sane/sanei_udp.h" 72141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 73141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ci#include "magicolor.h" 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ci 78141cc406Sopenharmony_ci#define min(x,y) (((x)<(y))?(x):(y)) 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci 81141cc406Sopenharmony_ci 82141cc406Sopenharmony_ci/**************************************************************************** 83141cc406Sopenharmony_ci * Devices supported by this backend 84141cc406Sopenharmony_ci ****************************************************************************/ 85141cc406Sopenharmony_ci 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_ci 88141cc406Sopenharmony_ci/* Scanner command type 89141cc406Sopenharmony_ci * | Start scan 90141cc406Sopenharmony_ci * | | Poll for error 91141cc406Sopenharmony_ci * | | | Stop scan? 92141cc406Sopenharmony_ci * | | | | Query image parameters 93141cc406Sopenharmony_ci * | | | | | set scan parameters 94141cc406Sopenharmony_ci * | | | | | | Get status? 95141cc406Sopenharmony_ci * | | | | | | | Read scanned data 96141cc406Sopenharmony_ci * | | | | | | | | Unknown 97141cc406Sopenharmony_ci * | | | | | | | | | Unknown 98141cc406Sopenharmony_ci * | | | | | | | | | | Net wrapper command type 99141cc406Sopenharmony_ci * | | | | | | | | | | | Net Welcome 100141cc406Sopenharmony_ci * | | | | | | | | | | | | Net Lock 101141cc406Sopenharmony_ci * | | | | | | | | | | | | | Net Lock ACK 102141cc406Sopenharmony_ci * | | | | | | | | | | | | | | Net Unlock 103141cc406Sopenharmony_ci * | | | | | | | | | | | | | | | 104141cc406Sopenharmony_ci*/ 105141cc406Sopenharmony_cistatic struct MagicolorCmd magicolor_cmd[] = { 106141cc406Sopenharmony_ci {"mc1690mf", CMD, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x12, NET, 0x00, 0x01, 0x02, 0x03}, 107141cc406Sopenharmony_ci {"mc4690mf", CMD, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x12, NET, 0x00, 0x01, 0x02, 0x03}, 108141cc406Sopenharmony_ci}; 109141cc406Sopenharmony_ci 110141cc406Sopenharmony_cistatic SANE_Int magicolor_default_resolutions[] = {150, 300, 600}; 111141cc406Sopenharmony_cistatic SANE_Int magicolor_default_depths[] = {1,8}; 112141cc406Sopenharmony_ci 113141cc406Sopenharmony_cistatic struct MagicolorCap magicolor_cap[] = { 114141cc406Sopenharmony_ci 115141cc406Sopenharmony_ci /* KONICA MINOLTA magicolor 1690MF, USB ID 0x123b:2089 */ 116141cc406Sopenharmony_ci { 117141cc406Sopenharmony_ci 0x2089, "mc1690mf", "KONICA MINOLTA magicolor 1690MF", ".1.3.6.1.4.1.18334.1.1.1.1.1.23.1.1", 118141cc406Sopenharmony_ci -1, 0x85, 119141cc406Sopenharmony_ci 600, {150, 600, 0}, magicolor_default_resolutions, 3, /* 600 dpi max, 3 resolutions */ 120141cc406Sopenharmony_ci 8, magicolor_default_depths, /* color depth 8 default, 1 and 8 possible */ 121141cc406Sopenharmony_ci {1, 9, 0}, /* brightness ranges (TODO!) */ 122141cc406Sopenharmony_ci {0, SANE_FIX(0x13f8 * MM_PER_INCH / 600), 0}, {0, SANE_FIX(0x1b9c * MM_PER_INCH / 600), 0}, /* FBF x/y ranges (TODO!) */ 123141cc406Sopenharmony_ci SANE_TRUE, SANE_FALSE, /* non-duplex ADF, x/y ranges (TODO!) */ 124141cc406Sopenharmony_ci {0, SANE_FIX(0x1390 * MM_PER_INCH / 600), 0}, {0, SANE_FIX(0x20dc * MM_PER_INCH / 600), 0}, 125141cc406Sopenharmony_ci }, 126141cc406Sopenharmony_ci 127141cc406Sopenharmony_ci /* KONICA MINOLTA magicolor 4690MF, USB ID 0x132b:2079 */ 128141cc406Sopenharmony_ci { 129141cc406Sopenharmony_ci 0x2079, "mc4690mf", "KONICA MINOLTA magicolor 4690MF", 130141cc406Sopenharmony_ci "FIXME", /* FIXME: fill in the correct OID! */ 131141cc406Sopenharmony_ci 0x03, 0x85, 132141cc406Sopenharmony_ci 600, {150, 600, 0}, magicolor_default_resolutions, 3, /* 600 dpi max, 3 resolutions */ 133141cc406Sopenharmony_ci 8, magicolor_default_depths, /* color depth 8 default, 1 and 8 possible */ 134141cc406Sopenharmony_ci {1, 9, 0}, /* brightness ranges (TODO!) */ 135141cc406Sopenharmony_ci {0, SANE_FIX(0x13f8 * MM_PER_INCH / 600), 0}, {0, SANE_FIX(0x1b9c * MM_PER_INCH / 600), 0}, /* FBF x/y ranges (TODO!) */ 136141cc406Sopenharmony_ci SANE_TRUE, SANE_TRUE, /* duplex ADF, x/y ranges (TODO!) */ 137141cc406Sopenharmony_ci {0, SANE_FIX(0x1390 * MM_PER_INCH / 600), 0}, {0, SANE_FIX(0x20dc * MM_PER_INCH / 600), 0}, 138141cc406Sopenharmony_ci }, 139141cc406Sopenharmony_ci 140141cc406Sopenharmony_ci}; 141141cc406Sopenharmony_ci 142141cc406Sopenharmony_cistatic int MC_SNMP_Timeout = 2500; 143141cc406Sopenharmony_cistatic int MC_Scan_Data_Timeout = 15000; 144141cc406Sopenharmony_cistatic int MC_Request_Timeout = 5000; 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_ci 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_ci/**************************************************************************** 149141cc406Sopenharmony_ci * General configuration parameter definitions 150141cc406Sopenharmony_ci ****************************************************************************/ 151141cc406Sopenharmony_ci 152141cc406Sopenharmony_ci 153141cc406Sopenharmony_ci/* 154141cc406Sopenharmony_ci * Definition of the mode_param struct, that is used to 155141cc406Sopenharmony_ci * specify the valid parameters for the different scan modes. 156141cc406Sopenharmony_ci * 157141cc406Sopenharmony_ci * The depth variable gets updated when the bit depth is modified. 158141cc406Sopenharmony_ci */ 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_cistatic struct mode_param mode_params[] = { 161141cc406Sopenharmony_ci {0x00, 1, 1}, /* Lineart, 1 color, 1 bit */ 162141cc406Sopenharmony_ci {0x02, 1, 24}, /* Grayscale, 1 color, 24 bit */ 163141cc406Sopenharmony_ci {0x03, 3, 24} /* Color, 3 colors, 24 bit */ 164141cc406Sopenharmony_ci}; 165141cc406Sopenharmony_ci 166141cc406Sopenharmony_cistatic SANE_String_Const mode_list[] = { 167141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_LINEART, 168141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_GRAY, 169141cc406Sopenharmony_ci SANE_VALUE_SCAN_MODE_COLOR, 170141cc406Sopenharmony_ci NULL 171141cc406Sopenharmony_ci}; 172141cc406Sopenharmony_ci 173141cc406Sopenharmony_cistatic const SANE_String_Const adf_mode_list[] = { 174141cc406Sopenharmony_ci SANE_I18N("Simplex"), 175141cc406Sopenharmony_ci SANE_I18N("Duplex"), 176141cc406Sopenharmony_ci NULL 177141cc406Sopenharmony_ci}; 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci/* Define the different scan sources */ 180141cc406Sopenharmony_ci 181141cc406Sopenharmony_ci#define FBF_STR SANE_I18N("Flatbed") 182141cc406Sopenharmony_ci#define ADF_STR SANE_I18N("Automatic Document Feeder") 183141cc406Sopenharmony_ci 184141cc406Sopenharmony_ci/* 185141cc406Sopenharmony_ci * source list need one dummy entry (save device settings is crashing). 186141cc406Sopenharmony_ci * NOTE: no const - this list gets created while exploring the capabilities 187141cc406Sopenharmony_ci * of the scanner. 188141cc406Sopenharmony_ci */ 189141cc406Sopenharmony_ci 190141cc406Sopenharmony_cistatic SANE_String_Const source_list[] = { 191141cc406Sopenharmony_ci FBF_STR, 192141cc406Sopenharmony_ci NULL, 193141cc406Sopenharmony_ci NULL, 194141cc406Sopenharmony_ci NULL 195141cc406Sopenharmony_ci}; 196141cc406Sopenharmony_ci 197141cc406Sopenharmony_ci/* Some utility functions */ 198141cc406Sopenharmony_ci 199141cc406Sopenharmony_cistatic size_t 200141cc406Sopenharmony_cimax_string_size(const SANE_String_Const strings[]) 201141cc406Sopenharmony_ci{ 202141cc406Sopenharmony_ci size_t size, max_size = 0; 203141cc406Sopenharmony_ci int i; 204141cc406Sopenharmony_ci 205141cc406Sopenharmony_ci for (i = 0; strings[i]; i++) { 206141cc406Sopenharmony_ci size = strlen(strings[i]) + 1; 207141cc406Sopenharmony_ci if (size > max_size) 208141cc406Sopenharmony_ci max_size = size; 209141cc406Sopenharmony_ci } 210141cc406Sopenharmony_ci return max_size; 211141cc406Sopenharmony_ci} 212141cc406Sopenharmony_ci 213141cc406Sopenharmony_cistatic SANE_Status attach_one_usb(SANE_String_Const devname); 214141cc406Sopenharmony_cistatic SANE_Status attach_one_net(SANE_String_Const devname, unsigned int device); 215141cc406Sopenharmony_ci 216141cc406Sopenharmony_cistatic void 217141cc406Sopenharmony_ciprint_params(const SANE_Parameters params) 218141cc406Sopenharmony_ci{ 219141cc406Sopenharmony_ci DBG(6, "params.format = %d\n", params.format); 220141cc406Sopenharmony_ci DBG(6, "params.last_frame = %d\n", params.last_frame); 221141cc406Sopenharmony_ci DBG(6, "params.bytes_per_line = %d\n", params.bytes_per_line); 222141cc406Sopenharmony_ci DBG(6, "params.pixels_per_line = %d\n", params.pixels_per_line); 223141cc406Sopenharmony_ci DBG(6, "params.lines = %d\n", params.lines); 224141cc406Sopenharmony_ci DBG(6, "params.depth = %d\n", params.depth); 225141cc406Sopenharmony_ci} 226141cc406Sopenharmony_ci 227141cc406Sopenharmony_ci 228141cc406Sopenharmony_ci 229141cc406Sopenharmony_ci/**************************************************************************** 230141cc406Sopenharmony_ci * Low-level Network communication functions 231141cc406Sopenharmony_ci ****************************************************************************/ 232141cc406Sopenharmony_ci 233141cc406Sopenharmony_ci 234141cc406Sopenharmony_ci#define MAGICOLOR_SNMP_SYSDESCR_OID ".1.3.6.1.2.1.1.1.0" 235141cc406Sopenharmony_ci#define MAGICOLOR_SNMP_SYSOBJECT_OID ".1.3.6.1.2.1.1.2.0" 236141cc406Sopenharmony_ci#define MAGICOLOR_SNMP_MAC_OID ".1.3.6.1.2.1.2.2.1.6.1" 237141cc406Sopenharmony_ci#define MAGICOLOR_SNMP_DEVICE_TREE ".1.3.6.1.4.1.18334.1.1.1.1.1" 238141cc406Sopenharmony_ci 239141cc406Sopenharmony_ci 240141cc406Sopenharmony_ci/* We don't have a packet wrapper, which holds packet size etc., so we 241141cc406Sopenharmony_ci don't have to use a *read_raw and a *_read function... */ 242141cc406Sopenharmony_cistatic int 243141cc406Sopenharmony_cisanei_magicolor_net_read(struct Magicolor_Scanner *s, unsigned char *buf, size_t wanted, 244141cc406Sopenharmony_ci SANE_Status * status) 245141cc406Sopenharmony_ci{ 246141cc406Sopenharmony_ci size_t size, read = 0; 247141cc406Sopenharmony_ci struct pollfd fds[1]; 248141cc406Sopenharmony_ci 249141cc406Sopenharmony_ci *status = SANE_STATUS_GOOD; 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_ci /* poll for data-to-be-read (using a 5 seconds timeout) */ 252141cc406Sopenharmony_ci fds[0].fd = s->fd; 253141cc406Sopenharmony_ci fds[0].events = POLLIN; 254141cc406Sopenharmony_ci if (poll (fds, 1, MC_Request_Timeout) <= 0) { 255141cc406Sopenharmony_ci *status = SANE_STATUS_IO_ERROR; 256141cc406Sopenharmony_ci return read; 257141cc406Sopenharmony_ci } 258141cc406Sopenharmony_ci 259141cc406Sopenharmony_ci while (read < wanted) { 260141cc406Sopenharmony_ci size = sanei_tcp_read(s->fd, buf + read, wanted - read); 261141cc406Sopenharmony_ci 262141cc406Sopenharmony_ci if (size == 0) 263141cc406Sopenharmony_ci break; 264141cc406Sopenharmony_ci 265141cc406Sopenharmony_ci read += size; 266141cc406Sopenharmony_ci } 267141cc406Sopenharmony_ci 268141cc406Sopenharmony_ci if (read < wanted) 269141cc406Sopenharmony_ci *status = SANE_STATUS_IO_ERROR; 270141cc406Sopenharmony_ci 271141cc406Sopenharmony_ci return read; 272141cc406Sopenharmony_ci} 273141cc406Sopenharmony_ci 274141cc406Sopenharmony_ci/* We need to optionally pad the buffer with 0x00 to send 64-byte chunks. 275141cc406Sopenharmony_ci On the other hand, the 0x04 commands don't need this, so we need two 276141cc406Sopenharmony_ci functions, one *_write function that pads the buffer and then calls 277141cc406Sopenharmony_ci *_write_raw */ 278141cc406Sopenharmony_cistatic int 279141cc406Sopenharmony_cisanei_magicolor_net_write_raw(struct Magicolor_Scanner *s, 280141cc406Sopenharmony_ci const unsigned char *buf, size_t buf_size, 281141cc406Sopenharmony_ci SANE_Status *status) 282141cc406Sopenharmony_ci{ 283141cc406Sopenharmony_ci sanei_tcp_write(s->fd, buf, buf_size); 284141cc406Sopenharmony_ci /* TODO: Check whether sending failed... */ 285141cc406Sopenharmony_ci 286141cc406Sopenharmony_ci *status = SANE_STATUS_GOOD; 287141cc406Sopenharmony_ci return buf_size; 288141cc406Sopenharmony_ci} 289141cc406Sopenharmony_ci 290141cc406Sopenharmony_cistatic int 291141cc406Sopenharmony_cisanei_magicolor_net_write(struct Magicolor_Scanner *s, 292141cc406Sopenharmony_ci const unsigned char *buf, size_t buf_size, 293141cc406Sopenharmony_ci SANE_Status *status) 294141cc406Sopenharmony_ci{ 295141cc406Sopenharmony_ci size_t len = 64; 296141cc406Sopenharmony_ci unsigned char *new_buf = malloc(len); 297141cc406Sopenharmony_ci if (!new_buf) { 298141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 299141cc406Sopenharmony_ci return 0; 300141cc406Sopenharmony_ci } 301141cc406Sopenharmony_ci memset(new_buf, 0x00, len); 302141cc406Sopenharmony_ci if (buf_size > len) 303141cc406Sopenharmony_ci buf_size = len; 304141cc406Sopenharmony_ci if (buf_size) 305141cc406Sopenharmony_ci memcpy(new_buf, buf, buf_size); 306141cc406Sopenharmony_ci return sanei_magicolor_net_write_raw (s, new_buf, len, status); 307141cc406Sopenharmony_ci} 308141cc406Sopenharmony_ci 309141cc406Sopenharmony_cistatic SANE_Status 310141cc406Sopenharmony_cisanei_magicolor_net_open(struct Magicolor_Scanner *s) 311141cc406Sopenharmony_ci{ 312141cc406Sopenharmony_ci SANE_Status status; 313141cc406Sopenharmony_ci unsigned char buf[5]; 314141cc406Sopenharmony_ci 315141cc406Sopenharmony_ci ssize_t read; 316141cc406Sopenharmony_ci struct timeval tv; 317141cc406Sopenharmony_ci struct MagicolorCmd *cmd = s->hw->cmd; 318141cc406Sopenharmony_ci 319141cc406Sopenharmony_ci tv.tv_sec = 5; 320141cc406Sopenharmony_ci tv.tv_usec = 0; 321141cc406Sopenharmony_ci 322141cc406Sopenharmony_ci setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); 323141cc406Sopenharmony_ci 324141cc406Sopenharmony_ci DBG(1, "%s\n", __func__); 325141cc406Sopenharmony_ci 326141cc406Sopenharmony_ci /* the scanner sends a kind of welcome msg */ 327141cc406Sopenharmony_ci read = sanei_magicolor_net_read(s, buf, 3, &status); 328141cc406Sopenharmony_ci if (read != 3) 329141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 330141cc406Sopenharmony_ci if (buf[0] != cmd->net_wrapper_cmd || buf[1] != cmd->net_welcome) { 331141cc406Sopenharmony_ci DBG (32, "Invalid welcome message received, Expected 0x%02x %02x 00, but got 0x%02x %02x %02x\n", 332141cc406Sopenharmony_ci cmd->net_wrapper_cmd, cmd->net_welcome, buf[0], buf[1], buf[2]); 333141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 334141cc406Sopenharmony_ci } else if (buf[2] != 0x00) { 335141cc406Sopenharmony_ci /* TODO: Handle response "04 00 01", indicating an error! */ 336141cc406Sopenharmony_ci DBG (32, "Welcome message received, busy status %02x\n", buf[2]); 337141cc406Sopenharmony_ci /* TODO: Return a human-readable error message (Unable to connect to scanner, scanner is not ready) */ 338141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 339141cc406Sopenharmony_ci } 340141cc406Sopenharmony_ci 341141cc406Sopenharmony_ci buf[0] = cmd->net_wrapper_cmd; 342141cc406Sopenharmony_ci buf[1] = cmd->net_lock; 343141cc406Sopenharmony_ci buf[2] = 0x00; 344141cc406Sopenharmony_ci /* Copy the device's USB id to bytes 3-4: */ 345141cc406Sopenharmony_ci buf[3] = s->hw->cap->id & 0xff; 346141cc406Sopenharmony_ci buf[4] = (s->hw->cap->id >> 8) & 0xff; 347141cc406Sopenharmony_ci 348141cc406Sopenharmony_ci DBG(32, "Proper welcome message received, locking the scanner...\n"); 349141cc406Sopenharmony_ci sanei_magicolor_net_write_raw(s, buf, 5, &status); 350141cc406Sopenharmony_ci 351141cc406Sopenharmony_ci read = sanei_magicolor_net_read(s, buf, 3, &status); 352141cc406Sopenharmony_ci if (read != 3) 353141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 354141cc406Sopenharmony_ci if (buf[0] != cmd->net_wrapper_cmd || buf[1] != cmd->net_lock_ack || buf[2] != 0x00) { 355141cc406Sopenharmony_ci DBG (32, "Welcome message received, Expected 0x%x %x 00, but got 0x%x %x %x\n", 356141cc406Sopenharmony_ci cmd->net_wrapper_cmd, cmd->net_lock_ack, buf[0], buf[1], buf[2]); 357141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 358141cc406Sopenharmony_ci } 359141cc406Sopenharmony_ci 360141cc406Sopenharmony_ci DBG(32, "scanner locked\n"); 361141cc406Sopenharmony_ci 362141cc406Sopenharmony_ci return status; 363141cc406Sopenharmony_ci} 364141cc406Sopenharmony_ci 365141cc406Sopenharmony_cistatic SANE_Status 366141cc406Sopenharmony_cisanei_magicolor_net_close(struct Magicolor_Scanner *s) 367141cc406Sopenharmony_ci{ 368141cc406Sopenharmony_ci SANE_Status status; 369141cc406Sopenharmony_ci struct MagicolorCmd *cmd = s->hw->cmd; 370141cc406Sopenharmony_ci unsigned char buf[3]; 371141cc406Sopenharmony_ci 372141cc406Sopenharmony_ci DBG(1, "%s\n", __func__); 373141cc406Sopenharmony_ci buf[0] = cmd->net_wrapper_cmd; 374141cc406Sopenharmony_ci buf[1] = cmd->net_unlock; 375141cc406Sopenharmony_ci buf[2] = 0x00; 376141cc406Sopenharmony_ci sanei_magicolor_net_write_raw(s, buf, 3, &status); 377141cc406Sopenharmony_ci return status; 378141cc406Sopenharmony_ci} 379141cc406Sopenharmony_ci 380141cc406Sopenharmony_ci 381141cc406Sopenharmony_ci 382141cc406Sopenharmony_ci/**************************************************************************** 383141cc406Sopenharmony_ci * Low-level USB communication functions 384141cc406Sopenharmony_ci ****************************************************************************/ 385141cc406Sopenharmony_ci 386141cc406Sopenharmony_ci#define SANE_MAGICOLOR_VENDOR_ID (0x132b) 387141cc406Sopenharmony_ci 388141cc406Sopenharmony_ciSANE_Word sanei_magicolor_usb_product_ids[] = { 389141cc406Sopenharmony_ci 0x2089, /* magicolor 1690MF */ 390141cc406Sopenharmony_ci 0x2079, /* magicolor 4690MF */ 391141cc406Sopenharmony_ci 0 /* last entry - this is used for devices that are specified 392141cc406Sopenharmony_ci in the config file as "usb <vendor> <product>" */ 393141cc406Sopenharmony_ci}; 394141cc406Sopenharmony_ci 395141cc406Sopenharmony_cistatic int 396141cc406Sopenharmony_cisanei_magicolor_getNumberOfUSBProductIds (void) 397141cc406Sopenharmony_ci{ 398141cc406Sopenharmony_ci return sizeof (sanei_magicolor_usb_product_ids) / sizeof (SANE_Word); 399141cc406Sopenharmony_ci} 400141cc406Sopenharmony_ci 401141cc406Sopenharmony_ci 402141cc406Sopenharmony_ci 403141cc406Sopenharmony_ci 404141cc406Sopenharmony_ci/**************************************************************************** 405141cc406Sopenharmony_ci * Magicolor low-level communication commands 406141cc406Sopenharmony_ci ****************************************************************************/ 407141cc406Sopenharmony_ci 408141cc406Sopenharmony_cistatic void dump_hex_buffer_dense (int level, const unsigned char *buf, size_t buf_size) 409141cc406Sopenharmony_ci{ 410141cc406Sopenharmony_ci size_t k; 411141cc406Sopenharmony_ci char msg[1024], fmt_buf[1024]; 412141cc406Sopenharmony_ci memset (&msg[0], 0x00, 1024); 413141cc406Sopenharmony_ci memset (&fmt_buf[0], 0x00, 1024); 414141cc406Sopenharmony_ci for (k = 0; k < min(buf_size, 80); k++) { 415141cc406Sopenharmony_ci if (k % 16 == 0) { 416141cc406Sopenharmony_ci if (k>0) { 417141cc406Sopenharmony_ci DBG (level, "%s\n", msg); 418141cc406Sopenharmony_ci memset (&msg[0], 0x00, 1024); 419141cc406Sopenharmony_ci } 420141cc406Sopenharmony_ci sprintf (fmt_buf, " 0x%04lx ", (unsigned long)k); 421141cc406Sopenharmony_ci strcat (msg, fmt_buf); 422141cc406Sopenharmony_ci } 423141cc406Sopenharmony_ci if (k % 8 == 0) { 424141cc406Sopenharmony_ci strcat (msg, " "); 425141cc406Sopenharmony_ci } 426141cc406Sopenharmony_ci sprintf (fmt_buf, " %02x" , buf[k]); 427141cc406Sopenharmony_ci strcat (msg, fmt_buf); 428141cc406Sopenharmony_ci } 429141cc406Sopenharmony_ci if (msg[0] != 0 ) { 430141cc406Sopenharmony_ci DBG (level, "%s\n", msg); 431141cc406Sopenharmony_ci } 432141cc406Sopenharmony_ci} 433141cc406Sopenharmony_ci 434141cc406Sopenharmony_ci/* Create buffers containing the command and arguments. Length of reserved 435141cc406Sopenharmony_ci * buffer is returned. It's the caller's job to free the buffer! */ 436141cc406Sopenharmony_cistatic int mc_create_buffer (Magicolor_Scanner *s, unsigned char cmd_type, unsigned char cmd, 437141cc406Sopenharmony_ci unsigned char **buf, unsigned char* arg1, size_t len1, 438141cc406Sopenharmony_ci SANE_Status *status) 439141cc406Sopenharmony_ci{ 440141cc406Sopenharmony_ci unsigned char* b = NULL; 441141cc406Sopenharmony_ci size_t buf_len = 2+4+len1+4; 442141cc406Sopenharmony_ci NOT_USED (s); 443141cc406Sopenharmony_ci if (len1 <= 0) 444141cc406Sopenharmony_ci buf_len = 6; /* no args, just cmd + final 0x00 00 00 00 */ 445141cc406Sopenharmony_ci *buf = b = malloc (buf_len); 446141cc406Sopenharmony_ci memset (b, 0x00, buf_len); 447141cc406Sopenharmony_ci if (!b) { 448141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 449141cc406Sopenharmony_ci return 0; 450141cc406Sopenharmony_ci } 451141cc406Sopenharmony_ci b[0] = cmd_type; 452141cc406Sopenharmony_ci b[1] = cmd; 453141cc406Sopenharmony_ci if (len1>0) { 454141cc406Sopenharmony_ci b[2] = len1 & 0xff; 455141cc406Sopenharmony_ci b[3] = (len1 >> 8) & 0xff; 456141cc406Sopenharmony_ci b[4] = (len1 >> 16) & 0xff; 457141cc406Sopenharmony_ci b[5] = (len1 >> 24) & 0xff; 458141cc406Sopenharmony_ci if (arg1) 459141cc406Sopenharmony_ci memcpy(b+6, arg1, len1); 460141cc406Sopenharmony_ci } 461141cc406Sopenharmony_ci /* Writing the final 0x00 00 00 00 is not necessary, they are 0x00 already */ 462141cc406Sopenharmony_ci *status = SANE_STATUS_GOOD; 463141cc406Sopenharmony_ci return buf_len; 464141cc406Sopenharmony_ci} 465141cc406Sopenharmony_ci 466141cc406Sopenharmony_cistatic int mc_create_buffer2 (Magicolor_Scanner *s, unsigned char cmd_type, unsigned char cmd, 467141cc406Sopenharmony_ci unsigned char **buf, unsigned char* arg1, size_t len1, 468141cc406Sopenharmony_ci unsigned char* arg2, size_t len2, SANE_Status *status) 469141cc406Sopenharmony_ci{ 470141cc406Sopenharmony_ci unsigned char* b = NULL; 471141cc406Sopenharmony_ci size_t buf_len = 2+4+len1+4+len2+4; 472141cc406Sopenharmony_ci /* If any of the two args has size 0, use the simpler mc_create_buffer */ 473141cc406Sopenharmony_ci if (len1<=0) 474141cc406Sopenharmony_ci return mc_create_buffer (s, cmd_type, cmd, buf, arg2, len2, status); 475141cc406Sopenharmony_ci else if (len2<=0) 476141cc406Sopenharmony_ci return mc_create_buffer (s, cmd_type, cmd, buf, arg1, len1, status); 477141cc406Sopenharmony_ci /* Allocate memory and copy over args and their lengths */ 478141cc406Sopenharmony_ci *buf = b = malloc (buf_len); 479141cc406Sopenharmony_ci if (!b) { 480141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 481141cc406Sopenharmony_ci return 0; 482141cc406Sopenharmony_ci } 483141cc406Sopenharmony_ci memset (b, 0x00, buf_len); 484141cc406Sopenharmony_ci b[0] = cmd_type; 485141cc406Sopenharmony_ci b[1] = cmd; 486141cc406Sopenharmony_ci /* copy over the argument length in lower endian */ 487141cc406Sopenharmony_ci b[2] = len1 & 0xff; 488141cc406Sopenharmony_ci b[3] = (len1 >> 8) & 0xff; 489141cc406Sopenharmony_ci b[4] = (len1 >> 16) & 0xff; 490141cc406Sopenharmony_ci b[5] = (len1 >> 24) & 0xff; 491141cc406Sopenharmony_ci if (arg1) { 492141cc406Sopenharmony_ci /* Copy the arguments */ 493141cc406Sopenharmony_ci memcpy(b+6, arg1, len1); 494141cc406Sopenharmony_ci } 495141cc406Sopenharmony_ci /* copy over the second argument length in little endian */ 496141cc406Sopenharmony_ci b[6+len1] = len2 & 0xff; 497141cc406Sopenharmony_ci b[7+len1] = (len2 >> 8) & 0xff; 498141cc406Sopenharmony_ci b[8+len1] = (len2 >> 16) & 0xff; 499141cc406Sopenharmony_ci b[9+len1] = (len2 >> 24) & 0xff; 500141cc406Sopenharmony_ci if (arg2) { 501141cc406Sopenharmony_ci memcpy(b+10+len1, arg2, len2); 502141cc406Sopenharmony_ci } 503141cc406Sopenharmony_ci *status = SANE_STATUS_GOOD; 504141cc406Sopenharmony_ci return buf_len; 505141cc406Sopenharmony_ci} 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_cistatic int 508141cc406Sopenharmony_cimc_send(Magicolor_Scanner * s, void *buf, size_t buf_size, SANE_Status * status) 509141cc406Sopenharmony_ci{ 510141cc406Sopenharmony_ci DBG(15, "%s: size = %lu\n", __func__, (u_long) buf_size); 511141cc406Sopenharmony_ci 512141cc406Sopenharmony_ci if (DBG_LEVEL >= 125) { 513141cc406Sopenharmony_ci const unsigned char *s = buf; 514141cc406Sopenharmony_ci DBG(125, "Cmd: 0x%02x %02x, complete buffer:\n", s[0], s[1]); 515141cc406Sopenharmony_ci dump_hex_buffer_dense (125, s, buf_size); 516141cc406Sopenharmony_ci } 517141cc406Sopenharmony_ci 518141cc406Sopenharmony_ci if (s->hw->connection == SANE_MAGICOLOR_NET) { 519141cc406Sopenharmony_ci return sanei_magicolor_net_write(s, buf, buf_size, status); 520141cc406Sopenharmony_ci } else if (s->hw->connection == SANE_MAGICOLOR_USB) { 521141cc406Sopenharmony_ci size_t n; 522141cc406Sopenharmony_ci n = buf_size; 523141cc406Sopenharmony_ci *status = sanei_usb_write_bulk(s->fd, buf, &n); 524141cc406Sopenharmony_ci DBG(125, "USB: wrote %lu bytes, status: %s\n", (unsigned long)n, sane_strstatus(*status)); 525141cc406Sopenharmony_ci return n; 526141cc406Sopenharmony_ci } 527141cc406Sopenharmony_ci 528141cc406Sopenharmony_ci *status = SANE_STATUS_INVAL; 529141cc406Sopenharmony_ci return 0; 530141cc406Sopenharmony_ci /* never reached */ 531141cc406Sopenharmony_ci} 532141cc406Sopenharmony_ci 533141cc406Sopenharmony_cistatic ssize_t 534141cc406Sopenharmony_cimc_recv(Magicolor_Scanner * s, void *buf, ssize_t buf_size, 535141cc406Sopenharmony_ci SANE_Status * status) 536141cc406Sopenharmony_ci{ 537141cc406Sopenharmony_ci ssize_t n = 0; 538141cc406Sopenharmony_ci 539141cc406Sopenharmony_ci DBG(15, "%s: size = %ld, buf = %p\n", __func__, (long) buf_size, buf); 540141cc406Sopenharmony_ci 541141cc406Sopenharmony_ci if (s->hw->connection == SANE_MAGICOLOR_NET) { 542141cc406Sopenharmony_ci n = sanei_magicolor_net_read(s, buf, buf_size, status); 543141cc406Sopenharmony_ci } else if (s->hw->connection == SANE_MAGICOLOR_USB) { 544141cc406Sopenharmony_ci /* !!! only report an error if we don't read anything */ 545141cc406Sopenharmony_ci n = buf_size; /* buf_size gets overwritten */ 546141cc406Sopenharmony_ci *status = 547141cc406Sopenharmony_ci sanei_usb_read_bulk(s->fd, (SANE_Byte *) buf, 548141cc406Sopenharmony_ci (size_t *) & n); 549141cc406Sopenharmony_ci 550141cc406Sopenharmony_ci if (n > 0) 551141cc406Sopenharmony_ci *status = SANE_STATUS_GOOD; 552141cc406Sopenharmony_ci } 553141cc406Sopenharmony_ci 554141cc406Sopenharmony_ci if (n < buf_size) { 555141cc406Sopenharmony_ci DBG(1, "%s: expected = %lu, got = %ld\n", __func__, 556141cc406Sopenharmony_ci (u_long) buf_size, (long) n); 557141cc406Sopenharmony_ci *status = SANE_STATUS_IO_ERROR; 558141cc406Sopenharmony_ci } 559141cc406Sopenharmony_ci 560141cc406Sopenharmony_ci /* dump buffer if appropriate */ 561141cc406Sopenharmony_ci if (DBG_LEVEL >= 127 && n > 0) { 562141cc406Sopenharmony_ci const unsigned char* b=buf; 563141cc406Sopenharmony_ci dump_hex_buffer_dense (125, b, buf_size); 564141cc406Sopenharmony_ci } 565141cc406Sopenharmony_ci 566141cc406Sopenharmony_ci return n; 567141cc406Sopenharmony_ci} 568141cc406Sopenharmony_ci 569141cc406Sopenharmony_ci/* Simple function to exchange a fixed amount of 570141cc406Sopenharmony_ci * data with the scanner 571141cc406Sopenharmony_ci */ 572141cc406Sopenharmony_cistatic SANE_Status 573141cc406Sopenharmony_cimc_txrx(Magicolor_Scanner * s, unsigned char *txbuf, size_t txlen, 574141cc406Sopenharmony_ci unsigned char *rxbuf, size_t rxlen) 575141cc406Sopenharmony_ci{ 576141cc406Sopenharmony_ci SANE_Status status; 577141cc406Sopenharmony_ci 578141cc406Sopenharmony_ci mc_send(s, txbuf, txlen, &status); 579141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 580141cc406Sopenharmony_ci DBG(1, "%s: tx err, %s\n", __func__, sane_strstatus(status)); 581141cc406Sopenharmony_ci return status; 582141cc406Sopenharmony_ci } 583141cc406Sopenharmony_ci 584141cc406Sopenharmony_ci mc_recv(s, rxbuf, rxlen, &status); 585141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 586141cc406Sopenharmony_ci DBG(1, "%s: rx err, %s\n", __func__, sane_strstatus(status)); 587141cc406Sopenharmony_ci } 588141cc406Sopenharmony_ci 589141cc406Sopenharmony_ci return status; 590141cc406Sopenharmony_ci} 591141cc406Sopenharmony_ci 592141cc406Sopenharmony_ci 593141cc406Sopenharmony_ci 594141cc406Sopenharmony_ci 595141cc406Sopenharmony_ci 596141cc406Sopenharmony_ci/**************************************************************************** 597141cc406Sopenharmony_ci * Magicolor high-level communication commands 598141cc406Sopenharmony_ci ****************************************************************************/ 599141cc406Sopenharmony_ci 600141cc406Sopenharmony_ci 601141cc406Sopenharmony_ci/** 0x03 09 01 - Request last error 602141cc406Sopenharmony_ci * <- Information block (0x00 for OK, 0x01 for ERROR) 603141cc406Sopenharmony_ci */ 604141cc406Sopenharmony_cistatic SANE_Status 605141cc406Sopenharmony_cicmd_request_error (SANE_Handle handle) 606141cc406Sopenharmony_ci{ 607141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 608141cc406Sopenharmony_ci SANE_Status status; 609141cc406Sopenharmony_ci unsigned char params[1]; 610141cc406Sopenharmony_ci unsigned char *buf; 611141cc406Sopenharmony_ci size_t buflen; 612141cc406Sopenharmony_ci 613141cc406Sopenharmony_ci DBG(8, "%s\n", __func__); 614141cc406Sopenharmony_ci 615141cc406Sopenharmony_ci if (s->hw->cmd->request_status == 0) 616141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 617141cc406Sopenharmony_ci 618141cc406Sopenharmony_ci buflen = mc_create_buffer (s, s->hw->cmd->scanner_cmd, s->hw->cmd->request_error, 619141cc406Sopenharmony_ci &buf, NULL, 1, &status); 620141cc406Sopenharmony_ci if (buflen <= 0 ) { 621141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 622141cc406Sopenharmony_ci } else if (status != SANE_STATUS_GOOD) { 623141cc406Sopenharmony_ci return status; 624141cc406Sopenharmony_ci } 625141cc406Sopenharmony_ci 626141cc406Sopenharmony_ci status = mc_txrx (s, buf, buflen, params, 1); 627141cc406Sopenharmony_ci free(buf); 628141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 629141cc406Sopenharmony_ci return status; 630141cc406Sopenharmony_ci 631141cc406Sopenharmony_ci DBG(1, "status: %02x\n", params[0]); 632141cc406Sopenharmony_ci 633141cc406Sopenharmony_ci switch (params[0]) { 634141cc406Sopenharmony_ci case STATUS_READY: 635141cc406Sopenharmony_ci DBG(1, " ready\n"); 636141cc406Sopenharmony_ci break; 637141cc406Sopenharmony_ci case STATUS_ADF_JAM: 638141cc406Sopenharmony_ci DBG(1, " paper jam in ADF\n"); 639141cc406Sopenharmony_ci return SANE_STATUS_JAMMED; 640141cc406Sopenharmony_ci break; 641141cc406Sopenharmony_ci case STATUS_OPEN: 642141cc406Sopenharmony_ci DBG(1, " printer door open or waiting for button press\n"); 643141cc406Sopenharmony_ci return SANE_STATUS_COVER_OPEN; 644141cc406Sopenharmony_ci break; 645141cc406Sopenharmony_ci case STATUS_NOT_READY: 646141cc406Sopenharmony_ci DBG(1, " scanner not ready (in use on another interface or warming up)\n"); 647141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 648141cc406Sopenharmony_ci break; 649141cc406Sopenharmony_ci default: 650141cc406Sopenharmony_ci DBG(1, " unknown status 0x%x\n", params[0]); 651141cc406Sopenharmony_ci } 652141cc406Sopenharmony_ci return status; 653141cc406Sopenharmony_ci} 654141cc406Sopenharmony_ci 655141cc406Sopenharmony_ci/** 0x03 0d - Request status command */ 656141cc406Sopenharmony_cistatic SANE_Status 657141cc406Sopenharmony_cicmd_request_status(SANE_Handle handle, unsigned char *b) 658141cc406Sopenharmony_ci{ 659141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 660141cc406Sopenharmony_ci SANE_Status status; 661141cc406Sopenharmony_ci unsigned char *buf; 662141cc406Sopenharmony_ci size_t buflen; 663141cc406Sopenharmony_ci 664141cc406Sopenharmony_ci DBG(8, "%s\n", __func__); 665141cc406Sopenharmony_ci if (!b) { 666141cc406Sopenharmony_ci DBG(1, "%s called with NULL buffer\n", __func__); 667141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 668141cc406Sopenharmony_ci } 669141cc406Sopenharmony_ci memset (b, 0x00, 0x0b); /* initialize all 0x0b bytes with 0 */ 670141cc406Sopenharmony_ci buflen = mc_create_buffer (s, s->hw->cmd->scanner_cmd, s->hw->cmd->request_status, 671141cc406Sopenharmony_ci &buf, NULL, 0x0b, &status); 672141cc406Sopenharmony_ci if (buflen <= 0 ) { 673141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 674141cc406Sopenharmony_ci } else if (status != SANE_STATUS_GOOD) { 675141cc406Sopenharmony_ci return status; 676141cc406Sopenharmony_ci } 677141cc406Sopenharmony_ci 678141cc406Sopenharmony_ci status = mc_txrx (s, buf, buflen, b, 0x0b); 679141cc406Sopenharmony_ci free (buf); 680141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 681141cc406Sopenharmony_ci DBG(8, "%s: Status NOT successfully retrieved\n", __func__); 682141cc406Sopenharmony_ci else { 683141cc406Sopenharmony_ci DBG(8, "%s: Status successfully retrieved:\n", __func__); 684141cc406Sopenharmony_ci /* TODO: debug output of the returned parameters... */ 685141cc406Sopenharmony_ci DBG (11, " ADF status: 0x%02x", b[1]); 686141cc406Sopenharmony_ci if (b[1] & ADF_LOADED) { 687141cc406Sopenharmony_ci DBG (11, " loaded\n"); 688141cc406Sopenharmony_ci } else { 689141cc406Sopenharmony_ci DBG (11, " not loaded\n"); 690141cc406Sopenharmony_ci } 691141cc406Sopenharmony_ci } 692141cc406Sopenharmony_ci return status; 693141cc406Sopenharmony_ci} 694141cc406Sopenharmony_ci 695141cc406Sopenharmony_ci 696141cc406Sopenharmony_ci/** 0x03 08 - Start scan command */ 697141cc406Sopenharmony_cistatic SANE_Status 698141cc406Sopenharmony_cicmd_start_scan (SANE_Handle handle, size_t value) 699141cc406Sopenharmony_ci{ 700141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 701141cc406Sopenharmony_ci SANE_Status status; 702141cc406Sopenharmony_ci unsigned char params1[4], params2[1]; 703141cc406Sopenharmony_ci unsigned char *buf; 704141cc406Sopenharmony_ci size_t buflen; 705141cc406Sopenharmony_ci 706141cc406Sopenharmony_ci DBG(8, "%s\n", __func__); 707141cc406Sopenharmony_ci /* Copy params to buffers */ 708141cc406Sopenharmony_ci /* arg1 is expected returned bytes per line, 4-byte little endian */ 709141cc406Sopenharmony_ci /* arg2 is unknown, seems to be always 0x00 */ 710141cc406Sopenharmony_ci params1[0] = value & 0xff; 711141cc406Sopenharmony_ci params1[1] = (value >> 8) & 0xff; 712141cc406Sopenharmony_ci params1[2] = (value >> 16) & 0xff; 713141cc406Sopenharmony_ci params1[3] = (value >> 24) & 0xff; 714141cc406Sopenharmony_ci 715141cc406Sopenharmony_ci params2[0] = 0x00; 716141cc406Sopenharmony_ci buflen = mc_create_buffer2 (s, s->hw->cmd->scanner_cmd, s->hw->cmd->start_scanning, 717141cc406Sopenharmony_ci &buf, params1, 4, params2, 1, &status); 718141cc406Sopenharmony_ci if (buflen <= 0 ) { 719141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 720141cc406Sopenharmony_ci } else if (status != SANE_STATUS_GOOD) { 721141cc406Sopenharmony_ci return status; 722141cc406Sopenharmony_ci } 723141cc406Sopenharmony_ci 724141cc406Sopenharmony_ci mc_send(s, buf, buflen, &status); 725141cc406Sopenharmony_ci free (buf); 726141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 727141cc406Sopenharmony_ci DBG(8, "%s: Data NOT successfully sent\n", __func__); 728141cc406Sopenharmony_ci else 729141cc406Sopenharmony_ci DBG(8, "%s: Data successfully sent\n", __func__); 730141cc406Sopenharmony_ci return status; 731141cc406Sopenharmony_ci} 732141cc406Sopenharmony_ci 733141cc406Sopenharmony_ci/** 0x03 0a - Cancel(?) Scan command */ 734141cc406Sopenharmony_ci/* TODO: Does this command really mean CANCEL??? */ 735141cc406Sopenharmony_cistatic SANE_Status 736141cc406Sopenharmony_cicmd_cancel_scan (SANE_Handle handle) 737141cc406Sopenharmony_ci{ 738141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 739141cc406Sopenharmony_ci SANE_Status status; 740141cc406Sopenharmony_ci unsigned char *buf; 741141cc406Sopenharmony_ci size_t buflen; 742141cc406Sopenharmony_ci 743141cc406Sopenharmony_ci DBG(8, "%s\n", __func__); 744141cc406Sopenharmony_ci buflen = mc_create_buffer (s, s->hw->cmd->scanner_cmd, s->hw->cmd->stop_scanning, 745141cc406Sopenharmony_ci &buf, NULL, 0, &status); 746141cc406Sopenharmony_ci if (buflen <= 0 ) { 747141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 748141cc406Sopenharmony_ci } else if (status != SANE_STATUS_GOOD) { 749141cc406Sopenharmony_ci return status; 750141cc406Sopenharmony_ci } 751141cc406Sopenharmony_ci 752141cc406Sopenharmony_ci mc_send(s, buf, buflen, &status); 753141cc406Sopenharmony_ci free (buf); 754141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 755141cc406Sopenharmony_ci DBG(8, "%s: Data NOT successfully sent\n", __func__); 756141cc406Sopenharmony_ci else 757141cc406Sopenharmony_ci DBG(8, "%s: Data successfully sent\n", __func__); 758141cc406Sopenharmony_ci return status; 759141cc406Sopenharmony_ci} 760141cc406Sopenharmony_ci 761141cc406Sopenharmony_ci/** 0x03 12 - Finish(?) scan command */ 762141cc406Sopenharmony_ci/* TODO: Does this command really mean FINISH??? */ 763141cc406Sopenharmony_cistatic SANE_Status 764141cc406Sopenharmony_cicmd_finish_scan (SANE_Handle handle) 765141cc406Sopenharmony_ci{ 766141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 767141cc406Sopenharmony_ci SANE_Status status; 768141cc406Sopenharmony_ci unsigned char *buf, returned[0x0b]; 769141cc406Sopenharmony_ci size_t buflen; 770141cc406Sopenharmony_ci 771141cc406Sopenharmony_ci DBG(8, "%s\n", __func__); 772141cc406Sopenharmony_ci buflen = mc_create_buffer (s, s->hw->cmd->scanner_cmd, s->hw->cmd->unknown2, 773141cc406Sopenharmony_ci &buf, NULL, 0x0b, &status); 774141cc406Sopenharmony_ci if (buflen <= 0 ) { 775141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 776141cc406Sopenharmony_ci } else if (status != SANE_STATUS_GOOD) { 777141cc406Sopenharmony_ci return status; 778141cc406Sopenharmony_ci } 779141cc406Sopenharmony_ci memset (&returned[0], 0x00, 0x0b); 780141cc406Sopenharmony_ci 781141cc406Sopenharmony_ci status = mc_txrx (s, buf, buflen, returned, 0x0b); 782141cc406Sopenharmony_ci free (buf); 783141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 784141cc406Sopenharmony_ci DBG(8, "%s: Data NOT successfully sent\n", __func__); 785141cc406Sopenharmony_ci else 786141cc406Sopenharmony_ci DBG(8, "%s: Data successfully sent\n", __func__); 787141cc406Sopenharmony_ci return status; 788141cc406Sopenharmony_ci} 789141cc406Sopenharmony_ci 790141cc406Sopenharmony_ci/** 0x03 0b - Get scanning parameters command 791141cc406Sopenharmony_ci * input buffer seems to be 0x00 always */ 792141cc406Sopenharmony_cistatic SANE_Status 793141cc406Sopenharmony_cicmd_get_scanning_parameters(SANE_Handle handle, 794141cc406Sopenharmony_ci SANE_Frame *format, SANE_Int *depth, 795141cc406Sopenharmony_ci SANE_Int *data_pixels, SANE_Int *pixels_per_line, 796141cc406Sopenharmony_ci SANE_Int *lines) 797141cc406Sopenharmony_ci{ 798141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 799141cc406Sopenharmony_ci SANE_Status status; 800141cc406Sopenharmony_ci unsigned char *txbuf, rxbuf[8]; 801141cc406Sopenharmony_ci size_t buflen; 802141cc406Sopenharmony_ci NOT_USED (format); 803141cc406Sopenharmony_ci NOT_USED (depth); 804141cc406Sopenharmony_ci 805141cc406Sopenharmony_ci DBG(8, "%s\n", __func__); 806141cc406Sopenharmony_ci buflen = mc_create_buffer (s, s->hw->cmd->scanner_cmd, 807141cc406Sopenharmony_ci s->hw->cmd->request_scan_parameters, 808141cc406Sopenharmony_ci &txbuf, NULL, 8, &status); 809141cc406Sopenharmony_ci if (buflen <= 0 ) { 810141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 811141cc406Sopenharmony_ci } else if (status != SANE_STATUS_GOOD) { 812141cc406Sopenharmony_ci return status; 813141cc406Sopenharmony_ci } 814141cc406Sopenharmony_ci 815141cc406Sopenharmony_ci status = mc_txrx (s, txbuf, buflen, rxbuf, 8); 816141cc406Sopenharmony_ci free (txbuf); 817141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 818141cc406Sopenharmony_ci DBG(8, "%s: Parameters NOT successfully retrieved\n", __func__); 819141cc406Sopenharmony_ci else { 820141cc406Sopenharmony_ci DBG(8, "%s: Parameters successfully retrieved\n", __func__); 821141cc406Sopenharmony_ci 822141cc406Sopenharmony_ci /* Assign px_per_line and lines. Bytes 7-8 must match 3-4 */ 823141cc406Sopenharmony_ci if (rxbuf[2]!=rxbuf[6] || rxbuf[3]!=rxbuf[7]) { 824141cc406Sopenharmony_ci DBG (1, "%s: ERROR: Returned image parameters indicate an " 825141cc406Sopenharmony_ci "unsupported device: Bytes 3-4 do not match " 826141cc406Sopenharmony_ci "bytes 7-8! Trying to continue with bytes 3-4.\n", 827141cc406Sopenharmony_ci __func__); 828141cc406Sopenharmony_ci dump_hex_buffer_dense (1, rxbuf, 8); 829141cc406Sopenharmony_ci } 830141cc406Sopenharmony_ci /* Read returned values, encoded in 2-byte little endian */ 831141cc406Sopenharmony_ci *data_pixels = rxbuf[1] * 0x100 + rxbuf[0]; 832141cc406Sopenharmony_ci *lines = rxbuf[3] * 0x100 + rxbuf[2]; 833141cc406Sopenharmony_ci *pixels_per_line = rxbuf[5] * 0x100 + rxbuf[4]; 834141cc406Sopenharmony_ci DBG (8, "%s: data_pixels = 0x%x (%u), lines = 0x%x (%u), " 835141cc406Sopenharmony_ci "pixels_per_line = 0x%x (%u)\n", __func__, 836141cc406Sopenharmony_ci *data_pixels, *data_pixels, 837141cc406Sopenharmony_ci *lines, *lines, 838141cc406Sopenharmony_ci *pixels_per_line, *pixels_per_line); 839141cc406Sopenharmony_ci 840141cc406Sopenharmony_ci /* 841141cc406Sopenharmony_ci * SECURITY REMEDIATION 842141cc406Sopenharmony_ci * See gitlab issue #279 - Issue10 SIGFPE in mc_setup_block_mode 843141cc406Sopenharmony_ci * 844141cc406Sopenharmony_ci * pixels_per_line cannot be zero, otherwise a division by zero error can occur later. 845141cc406Sopenharmony_ci * Added checking the parameters to ensure that this issue cannot occur. 846141cc406Sopenharmony_ci * 847141cc406Sopenharmony_ci * Additionally to the reported issue, it makes no sense for any of the values of 848141cc406Sopenharmony_ci * data_pixels, lines or pixels_per_line to be zero. I do not have any knowledge 849141cc406Sopenharmony_ci * of valid maximums for these parameters. 850141cc406Sopenharmony_ci * 851141cc406Sopenharmony_ci */ 852141cc406Sopenharmony_ci if ((*data_pixels == 0) || (*lines == 0) || (*pixels_per_line == 0)) { 853141cc406Sopenharmony_ci DBG (1, "%s: ERROR: Returned image parameters contain invalid " 854141cc406Sopenharmony_ci "bytes. Zero values for these parameters are not rational.\n", 855141cc406Sopenharmony_ci __func__); 856141cc406Sopenharmony_ci dump_hex_buffer_dense (1, rxbuf, 8); 857141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 858141cc406Sopenharmony_ci } 859141cc406Sopenharmony_ci } 860141cc406Sopenharmony_ci 861141cc406Sopenharmony_ci return status; 862141cc406Sopenharmony_ci} 863141cc406Sopenharmony_ci 864141cc406Sopenharmony_ci/** 0x03 0c - Set scanning parameters command */ 865141cc406Sopenharmony_cistatic SANE_Status 866141cc406Sopenharmony_cicmd_set_scanning_parameters(SANE_Handle handle, 867141cc406Sopenharmony_ci unsigned char resolution, unsigned char color_mode, 868141cc406Sopenharmony_ci unsigned char brightness, unsigned char contrast, 869141cc406Sopenharmony_ci int tl_x, int tl_y, int width, int height, unsigned char source) 870141cc406Sopenharmony_ci{ 871141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 872141cc406Sopenharmony_ci SANE_Status status; 873141cc406Sopenharmony_ci unsigned char param[0x11]; 874141cc406Sopenharmony_ci unsigned char *buf; 875141cc406Sopenharmony_ci size_t buflen; 876141cc406Sopenharmony_ci 877141cc406Sopenharmony_ci DBG(8, "%s\n", __func__); 878141cc406Sopenharmony_ci /* Copy over the params to the param byte array */ 879141cc406Sopenharmony_ci /* Byte structure: 880141cc406Sopenharmony_ci * byte 0: resolution 881141cc406Sopenharmony_ci * byte 1: color mode 882141cc406Sopenharmony_ci * byte 2: brightness 883141cc406Sopenharmony_ci * byte 3: 0xff 884141cc406Sopenharmony_ci * byte 4-5: x-start 885141cc406Sopenharmony_ci * byte 6-7: y-start 886141cc406Sopenharmony_ci * byte 8-9: x-extent 887141cc406Sopenharmony_ci * byte 10-11: y-extent 888141cc406Sopenharmony_ci * byte 12: source (ADF/FBF) 889141cc406Sopenharmony_ci **/ 890141cc406Sopenharmony_ci memset (¶m[0], 0x00, 0x11); 891141cc406Sopenharmony_ci param[0] = resolution; 892141cc406Sopenharmony_ci param[1] = color_mode; 893141cc406Sopenharmony_ci param[2] = brightness; 894141cc406Sopenharmony_ci param[3] = contrast | 0xff; /* TODO: Always 0xff? What about contrast? */ 895141cc406Sopenharmony_ci /* Image coordinates are encoded 2-byte little endian: */ 896141cc406Sopenharmony_ci param[4] = tl_x & 0xff; 897141cc406Sopenharmony_ci param[5] = (tl_x >> 8) & 0xff; 898141cc406Sopenharmony_ci param[6] = tl_y & 0xff; 899141cc406Sopenharmony_ci param[7] = (tl_y >> 8) & 0xff; 900141cc406Sopenharmony_ci param[8] = width & 0xff; 901141cc406Sopenharmony_ci param[9] = (width >> 8) & 0xff; 902141cc406Sopenharmony_ci param[10] = height & 0xff; 903141cc406Sopenharmony_ci param[11] = (height >> 8) & 0xff; 904141cc406Sopenharmony_ci 905141cc406Sopenharmony_ci param[12] = source; 906141cc406Sopenharmony_ci 907141cc406Sopenharmony_ci /* dump buffer if appropriate */ 908141cc406Sopenharmony_ci DBG (127, " Scanning parameter buffer:"); 909141cc406Sopenharmony_ci dump_hex_buffer_dense (127, param, 0x11); 910141cc406Sopenharmony_ci 911141cc406Sopenharmony_ci buflen = mc_create_buffer (s, s->hw->cmd->scanner_cmd, s->hw->cmd->set_scan_parameters, 912141cc406Sopenharmony_ci &buf, param, 0x11, &status); 913141cc406Sopenharmony_ci if (buflen <= 0 ) { 914141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 915141cc406Sopenharmony_ci } else if (status != SANE_STATUS_GOOD) { 916141cc406Sopenharmony_ci return status; 917141cc406Sopenharmony_ci } 918141cc406Sopenharmony_ci 919141cc406Sopenharmony_ci mc_send(s, buf, buflen, &status); 920141cc406Sopenharmony_ci free (buf); 921141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 922141cc406Sopenharmony_ci DBG(8, "%s: Data NOT successfully sent\n", __func__); 923141cc406Sopenharmony_ci else 924141cc406Sopenharmony_ci DBG(8, "%s: Data successfully sent\n", __func__); 925141cc406Sopenharmony_ci return status; 926141cc406Sopenharmony_ci} 927141cc406Sopenharmony_ci 928141cc406Sopenharmony_ci/** 0x03 ?? - Request push button status command */ 929141cc406Sopenharmony_ci#if 0 930141cc406Sopenharmony_cistatic SANE_Status 931141cc406Sopenharmony_cicmd_request_push_button_status(SANE_Handle handle, unsigned char *bstatus) 932141cc406Sopenharmony_ci{ 933141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 934141cc406Sopenharmony_ci SANE_Status status; 935141cc406Sopenharmony_ci unsigned char *buf; 936141cc406Sopenharmony_ci size_t buflen; 937141cc406Sopenharmony_ci 938141cc406Sopenharmony_ci DBG(8, "%s\n", __func__); 939141cc406Sopenharmony_ci 940141cc406Sopenharmony_ci 941141cc406Sopenharmony_ci if (s->hw->cmd->unknown1 == 0) 942141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 943141cc406Sopenharmony_ci 944141cc406Sopenharmony_ci DBG(8, "%s: Supported\n", __func__); 945141cc406Sopenharmony_ci memset (bstatus, 0x00, 1); 946141cc406Sopenharmony_ci buflen = mc_create_buffer (s, s->hw->cmd->scanner_cmd, s->hw->cmd->unknown1, 947141cc406Sopenharmony_ci &buf, bstatus, 1, &status); 948141cc406Sopenharmony_ci if (buflen <= 0 ) { 949141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 950141cc406Sopenharmony_ci } else if (status != SANE_STATUS_GOOD) { 951141cc406Sopenharmony_ci return status; 952141cc406Sopenharmony_ci } 953141cc406Sopenharmony_ci 954141cc406Sopenharmony_ci status = mc_txrx (s, buf, buflen, bstatus, 1); 955141cc406Sopenharmony_ci free(buf); 956141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 957141cc406Sopenharmony_ci return status; 958141cc406Sopenharmony_ci 959141cc406Sopenharmony_ci DBG(1, "push button status: %02x ", bstatus[0]); 960141cc406Sopenharmony_ci switch (bstatus[0]) { 961141cc406Sopenharmony_ci /* TODO: What's the response code for button pressed??? */ 962141cc406Sopenharmony_ci default: 963141cc406Sopenharmony_ci DBG(1, " unknown\n"); 964141cc406Sopenharmony_ci status = SANE_STATUS_UNSUPPORTED; 965141cc406Sopenharmony_ci } 966141cc406Sopenharmony_ci return status; 967141cc406Sopenharmony_ci} 968141cc406Sopenharmony_ci#endif 969141cc406Sopenharmony_ci 970141cc406Sopenharmony_ci/** 0x03 0e - Read data command */ 971141cc406Sopenharmony_cistatic SANE_Status 972141cc406Sopenharmony_cicmd_read_data (SANE_Handle handle, unsigned char *buf, size_t len) 973141cc406Sopenharmony_ci{ 974141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 975141cc406Sopenharmony_ci SANE_Status status; 976141cc406Sopenharmony_ci unsigned char *txbuf; 977141cc406Sopenharmony_ci unsigned char param[4]; 978141cc406Sopenharmony_ci size_t txbuflen; 979141cc406Sopenharmony_ci int oldtimeout = MC_Request_Timeout; 980141cc406Sopenharmony_ci 981141cc406Sopenharmony_ci DBG(8, "%s\n", __func__); 982141cc406Sopenharmony_ci param[0] = len & 0xff; 983141cc406Sopenharmony_ci param[1] = (len >> 8) & 0xff; 984141cc406Sopenharmony_ci param[2] = (len >> 16) & 0xff; 985141cc406Sopenharmony_ci param[3] = (len >> 24) & 0xff; 986141cc406Sopenharmony_ci 987141cc406Sopenharmony_ci txbuflen = mc_create_buffer (s, s->hw->cmd->scanner_cmd, s->hw->cmd->request_data, 988141cc406Sopenharmony_ci &txbuf, param, 4, &status); 989141cc406Sopenharmony_ci if (txbuflen <= 0 ) { 990141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 991141cc406Sopenharmony_ci } else if (status != SANE_STATUS_GOOD) { 992141cc406Sopenharmony_ci return status; 993141cc406Sopenharmony_ci } 994141cc406Sopenharmony_ci 995141cc406Sopenharmony_ci /* Temporarily set the poll timeout to 10 seconds instead of 2, 996141cc406Sopenharmony_ci * because a color scan needs >5 seconds to initialize. */ 997141cc406Sopenharmony_ci MC_Request_Timeout = MC_Scan_Data_Timeout; 998141cc406Sopenharmony_ci status = mc_txrx (s, txbuf, txbuflen, buf, len); 999141cc406Sopenharmony_ci MC_Request_Timeout = oldtimeout; 1000141cc406Sopenharmony_ci free (txbuf); 1001141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1002141cc406Sopenharmony_ci DBG(8, "%s: Image data NOT successfully retrieved\n", __func__); 1003141cc406Sopenharmony_ci else { 1004141cc406Sopenharmony_ci DBG(8, "%s: Image data successfully retrieved\n", __func__); 1005141cc406Sopenharmony_ci } 1006141cc406Sopenharmony_ci 1007141cc406Sopenharmony_ci return status; 1008141cc406Sopenharmony_ci} 1009141cc406Sopenharmony_ci 1010141cc406Sopenharmony_ci 1011141cc406Sopenharmony_ci 1012141cc406Sopenharmony_ci/* TODO: 0x03 0f command (unknown), 0x03 10 command (set button wait) */ 1013141cc406Sopenharmony_ci 1014141cc406Sopenharmony_ci 1015141cc406Sopenharmony_ci 1016141cc406Sopenharmony_ci 1017141cc406Sopenharmony_ci/**************************************************************************** 1018141cc406Sopenharmony_ci * Magicolor backend high-level operations 1019141cc406Sopenharmony_ci ****************************************************************************/ 1020141cc406Sopenharmony_ci 1021141cc406Sopenharmony_ci 1022141cc406Sopenharmony_cistatic void 1023141cc406Sopenharmony_cimc_dev_init(Magicolor_Device *dev, const char *devname, int conntype) 1024141cc406Sopenharmony_ci{ 1025141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 1026141cc406Sopenharmony_ci 1027141cc406Sopenharmony_ci dev->name = NULL; 1028141cc406Sopenharmony_ci dev->model = NULL; 1029141cc406Sopenharmony_ci dev->connection = conntype; 1030141cc406Sopenharmony_ci dev->sane.name = devname; 1031141cc406Sopenharmony_ci dev->sane.model = NULL; 1032141cc406Sopenharmony_ci dev->sane.type = "flatbed scanner"; 1033141cc406Sopenharmony_ci dev->sane.vendor = "Magicolor"; 1034141cc406Sopenharmony_ci dev->cap = &magicolor_cap[MAGICOLOR_CAP_DEFAULT]; 1035141cc406Sopenharmony_ci dev->cmd = &magicolor_cmd[MAGICOLOR_LEVEL_DEFAULT]; 1036141cc406Sopenharmony_ci /* Change default level when using a network connection */ 1037141cc406Sopenharmony_ci if (dev->connection == SANE_MAGICOLOR_NET) 1038141cc406Sopenharmony_ci dev->cmd = &magicolor_cmd[MAGICOLOR_LEVEL_NET]; 1039141cc406Sopenharmony_ci} 1040141cc406Sopenharmony_ci 1041141cc406Sopenharmony_cistatic SANE_Status 1042141cc406Sopenharmony_cimc_dev_post_init(struct Magicolor_Device *dev) 1043141cc406Sopenharmony_ci{ 1044141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 1045141cc406Sopenharmony_ci NOT_USED (dev); 1046141cc406Sopenharmony_ci /* Correct device parameters if needed */ 1047141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1048141cc406Sopenharmony_ci} 1049141cc406Sopenharmony_ci 1050141cc406Sopenharmony_cistatic SANE_Status 1051141cc406Sopenharmony_cimc_set_model(Magicolor_Scanner * s, const char *model, size_t len) 1052141cc406Sopenharmony_ci{ 1053141cc406Sopenharmony_ci unsigned char *buf; 1054141cc406Sopenharmony_ci unsigned char *p; 1055141cc406Sopenharmony_ci struct Magicolor_Device *dev = s->hw; 1056141cc406Sopenharmony_ci 1057141cc406Sopenharmony_ci buf = malloc(len + 1); 1058141cc406Sopenharmony_ci if (buf == NULL) 1059141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1060141cc406Sopenharmony_ci 1061141cc406Sopenharmony_ci memcpy(buf, model, len); 1062141cc406Sopenharmony_ci buf[len] = '\0'; 1063141cc406Sopenharmony_ci 1064141cc406Sopenharmony_ci p = &buf[len - 1]; 1065141cc406Sopenharmony_ci 1066141cc406Sopenharmony_ci while (*p == ' ') { 1067141cc406Sopenharmony_ci *p = '\0'; 1068141cc406Sopenharmony_ci p--; 1069141cc406Sopenharmony_ci } 1070141cc406Sopenharmony_ci 1071141cc406Sopenharmony_ci if (dev->model) 1072141cc406Sopenharmony_ci free(dev->model); 1073141cc406Sopenharmony_ci 1074141cc406Sopenharmony_ci dev->model = strndup((const char *) buf, len); 1075141cc406Sopenharmony_ci dev->sane.model = dev->model; 1076141cc406Sopenharmony_ci DBG(10, "%s: model is '%s'\n", __func__, dev->model); 1077141cc406Sopenharmony_ci 1078141cc406Sopenharmony_ci free(buf); 1079141cc406Sopenharmony_ci 1080141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1081141cc406Sopenharmony_ci} 1082141cc406Sopenharmony_ci 1083141cc406Sopenharmony_cistatic void 1084141cc406Sopenharmony_cimc_set_device (SANE_Handle handle, unsigned int device) 1085141cc406Sopenharmony_ci{ 1086141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 1087141cc406Sopenharmony_ci Magicolor_Device *dev = s->hw; 1088141cc406Sopenharmony_ci const char* cmd_level; 1089141cc406Sopenharmony_ci int n; 1090141cc406Sopenharmony_ci 1091141cc406Sopenharmony_ci DBG(1, "%s: 0x%x\n", __func__, device); 1092141cc406Sopenharmony_ci 1093141cc406Sopenharmony_ci for (n = 0; n < NELEMS (magicolor_cap); n++) { 1094141cc406Sopenharmony_ci if (magicolor_cap[n].id == device) 1095141cc406Sopenharmony_ci break; 1096141cc406Sopenharmony_ci } 1097141cc406Sopenharmony_ci if (n < NELEMS(magicolor_cap)) { 1098141cc406Sopenharmony_ci dev->cap = &magicolor_cap[n]; 1099141cc406Sopenharmony_ci } else { 1100141cc406Sopenharmony_ci dev->cap = &magicolor_cap[MAGICOLOR_CAP_DEFAULT]; 1101141cc406Sopenharmony_ci DBG(1, " unknown device 0x%x, using default %s\n", 1102141cc406Sopenharmony_ci device, dev->cap->model); 1103141cc406Sopenharmony_ci } 1104141cc406Sopenharmony_ci mc_set_model (s, dev->cap->model, strlen (dev->cap->model)); 1105141cc406Sopenharmony_ci 1106141cc406Sopenharmony_ci cmd_level = dev->cap->cmds; 1107141cc406Sopenharmony_ci /* set command type and level */ 1108141cc406Sopenharmony_ci for (n = 0; n < NELEMS(magicolor_cmd); n++) { 1109141cc406Sopenharmony_ci if (!strcmp(cmd_level, magicolor_cmd[n].level)) 1110141cc406Sopenharmony_ci break; 1111141cc406Sopenharmony_ci } 1112141cc406Sopenharmony_ci 1113141cc406Sopenharmony_ci if (n < NELEMS(magicolor_cmd)) { 1114141cc406Sopenharmony_ci dev->cmd = &magicolor_cmd[n]; 1115141cc406Sopenharmony_ci } else { 1116141cc406Sopenharmony_ci dev->cmd = &magicolor_cmd[MAGICOLOR_LEVEL_DEFAULT]; 1117141cc406Sopenharmony_ci DBG(1, " unknown command level %s, using %s\n", 1118141cc406Sopenharmony_ci cmd_level, dev->cmd->level); 1119141cc406Sopenharmony_ci } 1120141cc406Sopenharmony_ci} 1121141cc406Sopenharmony_ci 1122141cc406Sopenharmony_cistatic SANE_Status 1123141cc406Sopenharmony_cimc_discover_capabilities(Magicolor_Scanner *s) 1124141cc406Sopenharmony_ci{ 1125141cc406Sopenharmony_ci SANE_Status status; 1126141cc406Sopenharmony_ci Magicolor_Device *dev = s->hw; 1127141cc406Sopenharmony_ci 1128141cc406Sopenharmony_ci SANE_String_Const *source_list_add = source_list; 1129141cc406Sopenharmony_ci 1130141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 1131141cc406Sopenharmony_ci 1132141cc406Sopenharmony_ci /* always add flatbed */ 1133141cc406Sopenharmony_ci *source_list_add++ = FBF_STR; 1134141cc406Sopenharmony_ci /* TODO: How can I check for existence of an ADF??? */ 1135141cc406Sopenharmony_ci if (dev->cap->ADF) 1136141cc406Sopenharmony_ci *source_list_add++ = ADF_STR; 1137141cc406Sopenharmony_ci 1138141cc406Sopenharmony_ci /* TODO: Is there any capability that we can extract from the 1139141cc406Sopenharmony_ci * device by some scanne command? So far, it looks like 1140141cc406Sopenharmony_ci * the device does not support any reporting. I don't even 1141141cc406Sopenharmony_ci * see a way to determine which device we are talking to! 1142141cc406Sopenharmony_ci */ 1143141cc406Sopenharmony_ci 1144141cc406Sopenharmony_ci 1145141cc406Sopenharmony_ci /* request error status */ 1146141cc406Sopenharmony_ci status = cmd_request_error(s); 1147141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1148141cc406Sopenharmony_ci return status; 1149141cc406Sopenharmony_ci 1150141cc406Sopenharmony_ci dev->x_range = &dev->cap->fbf_x_range; 1151141cc406Sopenharmony_ci dev->y_range = &dev->cap->fbf_y_range; 1152141cc406Sopenharmony_ci 1153141cc406Sopenharmony_ci DBG(5, " x-range: %f %f\n", SANE_UNFIX(dev->x_range->min), SANE_UNFIX(dev->x_range->max)); 1154141cc406Sopenharmony_ci DBG(5, " y-range: %f %f\n", SANE_UNFIX(dev->y_range->min), SANE_UNFIX(dev->y_range->max)); 1155141cc406Sopenharmony_ci 1156141cc406Sopenharmony_ci DBG(5, "End of %s, status:%s\n", __func__, sane_strstatus(status)); 1157141cc406Sopenharmony_ci *source_list_add = NULL; /* add end marker to source list */ 1158141cc406Sopenharmony_ci return status; 1159141cc406Sopenharmony_ci} 1160141cc406Sopenharmony_ci 1161141cc406Sopenharmony_cistatic SANE_Status 1162141cc406Sopenharmony_cimc_setup_block_mode (Magicolor_Scanner *s) 1163141cc406Sopenharmony_ci{ 1164141cc406Sopenharmony_ci /* block_len should always be a multiple of bytes_per_line, so 1165141cc406Sopenharmony_ci * we retrieve only whole lines at once */ 1166141cc406Sopenharmony_ci s->block_len = (int)(0xff00/s->scan_bytes_per_line) * s->scan_bytes_per_line; 1167141cc406Sopenharmony_ci s->blocks = s->data_len / s->block_len; 1168141cc406Sopenharmony_ci s->last_len = s->data_len - (s->blocks * s->block_len); 1169141cc406Sopenharmony_ci if (s->last_len>0) 1170141cc406Sopenharmony_ci s->blocks++; 1171141cc406Sopenharmony_ci DBG(5, "%s: block_len=0x%x, last_len=0x%0x, blocks=%d\n", __func__, s->block_len, s->last_len, s->blocks); 1172141cc406Sopenharmony_ci s->counter = 0; 1173141cc406Sopenharmony_ci s->bytes_read_in_line = 0; 1174141cc406Sopenharmony_ci if (s->line_buffer) 1175141cc406Sopenharmony_ci free(s->line_buffer); 1176141cc406Sopenharmony_ci s->line_buffer = malloc(s->scan_bytes_per_line); 1177141cc406Sopenharmony_ci if (s->line_buffer == NULL) { 1178141cc406Sopenharmony_ci DBG(1, "out of memory (line %d)\n", __LINE__); 1179141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1180141cc406Sopenharmony_ci } 1181141cc406Sopenharmony_ci 1182141cc406Sopenharmony_ci 1183141cc406Sopenharmony_ci DBG (5, " %s: Setup block mode - scan_bytes_per_line=%d, pixels_per_line=%d, depth=%d, data_len=%x, block_len=%x, blocks=%d, last_len=%x\n", 1184141cc406Sopenharmony_ci __func__, s->scan_bytes_per_line, s->params.pixels_per_line, s->params.depth, s->data_len, s->block_len, s->blocks, s->last_len); 1185141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1186141cc406Sopenharmony_ci} 1187141cc406Sopenharmony_ci 1188141cc406Sopenharmony_ci/* Call the 0x03 0c command to set scanning parameters from the s->opt list */ 1189141cc406Sopenharmony_cistatic SANE_Status 1190141cc406Sopenharmony_cimc_set_scanning_parameters(Magicolor_Scanner * s) 1191141cc406Sopenharmony_ci{ 1192141cc406Sopenharmony_ci SANE_Status status; 1193141cc406Sopenharmony_ci unsigned char rs, source, brightness; 1194141cc406Sopenharmony_ci struct mode_param *mparam = &mode_params[s->val[OPT_MODE].w]; 1195141cc406Sopenharmony_ci SANE_Int scan_pixels_per_line = 0; 1196141cc406Sopenharmony_ci 1197141cc406Sopenharmony_ci DBG(1, "%s\n", __func__); 1198141cc406Sopenharmony_ci 1199141cc406Sopenharmony_ci /* Find the resolution in the res list and assign the index to buf[1] */ 1200141cc406Sopenharmony_ci for (rs=0; rs < s->hw->cap->res_list_size; rs++ ) { 1201141cc406Sopenharmony_ci if ( s->val[OPT_RESOLUTION].w == s->hw->cap->res_list[rs] ) 1202141cc406Sopenharmony_ci break; 1203141cc406Sopenharmony_ci } 1204141cc406Sopenharmony_ci 1205141cc406Sopenharmony_ci if (SANE_OPTION_IS_ACTIVE(s->opt[OPT_BRIGHTNESS].cap)) { 1206141cc406Sopenharmony_ci brightness = s->val[OPT_BRIGHTNESS].w; 1207141cc406Sopenharmony_ci } else { 1208141cc406Sopenharmony_ci brightness = 5; 1209141cc406Sopenharmony_ci } 1210141cc406Sopenharmony_ci 1211141cc406Sopenharmony_ci /* ADF used? */ 1212141cc406Sopenharmony_ci if (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) == 0) { 1213141cc406Sopenharmony_ci /* Use ADF */ 1214141cc406Sopenharmony_ci if (s->val[OPT_ADF_MODE].w == 0) { 1215141cc406Sopenharmony_ci source = 0x01; 1216141cc406Sopenharmony_ci } else { 1217141cc406Sopenharmony_ci /* Use duplex */ 1218141cc406Sopenharmony_ci source = 0x02; 1219141cc406Sopenharmony_ci } 1220141cc406Sopenharmony_ci } else { 1221141cc406Sopenharmony_ci source = 0x00; 1222141cc406Sopenharmony_ci } 1223141cc406Sopenharmony_ci 1224141cc406Sopenharmony_ci /* TODO: Any way to set PREVIEW??? */ 1225141cc406Sopenharmony_ci 1226141cc406Sopenharmony_ci /* Remaining bytes unused */ 1227141cc406Sopenharmony_ci status = cmd_set_scanning_parameters(s, 1228141cc406Sopenharmony_ci rs, mparam->flags, /* res, color mode */ 1229141cc406Sopenharmony_ci brightness, 0xff, /* brightness, contrast? */ 1230141cc406Sopenharmony_ci s->left, s->top, /* top/left start */ 1231141cc406Sopenharmony_ci s->width, s->height, /* extent */ 1232141cc406Sopenharmony_ci source); /* source */ 1233141cc406Sopenharmony_ci 1234141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1235141cc406Sopenharmony_ci DBG (2, "%s: Command cmd_set_scanning_parameters failed, %s\n", 1236141cc406Sopenharmony_ci __func__, sane_strstatus(status)); 1237141cc406Sopenharmony_ci 1238141cc406Sopenharmony_ci /* Now query the scanner for the current image parameters */ 1239141cc406Sopenharmony_ci status = cmd_get_scanning_parameters (s, 1240141cc406Sopenharmony_ci &s->params.format, &s->params.depth, 1241141cc406Sopenharmony_ci &scan_pixels_per_line, 1242141cc406Sopenharmony_ci &s->params.pixels_per_line, &s->params.lines); 1243141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1244141cc406Sopenharmony_ci DBG (2, "%s: Command cmd_get_scanning_parameters failed, %s\n", 1245141cc406Sopenharmony_ci __func__, sane_strstatus(status)); 1246141cc406Sopenharmony_ci return status; 1247141cc406Sopenharmony_ci } 1248141cc406Sopenharmony_ci 1249141cc406Sopenharmony_ci /* Calculate how many bytes are really used per line */ 1250141cc406Sopenharmony_ci s->params.bytes_per_line = ceil (s->params.pixels_per_line * s->params.depth / 8.0); 1251141cc406Sopenharmony_ci if (s->val[OPT_MODE].w == MODE_COLOR) 1252141cc406Sopenharmony_ci s->params.bytes_per_line *= 3; 1253141cc406Sopenharmony_ci 1254141cc406Sopenharmony_ci /* Calculate how many bytes per line will be returned by the scanner. 1255141cc406Sopenharmony_ci * The values needed for this are returned by get_scannign_parameters */ 1256141cc406Sopenharmony_ci s->scan_bytes_per_line = ceil (scan_pixels_per_line * s->params.depth / 8.0); 1257141cc406Sopenharmony_ci if (s->val[OPT_MODE].w == MODE_COLOR) { 1258141cc406Sopenharmony_ci s->scan_bytes_per_line *= 3; 1259141cc406Sopenharmony_ci } 1260141cc406Sopenharmony_ci s->data_len = s->params.lines * s->scan_bytes_per_line; 1261141cc406Sopenharmony_ci 1262141cc406Sopenharmony_ci status = mc_setup_block_mode (s); 1263141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1264141cc406Sopenharmony_ci DBG (2, "%s: Command mc_setup_block_mode failed, %s\n", 1265141cc406Sopenharmony_ci __func__, sane_strstatus(status)); 1266141cc406Sopenharmony_ci 1267141cc406Sopenharmony_ci DBG (1, "%s: bytes_read in line: %d\n", __func__, s->bytes_read_in_line); 1268141cc406Sopenharmony_ci 1269141cc406Sopenharmony_ci return status; 1270141cc406Sopenharmony_ci} 1271141cc406Sopenharmony_ci 1272141cc406Sopenharmony_cistatic SANE_Status 1273141cc406Sopenharmony_cimc_check_adf(Magicolor_Scanner * s) 1274141cc406Sopenharmony_ci{ 1275141cc406Sopenharmony_ci SANE_Status status; 1276141cc406Sopenharmony_ci unsigned char buf[0x0b]; 1277141cc406Sopenharmony_ci 1278141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 1279141cc406Sopenharmony_ci 1280141cc406Sopenharmony_ci status = cmd_request_status(s, buf); 1281141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1282141cc406Sopenharmony_ci return status; 1283141cc406Sopenharmony_ci 1284141cc406Sopenharmony_ci if (!(buf[1] & ADF_LOADED)) 1285141cc406Sopenharmony_ci return SANE_STATUS_NO_DOCS; 1286141cc406Sopenharmony_ci 1287141cc406Sopenharmony_ci /* TODO: Check for jam in ADF */ 1288141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1289141cc406Sopenharmony_ci} 1290141cc406Sopenharmony_ci 1291141cc406Sopenharmony_cistatic SANE_Status 1292141cc406Sopenharmony_cimc_scan_finish(Magicolor_Scanner * s) 1293141cc406Sopenharmony_ci{ 1294141cc406Sopenharmony_ci SANE_Status status; 1295141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 1296141cc406Sopenharmony_ci 1297141cc406Sopenharmony_ci /* If we have not yet read all data, cancel the scan */ 1298141cc406Sopenharmony_ci if (s->buf && !s->eof) 1299141cc406Sopenharmony_ci status = cmd_cancel_scan (s); 1300141cc406Sopenharmony_ci 1301141cc406Sopenharmony_ci if (s->line_buffer) 1302141cc406Sopenharmony_ci free (s->line_buffer); 1303141cc406Sopenharmony_ci s->line_buffer = NULL; 1304141cc406Sopenharmony_ci free(s->buf); 1305141cc406Sopenharmony_ci s->buf = s->end = s->ptr = NULL; 1306141cc406Sopenharmony_ci 1307141cc406Sopenharmony_ci /* TODO: Any magicolor command for "scan finished"? */ 1308141cc406Sopenharmony_ci status = cmd_finish_scan (s); 1309141cc406Sopenharmony_ci 1310141cc406Sopenharmony_ci status = cmd_request_error(s); 1311141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1312141cc406Sopenharmony_ci cmd_cancel_scan (s); 1313141cc406Sopenharmony_ci return status; 1314141cc406Sopenharmony_ci } 1315141cc406Sopenharmony_ci 1316141cc406Sopenharmony_ci /* XXX required? */ 1317141cc406Sopenharmony_ci /* TODO: cmd_reset(s);*/ 1318141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1319141cc406Sopenharmony_ci} 1320141cc406Sopenharmony_ci 1321141cc406Sopenharmony_cistatic void 1322141cc406Sopenharmony_cimc_copy_image_data(Magicolor_Scanner * s, SANE_Byte * data, SANE_Int max_length, 1323141cc406Sopenharmony_ci SANE_Int * length) 1324141cc406Sopenharmony_ci{ 1325141cc406Sopenharmony_ci DBG (1, "%s: bytes_read in line: %d\n", __func__, s->bytes_read_in_line); 1326141cc406Sopenharmony_ci if (s->params.format == SANE_FRAME_RGB) { 1327141cc406Sopenharmony_ci SANE_Int bytes_available, scan_pixels_per_line = s->scan_bytes_per_line/3; 1328141cc406Sopenharmony_ci *length = 0; 1329141cc406Sopenharmony_ci 1330141cc406Sopenharmony_ci while ((max_length >= s->params.bytes_per_line) && (s->ptr < s->end)) { 1331141cc406Sopenharmony_ci SANE_Int bytes_to_copy = s->scan_bytes_per_line - s->bytes_read_in_line; 1332141cc406Sopenharmony_ci /* First, fill the line buffer for the current line: */ 1333141cc406Sopenharmony_ci bytes_available = (s->end - s->ptr); 1334141cc406Sopenharmony_ci /* Don't copy more than we have buffer and available */ 1335141cc406Sopenharmony_ci if (bytes_to_copy > bytes_available) 1336141cc406Sopenharmony_ci bytes_to_copy = bytes_available; 1337141cc406Sopenharmony_ci 1338141cc406Sopenharmony_ci if (bytes_to_copy > 0) { 1339141cc406Sopenharmony_ci memcpy (s->line_buffer + s->bytes_read_in_line, s->ptr, bytes_to_copy); 1340141cc406Sopenharmony_ci s->ptr += bytes_to_copy; 1341141cc406Sopenharmony_ci s->bytes_read_in_line += bytes_to_copy; 1342141cc406Sopenharmony_ci } 1343141cc406Sopenharmony_ci 1344141cc406Sopenharmony_ci /* We have filled as much as possible of the current line 1345141cc406Sopenharmony_ci * with data from the scanner. If we have a complete line, 1346141cc406Sopenharmony_ci * copy it over. */ 1347141cc406Sopenharmony_ci if ((s->bytes_read_in_line >= s->scan_bytes_per_line) && 1348141cc406Sopenharmony_ci (s->params.bytes_per_line <= max_length)) 1349141cc406Sopenharmony_ci { 1350141cc406Sopenharmony_ci SANE_Int i; 1351141cc406Sopenharmony_ci SANE_Byte *line = s->line_buffer; 1352141cc406Sopenharmony_ci *length += s->params.bytes_per_line; 1353141cc406Sopenharmony_ci for (i=0; i< s->params.pixels_per_line; ++i) { 1354141cc406Sopenharmony_ci *data++ = line[0]; 1355141cc406Sopenharmony_ci *data++ = line[scan_pixels_per_line]; 1356141cc406Sopenharmony_ci *data++ = line[2 * scan_pixels_per_line]; 1357141cc406Sopenharmony_ci line++; 1358141cc406Sopenharmony_ci } 1359141cc406Sopenharmony_ci max_length -= s->params.bytes_per_line; 1360141cc406Sopenharmony_ci s->bytes_read_in_line -= s->scan_bytes_per_line; 1361141cc406Sopenharmony_ci } 1362141cc406Sopenharmony_ci } 1363141cc406Sopenharmony_ci 1364141cc406Sopenharmony_ci } else { 1365141cc406Sopenharmony_ci /* B/W and Grayscale use the same structure, so we use the same code */ 1366141cc406Sopenharmony_ci SANE_Int bytes_available; 1367141cc406Sopenharmony_ci *length = 0; 1368141cc406Sopenharmony_ci 1369141cc406Sopenharmony_ci while ((max_length != 0) && (s->ptr < s->end)) { 1370141cc406Sopenharmony_ci SANE_Int bytes_to_skip, bytes_to_copy; 1371141cc406Sopenharmony_ci bytes_available = (s->end - s->ptr); 1372141cc406Sopenharmony_ci bytes_to_copy = s->params.bytes_per_line - s->bytes_read_in_line; 1373141cc406Sopenharmony_ci bytes_to_skip = s->scan_bytes_per_line - s->bytes_read_in_line; 1374141cc406Sopenharmony_ci 1375141cc406Sopenharmony_ci /* Don't copy more than we have buffer */ 1376141cc406Sopenharmony_ci if (bytes_to_copy > max_length) { 1377141cc406Sopenharmony_ci bytes_to_copy = max_length; 1378141cc406Sopenharmony_ci bytes_to_skip = max_length; 1379141cc406Sopenharmony_ci } 1380141cc406Sopenharmony_ci 1381141cc406Sopenharmony_ci /* Don't copy/skip more bytes than we have read in */ 1382141cc406Sopenharmony_ci if (bytes_to_copy > bytes_available) 1383141cc406Sopenharmony_ci bytes_to_copy = bytes_available; 1384141cc406Sopenharmony_ci if (bytes_to_skip > bytes_available) 1385141cc406Sopenharmony_ci bytes_to_skip = bytes_available; 1386141cc406Sopenharmony_ci 1387141cc406Sopenharmony_ci if (bytes_to_copy > 0) { 1388141cc406Sopenharmony_ci /* we have not yet copied all pixels of the line */ 1389141cc406Sopenharmony_ci memcpy (data, s->ptr, bytes_to_copy); 1390141cc406Sopenharmony_ci max_length -= bytes_to_copy; 1391141cc406Sopenharmony_ci *length += bytes_to_copy; 1392141cc406Sopenharmony_ci data += bytes_to_copy; 1393141cc406Sopenharmony_ci } 1394141cc406Sopenharmony_ci if (bytes_to_skip > 0) { 1395141cc406Sopenharmony_ci s->ptr += bytes_to_skip; 1396141cc406Sopenharmony_ci s->bytes_read_in_line += bytes_to_skip; 1397141cc406Sopenharmony_ci } 1398141cc406Sopenharmony_ci if (s->bytes_read_in_line >= s->scan_bytes_per_line) 1399141cc406Sopenharmony_ci s->bytes_read_in_line -= s->scan_bytes_per_line; 1400141cc406Sopenharmony_ci 1401141cc406Sopenharmony_ci } 1402141cc406Sopenharmony_ci } 1403141cc406Sopenharmony_ci} 1404141cc406Sopenharmony_ci 1405141cc406Sopenharmony_cistatic SANE_Status 1406141cc406Sopenharmony_cimc_init_parameters(Magicolor_Scanner * s) 1407141cc406Sopenharmony_ci{ 1408141cc406Sopenharmony_ci int dpi, optres; 1409141cc406Sopenharmony_ci 1410141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 1411141cc406Sopenharmony_ci 1412141cc406Sopenharmony_ci memset(&s->params, 0, sizeof(SANE_Parameters)); 1413141cc406Sopenharmony_ci 1414141cc406Sopenharmony_ci dpi = s->val[OPT_RESOLUTION].w; 1415141cc406Sopenharmony_ci optres = s->hw->cap->optical_res; 1416141cc406Sopenharmony_ci 1417141cc406Sopenharmony_ci if (SANE_UNFIX(s->val[OPT_BR_Y].w) == 0 || 1418141cc406Sopenharmony_ci SANE_UNFIX(s->val[OPT_BR_X].w) == 0) 1419141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1420141cc406Sopenharmony_ci 1421141cc406Sopenharmony_ci /* TODO: Use OPT_RESOLUTION or fixed 600dpi for left/top/width/height? */ 1422141cc406Sopenharmony_ci s->left = ((SANE_UNFIX(s->val[OPT_TL_X].w) / MM_PER_INCH) * optres) + 0.5; 1423141cc406Sopenharmony_ci 1424141cc406Sopenharmony_ci s->top = ((SANE_UNFIX(s->val[OPT_TL_Y].w) / MM_PER_INCH) * optres) + 0.5; 1425141cc406Sopenharmony_ci 1426141cc406Sopenharmony_ci s->width = 1427141cc406Sopenharmony_ci ((SANE_UNFIX(s->val[OPT_BR_X].w - 1428141cc406Sopenharmony_ci s->val[OPT_TL_X].w) / MM_PER_INCH) * optres) + 0.5; 1429141cc406Sopenharmony_ci 1430141cc406Sopenharmony_ci s->height = 1431141cc406Sopenharmony_ci ((SANE_UNFIX(s->val[OPT_BR_Y].w - 1432141cc406Sopenharmony_ci s->val[OPT_TL_Y].w) / MM_PER_INCH) * optres) + 0.5; 1433141cc406Sopenharmony_ci 1434141cc406Sopenharmony_ci s->params.pixels_per_line = s->width * dpi / optres + 0.5; 1435141cc406Sopenharmony_ci s->params.lines = s->height * dpi / optres + 0.5; 1436141cc406Sopenharmony_ci 1437141cc406Sopenharmony_ci 1438141cc406Sopenharmony_ci DBG(1, "%s: resolution = %d, preview = %d\n", 1439141cc406Sopenharmony_ci __func__, dpi, s->val[OPT_PREVIEW].w); 1440141cc406Sopenharmony_ci 1441141cc406Sopenharmony_ci DBG(1, "%s: %p %p tlx %f tly %f brx %f bry %f [mm]\n", 1442141cc406Sopenharmony_ci __func__, (void *) s, (void *) s->val, 1443141cc406Sopenharmony_ci SANE_UNFIX(s->val[OPT_TL_X].w), SANE_UNFIX(s->val[OPT_TL_Y].w), 1444141cc406Sopenharmony_ci SANE_UNFIX(s->val[OPT_BR_X].w), SANE_UNFIX(s->val[OPT_BR_Y].w)); 1445141cc406Sopenharmony_ci 1446141cc406Sopenharmony_ci /* 1447141cc406Sopenharmony_ci * The default color depth is stored in mode_params.depth: 1448141cc406Sopenharmony_ci */ 1449141cc406Sopenharmony_ci DBG(1, " %s, vor depth\n", __func__); 1450141cc406Sopenharmony_ci 1451141cc406Sopenharmony_ci if (mode_params[s->val[OPT_MODE].w].depth == 1) 1452141cc406Sopenharmony_ci s->params.depth = 1; 1453141cc406Sopenharmony_ci else 1454141cc406Sopenharmony_ci s->params.depth = s->val[OPT_BIT_DEPTH].w; 1455141cc406Sopenharmony_ci 1456141cc406Sopenharmony_ci s->params.last_frame = SANE_TRUE; 1457141cc406Sopenharmony_ci 1458141cc406Sopenharmony_ci s->params.bytes_per_line = ceil (s->params.depth * s->params.pixels_per_line / 8.0); 1459141cc406Sopenharmony_ci 1460141cc406Sopenharmony_ci switch (s->val[OPT_MODE].w) { 1461141cc406Sopenharmony_ci case MODE_BINARY: 1462141cc406Sopenharmony_ci case MODE_GRAY: 1463141cc406Sopenharmony_ci s->params.format = SANE_FRAME_GRAY; 1464141cc406Sopenharmony_ci break; 1465141cc406Sopenharmony_ci case MODE_COLOR: 1466141cc406Sopenharmony_ci s->params.format = SANE_FRAME_RGB; 1467141cc406Sopenharmony_ci s->params.bytes_per_line *= 3; 1468141cc406Sopenharmony_ci break; 1469141cc406Sopenharmony_ci } 1470141cc406Sopenharmony_ci 1471141cc406Sopenharmony_ci 1472141cc406Sopenharmony_ci DBG(1, "%s: Parameters are format=%d, bytes_per_line=%d, lines=%d\n", __func__, s->params.format, s->params.bytes_per_line, s->params.lines); 1473141cc406Sopenharmony_ci return (s->params.lines > 0) ? SANE_STATUS_GOOD : SANE_STATUS_INVAL; 1474141cc406Sopenharmony_ci} 1475141cc406Sopenharmony_ci 1476141cc406Sopenharmony_cistatic SANE_Status 1477141cc406Sopenharmony_cimc_start_scan(Magicolor_Scanner * s) 1478141cc406Sopenharmony_ci{ 1479141cc406Sopenharmony_ci SANE_Status status = cmd_start_scan (s, s->data_len); 1480141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD ) { 1481141cc406Sopenharmony_ci DBG (1, "%s: starting the scan failed (%s)\n", __func__, sane_strstatus(status)); 1482141cc406Sopenharmony_ci } 1483141cc406Sopenharmony_ci return status; 1484141cc406Sopenharmony_ci} 1485141cc406Sopenharmony_ci 1486141cc406Sopenharmony_cistatic SANE_Status 1487141cc406Sopenharmony_cimc_read(struct Magicolor_Scanner *s) 1488141cc406Sopenharmony_ci{ 1489141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 1490141cc406Sopenharmony_ci ssize_t buf_len = 0; 1491141cc406Sopenharmony_ci 1492141cc406Sopenharmony_ci /* did we passed everything we read to sane? */ 1493141cc406Sopenharmony_ci if (s->ptr == s->end) { 1494141cc406Sopenharmony_ci 1495141cc406Sopenharmony_ci if (s->eof) 1496141cc406Sopenharmony_ci return SANE_STATUS_EOF; 1497141cc406Sopenharmony_ci 1498141cc406Sopenharmony_ci s->counter++; 1499141cc406Sopenharmony_ci buf_len = s->block_len; 1500141cc406Sopenharmony_ci 1501141cc406Sopenharmony_ci if (s->counter == s->blocks && s->last_len) 1502141cc406Sopenharmony_ci buf_len = s->last_len; 1503141cc406Sopenharmony_ci 1504141cc406Sopenharmony_ci DBG(18, "%s: block %d/%d, size %lu\n", __func__, 1505141cc406Sopenharmony_ci s->counter, s->blocks, 1506141cc406Sopenharmony_ci (unsigned long) buf_len); 1507141cc406Sopenharmony_ci 1508141cc406Sopenharmony_ci /* receive image data + error code */ 1509141cc406Sopenharmony_ci status = cmd_read_data (s, s->buf, buf_len); 1510141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1511141cc406Sopenharmony_ci DBG (1, "%s: Receiving image data failed (%s)\n", 1512141cc406Sopenharmony_ci __func__, sane_strstatus(status)); 1513141cc406Sopenharmony_ci cmd_cancel_scan(s); 1514141cc406Sopenharmony_ci return status; 1515141cc406Sopenharmony_ci } 1516141cc406Sopenharmony_ci 1517141cc406Sopenharmony_ci DBG(18, "%s: successfully read %lu bytes\n", __func__, (unsigned long) buf_len); 1518141cc406Sopenharmony_ci 1519141cc406Sopenharmony_ci if (s->counter < s->blocks) { 1520141cc406Sopenharmony_ci if (s->canceling) { 1521141cc406Sopenharmony_ci cmd_cancel_scan(s); 1522141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1523141cc406Sopenharmony_ci } 1524141cc406Sopenharmony_ci } else 1525141cc406Sopenharmony_ci s->eof = SANE_TRUE; 1526141cc406Sopenharmony_ci 1527141cc406Sopenharmony_ci s->end = s->buf + buf_len; 1528141cc406Sopenharmony_ci s->ptr = s->buf; 1529141cc406Sopenharmony_ci } 1530141cc406Sopenharmony_ci 1531141cc406Sopenharmony_ci return status; 1532141cc406Sopenharmony_ci} 1533141cc406Sopenharmony_ci 1534141cc406Sopenharmony_ci 1535141cc406Sopenharmony_ci 1536141cc406Sopenharmony_ci 1537141cc406Sopenharmony_ci/**************************************************************************** 1538141cc406Sopenharmony_ci * SANE API implementation (high-level functions) 1539141cc406Sopenharmony_ci ****************************************************************************/ 1540141cc406Sopenharmony_ci 1541141cc406Sopenharmony_ci 1542141cc406Sopenharmony_ci#if HAVE_LIBSNMP 1543141cc406Sopenharmony_cistatic struct MagicolorCap * 1544141cc406Sopenharmony_cimc_get_device_from_identification (const char*ident) 1545141cc406Sopenharmony_ci{ 1546141cc406Sopenharmony_ci int n; 1547141cc406Sopenharmony_ci for (n = 0; n < NELEMS (magicolor_cap); n++) { 1548141cc406Sopenharmony_ci if ((strcmp (magicolor_cap[n].model, ident) == 0) || (strcmp (magicolor_cap[n].OID, ident) == 0)) 1549141cc406Sopenharmony_ci { 1550141cc406Sopenharmony_ci return &magicolor_cap[n]; 1551141cc406Sopenharmony_ci } 1552141cc406Sopenharmony_ci } 1553141cc406Sopenharmony_ci return NULL; 1554141cc406Sopenharmony_ci} 1555141cc406Sopenharmony_ci#endif 1556141cc406Sopenharmony_ci 1557141cc406Sopenharmony_ci 1558141cc406Sopenharmony_ci/* 1559141cc406Sopenharmony_ci * close_scanner() 1560141cc406Sopenharmony_ci * 1561141cc406Sopenharmony_ci * Close the open scanner. Depending on the connection method, a different 1562141cc406Sopenharmony_ci * close function is called. 1563141cc406Sopenharmony_ci */ 1564141cc406Sopenharmony_cistatic void 1565141cc406Sopenharmony_ciclose_scanner(Magicolor_Scanner *s) 1566141cc406Sopenharmony_ci{ 1567141cc406Sopenharmony_ci DBG(7, "%s: fd = %d\n", __func__, s->fd); 1568141cc406Sopenharmony_ci 1569141cc406Sopenharmony_ci if (s->fd == -1) 1570141cc406Sopenharmony_ci return; 1571141cc406Sopenharmony_ci 1572141cc406Sopenharmony_ci mc_scan_finish(s); 1573141cc406Sopenharmony_ci if (s->hw->connection == SANE_MAGICOLOR_NET) { 1574141cc406Sopenharmony_ci sanei_magicolor_net_close(s); 1575141cc406Sopenharmony_ci sanei_tcp_close(s->fd); 1576141cc406Sopenharmony_ci } else if (s->hw->connection == SANE_MAGICOLOR_USB) { 1577141cc406Sopenharmony_ci sanei_usb_close(s->fd); 1578141cc406Sopenharmony_ci } 1579141cc406Sopenharmony_ci 1580141cc406Sopenharmony_ci s->fd = -1; 1581141cc406Sopenharmony_ci} 1582141cc406Sopenharmony_ci 1583141cc406Sopenharmony_cistatic SANE_Bool 1584141cc406Sopenharmony_cisplit_scanner_name (const char *name, char * IP, unsigned int *model) 1585141cc406Sopenharmony_ci{ 1586141cc406Sopenharmony_ci const char *device = name; 1587141cc406Sopenharmony_ci const char *qm; 1588141cc406Sopenharmony_ci *model = 0; 1589141cc406Sopenharmony_ci /* cut off leading net: */ 1590141cc406Sopenharmony_ci if (strncmp(device, "net:", 4) == 0) 1591141cc406Sopenharmony_ci device = &device[4]; 1592141cc406Sopenharmony_ci 1593141cc406Sopenharmony_ci qm = strchr(device, '?'); 1594141cc406Sopenharmony_ci if (qm != NULL) { 1595141cc406Sopenharmony_ci size_t len = qm-device; 1596141cc406Sopenharmony_ci strncpy (IP, device, len); 1597141cc406Sopenharmony_ci IP[len] = '\0'; 1598141cc406Sopenharmony_ci qm++; 1599141cc406Sopenharmony_ci if (strncmp(qm, "model=", 6) == 0) { 1600141cc406Sopenharmony_ci qm += 6; 1601141cc406Sopenharmony_ci if (!sscanf(qm, "0x%x", model)) 1602141cc406Sopenharmony_ci sscanf(qm, "%x", model); 1603141cc406Sopenharmony_ci } 1604141cc406Sopenharmony_ci } else { 1605141cc406Sopenharmony_ci strcpy (IP, device); 1606141cc406Sopenharmony_ci } 1607141cc406Sopenharmony_ci return SANE_TRUE; 1608141cc406Sopenharmony_ci} 1609141cc406Sopenharmony_ci 1610141cc406Sopenharmony_ci/* 1611141cc406Sopenharmony_ci * open_scanner() 1612141cc406Sopenharmony_ci * 1613141cc406Sopenharmony_ci * Open the scanner device. Depending on the connection method, 1614141cc406Sopenharmony_ci * different open functions are called. 1615141cc406Sopenharmony_ci */ 1616141cc406Sopenharmony_ci 1617141cc406Sopenharmony_cistatic SANE_Status 1618141cc406Sopenharmony_ciopen_scanner(Magicolor_Scanner *s) 1619141cc406Sopenharmony_ci{ 1620141cc406Sopenharmony_ci SANE_Status status = 0; 1621141cc406Sopenharmony_ci 1622141cc406Sopenharmony_ci DBG(7, "%s: %s\n", __func__, s->hw->sane.name); 1623141cc406Sopenharmony_ci 1624141cc406Sopenharmony_ci if (s->fd != -1) { 1625141cc406Sopenharmony_ci DBG(7, "scanner is already open: fd = %d\n", s->fd); 1626141cc406Sopenharmony_ci return SANE_STATUS_GOOD; /* no need to open the scanner */ 1627141cc406Sopenharmony_ci } 1628141cc406Sopenharmony_ci 1629141cc406Sopenharmony_ci if (s->hw->connection == SANE_MAGICOLOR_NET) { 1630141cc406Sopenharmony_ci /* device name has the form net:ipaddr?model=... */ 1631141cc406Sopenharmony_ci char IP[1024]; 1632141cc406Sopenharmony_ci unsigned int model = 0; 1633141cc406Sopenharmony_ci if (!split_scanner_name (s->hw->sane.name, IP, &model)) 1634141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1635141cc406Sopenharmony_ci status = sanei_tcp_open(IP, 4567, &s->fd); 1636141cc406Sopenharmony_ci if (model>0) 1637141cc406Sopenharmony_ci mc_set_device (s, model); 1638141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) { 1639141cc406Sopenharmony_ci DBG(7, "awaiting welcome message\n"); 1640141cc406Sopenharmony_ci status = sanei_magicolor_net_open (s); 1641141cc406Sopenharmony_ci } 1642141cc406Sopenharmony_ci 1643141cc406Sopenharmony_ci } else if (s->hw->connection == SANE_MAGICOLOR_USB) { 1644141cc406Sopenharmony_ci status = sanei_usb_open(s->hw->sane.name, &s->fd); 1645141cc406Sopenharmony_ci if (s->hw->cap->out_ep>0) 1646141cc406Sopenharmony_ci sanei_usb_set_endpoint (s->fd, 1647141cc406Sopenharmony_ci USB_DIR_OUT | USB_ENDPOINT_TYPE_BULK, s->hw->cap->out_ep); 1648141cc406Sopenharmony_ci if (s->hw->cap->in_ep>0) 1649141cc406Sopenharmony_ci sanei_usb_set_endpoint (s->fd, 1650141cc406Sopenharmony_ci USB_DIR_IN | USB_ENDPOINT_TYPE_BULK, s->hw->cap->in_ep); 1651141cc406Sopenharmony_ci } 1652141cc406Sopenharmony_ci 1653141cc406Sopenharmony_ci if (status == SANE_STATUS_ACCESS_DENIED) { 1654141cc406Sopenharmony_ci DBG(1, "please check that you have permissions on the device.\n"); 1655141cc406Sopenharmony_ci DBG(1, "if this is a multi-function device with a printer,\n"); 1656141cc406Sopenharmony_ci DBG(1, "disable any conflicting driver (like usblp).\n"); 1657141cc406Sopenharmony_ci } 1658141cc406Sopenharmony_ci 1659141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1660141cc406Sopenharmony_ci DBG(1, "%s open failed: %s\n", s->hw->sane.name, 1661141cc406Sopenharmony_ci sane_strstatus(status)); 1662141cc406Sopenharmony_ci else 1663141cc406Sopenharmony_ci DBG(3, "scanner opened\n"); 1664141cc406Sopenharmony_ci 1665141cc406Sopenharmony_ci return status; 1666141cc406Sopenharmony_ci} 1667141cc406Sopenharmony_ci 1668141cc406Sopenharmony_cistatic SANE_Status 1669141cc406Sopenharmony_cidetect_usb(struct Magicolor_Scanner *s) 1670141cc406Sopenharmony_ci{ 1671141cc406Sopenharmony_ci SANE_Status status; 1672141cc406Sopenharmony_ci int vendor, product; 1673141cc406Sopenharmony_ci int i, numIds; 1674141cc406Sopenharmony_ci SANE_Bool is_valid; 1675141cc406Sopenharmony_ci 1676141cc406Sopenharmony_ci /* if the sanei_usb_get_vendor_product call is not supported, 1677141cc406Sopenharmony_ci * then we just ignore this and rely on the user to config 1678141cc406Sopenharmony_ci * the correct device. 1679141cc406Sopenharmony_ci */ 1680141cc406Sopenharmony_ci 1681141cc406Sopenharmony_ci status = sanei_usb_get_vendor_product(s->fd, &vendor, &product); 1682141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1683141cc406Sopenharmony_ci DBG(1, "the device cannot be verified - will continue\n"); 1684141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1685141cc406Sopenharmony_ci } 1686141cc406Sopenharmony_ci 1687141cc406Sopenharmony_ci /* check the vendor ID to see if we are dealing with an MAGICOLOR device */ 1688141cc406Sopenharmony_ci if (vendor != SANE_MAGICOLOR_VENDOR_ID) { 1689141cc406Sopenharmony_ci /* this is not a supported vendor ID */ 1690141cc406Sopenharmony_ci DBG(1, "not an Magicolor device at %s (vendor id=0x%x)\n", 1691141cc406Sopenharmony_ci s->hw->sane.name, vendor); 1692141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1693141cc406Sopenharmony_ci } 1694141cc406Sopenharmony_ci 1695141cc406Sopenharmony_ci numIds = sanei_magicolor_getNumberOfUSBProductIds(); 1696141cc406Sopenharmony_ci is_valid = SANE_FALSE; 1697141cc406Sopenharmony_ci i = 0; 1698141cc406Sopenharmony_ci 1699141cc406Sopenharmony_ci /* check all known product IDs to verify that we know 1700141cc406Sopenharmony_ci * about the device */ 1701141cc406Sopenharmony_ci while (i != numIds && !is_valid) { 1702141cc406Sopenharmony_ci if (product == sanei_magicolor_usb_product_ids[i]) 1703141cc406Sopenharmony_ci is_valid = SANE_TRUE; 1704141cc406Sopenharmony_ci i++; 1705141cc406Sopenharmony_ci } 1706141cc406Sopenharmony_ci 1707141cc406Sopenharmony_ci if (is_valid == SANE_FALSE) { 1708141cc406Sopenharmony_ci DBG(1, "the device at %s is not a supported (product id=0x%x)\n", 1709141cc406Sopenharmony_ci s->hw->sane.name, product); 1710141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1711141cc406Sopenharmony_ci } 1712141cc406Sopenharmony_ci 1713141cc406Sopenharmony_ci DBG(2, "found valid Magicolor scanner: 0x%x/0x%x (vendorID/productID)\n", 1714141cc406Sopenharmony_ci vendor, product); 1715141cc406Sopenharmony_ci mc_set_device(s, product); 1716141cc406Sopenharmony_ci 1717141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1718141cc406Sopenharmony_ci} 1719141cc406Sopenharmony_ci 1720141cc406Sopenharmony_ci/* 1721141cc406Sopenharmony_ci * used by attach* and sane_get_devices 1722141cc406Sopenharmony_ci * a ptr to a single-linked list of Magicolor_Device structs 1723141cc406Sopenharmony_ci * a ptr to a null term array of ptrs to SANE_Device structs 1724141cc406Sopenharmony_ci */ 1725141cc406Sopenharmony_cistatic int num_devices; /* number of scanners attached to backend */ 1726141cc406Sopenharmony_cistatic Magicolor_Device *first_dev; /* first MAGICOLOR scanner in list */ 1727141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL; 1728141cc406Sopenharmony_ci 1729141cc406Sopenharmony_cistatic struct Magicolor_Scanner * 1730141cc406Sopenharmony_ciscanner_create(struct Magicolor_Device *dev, SANE_Status *status) 1731141cc406Sopenharmony_ci{ 1732141cc406Sopenharmony_ci struct Magicolor_Scanner *s; 1733141cc406Sopenharmony_ci 1734141cc406Sopenharmony_ci s = malloc(sizeof(struct Magicolor_Scanner)); 1735141cc406Sopenharmony_ci if (s == NULL) { 1736141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 1737141cc406Sopenharmony_ci return NULL; 1738141cc406Sopenharmony_ci } 1739141cc406Sopenharmony_ci 1740141cc406Sopenharmony_ci memset(s, 0x00, sizeof(struct Magicolor_Scanner)); 1741141cc406Sopenharmony_ci 1742141cc406Sopenharmony_ci s->fd = -1; 1743141cc406Sopenharmony_ci s->hw = dev; 1744141cc406Sopenharmony_ci 1745141cc406Sopenharmony_ci return s; 1746141cc406Sopenharmony_ci} 1747141cc406Sopenharmony_ci 1748141cc406Sopenharmony_cistatic struct Magicolor_Scanner * 1749141cc406Sopenharmony_cidevice_detect(const char *name, int type, SANE_Status *status) 1750141cc406Sopenharmony_ci{ 1751141cc406Sopenharmony_ci struct Magicolor_Scanner *s; 1752141cc406Sopenharmony_ci struct Magicolor_Device *dev; 1753141cc406Sopenharmony_ci 1754141cc406Sopenharmony_ci /* try to find the device in our list */ 1755141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) { 1756141cc406Sopenharmony_ci if (strcmp(dev->sane.name, name) == 0) { 1757141cc406Sopenharmony_ci dev->missing = 0; 1758141cc406Sopenharmony_ci DBG (10, "%s: Device %s already attached!\n", __func__, 1759141cc406Sopenharmony_ci name); 1760141cc406Sopenharmony_ci return scanner_create(dev, status); 1761141cc406Sopenharmony_ci } 1762141cc406Sopenharmony_ci } 1763141cc406Sopenharmony_ci 1764141cc406Sopenharmony_ci if (type == SANE_MAGICOLOR_NODEV) { 1765141cc406Sopenharmony_ci *status = SANE_STATUS_INVAL; 1766141cc406Sopenharmony_ci return NULL; 1767141cc406Sopenharmony_ci } 1768141cc406Sopenharmony_ci 1769141cc406Sopenharmony_ci /* alloc and clear our device structure */ 1770141cc406Sopenharmony_ci dev = malloc(sizeof(*dev)); 1771141cc406Sopenharmony_ci if (!dev) { 1772141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 1773141cc406Sopenharmony_ci return NULL; 1774141cc406Sopenharmony_ci } 1775141cc406Sopenharmony_ci memset(dev, 0x00, sizeof(struct Magicolor_Device)); 1776141cc406Sopenharmony_ci 1777141cc406Sopenharmony_ci s = scanner_create(dev, status); 1778141cc406Sopenharmony_ci if (s == NULL) 1779141cc406Sopenharmony_ci return NULL; 1780141cc406Sopenharmony_ci 1781141cc406Sopenharmony_ci mc_dev_init(dev, name, type); 1782141cc406Sopenharmony_ci 1783141cc406Sopenharmony_ci *status = open_scanner(s); 1784141cc406Sopenharmony_ci if (*status != SANE_STATUS_GOOD) { 1785141cc406Sopenharmony_ci free(s); 1786141cc406Sopenharmony_ci return NULL; 1787141cc406Sopenharmony_ci } 1788141cc406Sopenharmony_ci 1789141cc406Sopenharmony_ci /* from now on, close_scanner() must be called */ 1790141cc406Sopenharmony_ci 1791141cc406Sopenharmony_ci /* USB requires special care */ 1792141cc406Sopenharmony_ci if (dev->connection == SANE_MAGICOLOR_USB) { 1793141cc406Sopenharmony_ci *status = detect_usb(s); 1794141cc406Sopenharmony_ci } 1795141cc406Sopenharmony_ci 1796141cc406Sopenharmony_ci if (*status != SANE_STATUS_GOOD) 1797141cc406Sopenharmony_ci goto close; 1798141cc406Sopenharmony_ci 1799141cc406Sopenharmony_ci /* set name and model (if not already set) */ 1800141cc406Sopenharmony_ci if (dev->model == NULL) 1801141cc406Sopenharmony_ci mc_set_model(s, "generic", 7); 1802141cc406Sopenharmony_ci 1803141cc406Sopenharmony_ci dev->name = strdup(name); 1804141cc406Sopenharmony_ci dev->sane.name = dev->name; 1805141cc406Sopenharmony_ci 1806141cc406Sopenharmony_ci *status = mc_discover_capabilities(s); 1807141cc406Sopenharmony_ci if (*status != SANE_STATUS_GOOD) 1808141cc406Sopenharmony_ci goto close; 1809141cc406Sopenharmony_ci 1810141cc406Sopenharmony_ci if (source_list[0] == NULL || dev->cap->dpi_range.min == 0) { 1811141cc406Sopenharmony_ci DBG(1, "something is wrong in the discovery process, aborting.\n"); 1812141cc406Sopenharmony_ci *status = SANE_STATUS_IO_ERROR; 1813141cc406Sopenharmony_ci goto close; 1814141cc406Sopenharmony_ci } 1815141cc406Sopenharmony_ci 1816141cc406Sopenharmony_ci mc_dev_post_init(dev); 1817141cc406Sopenharmony_ci 1818141cc406Sopenharmony_ci /* add this scanner to the device list */ 1819141cc406Sopenharmony_ci num_devices++; 1820141cc406Sopenharmony_ci dev->missing = 0; 1821141cc406Sopenharmony_ci dev->next = first_dev; 1822141cc406Sopenharmony_ci first_dev = dev; 1823141cc406Sopenharmony_ci 1824141cc406Sopenharmony_ci return s; 1825141cc406Sopenharmony_ci 1826141cc406Sopenharmony_ci close: 1827141cc406Sopenharmony_ci close_scanner(s); 1828141cc406Sopenharmony_ci free(s); 1829141cc406Sopenharmony_ci return NULL; 1830141cc406Sopenharmony_ci} 1831141cc406Sopenharmony_ci 1832141cc406Sopenharmony_ci#if HAVE_LIBSNMP 1833141cc406Sopenharmony_ci 1834141cc406Sopenharmony_ci/* Keep a linked list of already observed IP addresses */ 1835141cc406Sopenharmony_ci/* typedef struct snmp_ip SNMP_IP; */ 1836141cc406Sopenharmony_citypedef struct snmp_ip { 1837141cc406Sopenharmony_ci char ip_addr[1024]; 1838141cc406Sopenharmony_ci struct snmp_ip*next; 1839141cc406Sopenharmony_ci} snmp_ip; 1840141cc406Sopenharmony_ci 1841141cc406Sopenharmony_citypedef struct { 1842141cc406Sopenharmony_ci int nr; 1843141cc406Sopenharmony_ci snmp_ip*handled; 1844141cc406Sopenharmony_ci snmp_ip*detected; 1845141cc406Sopenharmony_ci} snmp_discovery_data; 1846141cc406Sopenharmony_ci 1847141cc406Sopenharmony_ci 1848141cc406Sopenharmony_ci/** Handle one SNMP response (whether received sync or async) and if describes 1849141cc406Sopenharmony_ci * a magicolor device, attach it. Returns the number of attached devices (0 1850141cc406Sopenharmony_ci * or 1) */ 1851141cc406Sopenharmony_cistatic int 1852141cc406Sopenharmony_cimc_network_discovery_handle (struct snmp_pdu *pdu, snmp_discovery_data *magic) 1853141cc406Sopenharmony_ci{ 1854141cc406Sopenharmony_ci netsnmp_variable_list *varlist = pdu->variables, *vp; 1855141cc406Sopenharmony_ci oid anOID[MAX_OID_LEN]; 1856141cc406Sopenharmony_ci size_t anOID_len = MAX_OID_LEN; 1857141cc406Sopenharmony_ci /* Device information variables */ 1858141cc406Sopenharmony_ci char ip_addr[1024] = ""; 1859141cc406Sopenharmony_ci char model[1024] = ""; 1860141cc406Sopenharmony_ci char device[1024] = ""; 1861141cc406Sopenharmony_ci /* remote IP detection variables */ 1862141cc406Sopenharmony_ci netsnmp_indexed_addr_pair *responder = (netsnmp_indexed_addr_pair *) pdu->transport_data; 1863141cc406Sopenharmony_ci struct sockaddr_in *remote = NULL; 1864141cc406Sopenharmony_ci struct MagicolorCap *cap; 1865141cc406Sopenharmony_ci snmp_ip *ip = NULL; 1866141cc406Sopenharmony_ci 1867141cc406Sopenharmony_ci DBG(5, "%s: Handling SNMP response \n", __func__); 1868141cc406Sopenharmony_ci 1869141cc406Sopenharmony_ci if (responder == NULL || pdu->transport_data_length != sizeof(netsnmp_indexed_addr_pair )) { 1870141cc406Sopenharmony_ci DBG(1, "%s: Unable to extract IP address from SNMP response.\n", 1871141cc406Sopenharmony_ci __func__); 1872141cc406Sopenharmony_ci return 0; 1873141cc406Sopenharmony_ci } 1874141cc406Sopenharmony_ci remote = (struct sockaddr_in *) &(responder->remote_addr); 1875141cc406Sopenharmony_ci if (remote == NULL) { 1876141cc406Sopenharmony_ci DBG(1, "%s: Unable to extract IP address from SNMP response.\n", 1877141cc406Sopenharmony_ci __func__); 1878141cc406Sopenharmony_ci return 0; 1879141cc406Sopenharmony_ci } 1880141cc406Sopenharmony_ci snprintf(ip_addr, sizeof(ip_addr), "%s", inet_ntoa(remote->sin_addr)); 1881141cc406Sopenharmony_ci DBG(35, "%s: IP Address of responder is %s\n", __func__, ip_addr); 1882141cc406Sopenharmony_ci if (magic) 1883141cc406Sopenharmony_ci ip = magic->handled; 1884141cc406Sopenharmony_ci while (ip) { 1885141cc406Sopenharmony_ci if (strcmp (ip->ip_addr, ip_addr) == 0) { 1886141cc406Sopenharmony_ci DBG (5, "%s: Already handled device %s, skipping\n", __func__, ip_addr); 1887141cc406Sopenharmony_ci return 0; 1888141cc406Sopenharmony_ci } 1889141cc406Sopenharmony_ci ip = ip->next; 1890141cc406Sopenharmony_ci } 1891141cc406Sopenharmony_ci if (magic) { 1892141cc406Sopenharmony_ci snmp_ip *new_handled = malloc(sizeof(snmp_ip)); 1893141cc406Sopenharmony_ci strcpy (&new_handled->ip_addr[0], ip_addr); 1894141cc406Sopenharmony_ci new_handled->next = magic->handled; 1895141cc406Sopenharmony_ci magic->handled = new_handled; 1896141cc406Sopenharmony_ci } 1897141cc406Sopenharmony_ci 1898141cc406Sopenharmony_ci /* System Object ID (Unique OID identifying model) 1899141cc406Sopenharmony_ci * This determines whether we really have a magicolor device */ 1900141cc406Sopenharmony_ci anOID_len = MAX_OID_LEN; 1901141cc406Sopenharmony_ci read_objid(MAGICOLOR_SNMP_SYSOBJECT_OID, anOID, &anOID_len); 1902141cc406Sopenharmony_ci vp = find_varbind_in_list (varlist, anOID, anOID_len); 1903141cc406Sopenharmony_ci if (vp) { 1904141cc406Sopenharmony_ci size_t value_len = vp->val_len/sizeof(oid); 1905141cc406Sopenharmony_ci if (vp->type != ASN_OBJECT_ID) { 1906141cc406Sopenharmony_ci DBG (3, "%s: SystemObjectID does not return an OID, device is not a magicolor device\n", __func__); 1907141cc406Sopenharmony_ci return 0; 1908141cc406Sopenharmony_ci } 1909141cc406Sopenharmony_ci 1910141cc406Sopenharmony_ci // Make sure that snprint_objid gives us just numbers, instead of a 1911141cc406Sopenharmony_ci // SNMPv2-SMI::enterprises prefix. 1912141cc406Sopenharmony_ci netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 1913141cc406Sopenharmony_ci NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, 1914141cc406Sopenharmony_ci NETSNMP_OID_OUTPUT_NUMERIC); 1915141cc406Sopenharmony_ci 1916141cc406Sopenharmony_ci snprint_objid (device, sizeof(device), vp->val.objid, value_len); 1917141cc406Sopenharmony_ci DBG (5, "%s: Device object ID is '%s'\n", __func__, device); 1918141cc406Sopenharmony_ci 1919141cc406Sopenharmony_ci anOID_len = MAX_OID_LEN; 1920141cc406Sopenharmony_ci read_objid (MAGICOLOR_SNMP_DEVICE_TREE, anOID, &anOID_len); 1921141cc406Sopenharmony_ci if (netsnmp_oid_is_subtree (anOID, anOID_len, 1922141cc406Sopenharmony_ci vp->val.objid, value_len) == 0) { 1923141cc406Sopenharmony_ci DBG (5, "%s: Device appears to be a magicolor device (OID=%s)\n", __func__, device); 1924141cc406Sopenharmony_ci } else { 1925141cc406Sopenharmony_ci DBG (5, "%s: Device is not a Magicolor device\n", __func__); 1926141cc406Sopenharmony_ci return 0; 1927141cc406Sopenharmony_ci } 1928141cc406Sopenharmony_ci } 1929141cc406Sopenharmony_ci 1930141cc406Sopenharmony_ci /* Retrieve sysDescr (i.e. model name) */ 1931141cc406Sopenharmony_ci anOID_len = MAX_OID_LEN; 1932141cc406Sopenharmony_ci read_objid(MAGICOLOR_SNMP_SYSDESCR_OID, anOID, &anOID_len); 1933141cc406Sopenharmony_ci vp = find_varbind_in_list (varlist, anOID, anOID_len); 1934141cc406Sopenharmony_ci if (vp) { 1935141cc406Sopenharmony_ci size_t model_len = min(vp->val_len, sizeof(model) - 1); 1936141cc406Sopenharmony_ci memcpy(model, vp->val.string, model_len); 1937141cc406Sopenharmony_ci model[model_len] = '\0'; 1938141cc406Sopenharmony_ci DBG (5, "%s: Found model: %s\n", __func__, model); 1939141cc406Sopenharmony_ci } 1940141cc406Sopenharmony_ci 1941141cc406Sopenharmony_ci DBG (1, "%s: Detected device '%s' on IP %s\n", 1942141cc406Sopenharmony_ci __func__, model, ip_addr); 1943141cc406Sopenharmony_ci 1944141cc406Sopenharmony_ci vp = pdu->variables; 1945141cc406Sopenharmony_ci /* TODO: attach the IP with attach_one_net(ip) */ 1946141cc406Sopenharmony_ci cap = mc_get_device_from_identification (device); 1947141cc406Sopenharmony_ci if (cap) { 1948141cc406Sopenharmony_ci DBG(1, "%s: Found autodiscovered device: %s (type 0x%x)\n", __func__, cap->model, cap->id); 1949141cc406Sopenharmony_ci attach_one_net (ip_addr, cap->id); 1950141cc406Sopenharmony_ci if (magic) { 1951141cc406Sopenharmony_ci snmp_ip *new_detected = malloc(sizeof(snmp_ip)); 1952141cc406Sopenharmony_ci strcpy (&new_detected->ip_addr[0], ip_addr); 1953141cc406Sopenharmony_ci new_detected->next = magic->detected; 1954141cc406Sopenharmony_ci magic->detected = new_detected; 1955141cc406Sopenharmony_ci } 1956141cc406Sopenharmony_ci return 1; 1957141cc406Sopenharmony_ci } 1958141cc406Sopenharmony_ci return 0; 1959141cc406Sopenharmony_ci} 1960141cc406Sopenharmony_ci 1961141cc406Sopenharmony_cistatic int 1962141cc406Sopenharmony_cimc_network_discovery_cb (int operation, struct snmp_session *sp, int reqid, 1963141cc406Sopenharmony_ci struct snmp_pdu *pdu, void *magic) 1964141cc406Sopenharmony_ci{ 1965141cc406Sopenharmony_ci NOT_USED (reqid); 1966141cc406Sopenharmony_ci NOT_USED (sp); 1967141cc406Sopenharmony_ci DBG(5, "%s: Received broadcast response \n", __func__); 1968141cc406Sopenharmony_ci 1969141cc406Sopenharmony_ci if (operation == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) { 1970141cc406Sopenharmony_ci snmp_discovery_data *m = (snmp_discovery_data*)magic; 1971141cc406Sopenharmony_ci int nr = mc_network_discovery_handle (pdu, m); 1972141cc406Sopenharmony_ci m->nr += nr; 1973141cc406Sopenharmony_ci DBG(5, "%s: Added %d discovered host(s) for SNMP response.\n", __func__, nr); 1974141cc406Sopenharmony_ci } 1975141cc406Sopenharmony_ci 1976141cc406Sopenharmony_ci return 0; 1977141cc406Sopenharmony_ci} 1978141cc406Sopenharmony_ci#endif 1979141cc406Sopenharmony_ci 1980141cc406Sopenharmony_ci/* Use SNMP for automatic network discovery. If host is given, try to detect 1981141cc406Sopenharmony_ci * that one host (using sync SNMP, otherwise send an SNMP broadcast (async). 1982141cc406Sopenharmony_ci */ 1983141cc406Sopenharmony_cistatic int 1984141cc406Sopenharmony_cimc_network_discovery(const char*host) 1985141cc406Sopenharmony_ci{ 1986141cc406Sopenharmony_ci#if HAVE_LIBSNMP 1987141cc406Sopenharmony_ci netsnmp_session session, *ss; 1988141cc406Sopenharmony_ci netsnmp_pdu *pdu; 1989141cc406Sopenharmony_ci oid anOID[MAX_OID_LEN]; 1990141cc406Sopenharmony_ci size_t anOID_len = MAX_OID_LEN; 1991141cc406Sopenharmony_ci snmp_discovery_data magic; 1992141cc406Sopenharmony_ci magic.nr = 0; 1993141cc406Sopenharmony_ci magic.handled = 0; 1994141cc406Sopenharmony_ci magic.detected = 0; 1995141cc406Sopenharmony_ci 1996141cc406Sopenharmony_ci DBG(1, "%s: running network discovery \n", __func__); 1997141cc406Sopenharmony_ci 1998141cc406Sopenharmony_ci /* Win32: init winsock */ 1999141cc406Sopenharmony_ci SOCK_STARTUP; 2000141cc406Sopenharmony_ci init_snmp("sane-magicolor-backend"); 2001141cc406Sopenharmony_ci snmp_sess_init (&session); 2002141cc406Sopenharmony_ci session.version = SNMP_VERSION_2c; 2003141cc406Sopenharmony_ci session.community = (u_char *) "public"; 2004141cc406Sopenharmony_ci session.community_len = strlen ((char *)session.community); 2005141cc406Sopenharmony_ci if (host) { 2006141cc406Sopenharmony_ci session.peername = (char *) host; 2007141cc406Sopenharmony_ci } else { 2008141cc406Sopenharmony_ci /* Do a network discovery via a broadcast */ 2009141cc406Sopenharmony_ci session.peername = "255.255.255.255"; 2010141cc406Sopenharmony_ci session.flags |= SNMP_FLAGS_UDP_BROADCAST; 2011141cc406Sopenharmony_ci session.callback = mc_network_discovery_cb; 2012141cc406Sopenharmony_ci session.callback_magic = &magic; 2013141cc406Sopenharmony_ci } 2014141cc406Sopenharmony_ci 2015141cc406Sopenharmony_ci ss = snmp_open (&session); /* establish the session */ 2016141cc406Sopenharmony_ci if (!ss) { 2017141cc406Sopenharmony_ci snmp_sess_perror ("ack", &session); 2018141cc406Sopenharmony_ci SOCK_CLEANUP; 2019141cc406Sopenharmony_ci return 0; 2020141cc406Sopenharmony_ci } 2021141cc406Sopenharmony_ci 2022141cc406Sopenharmony_ci /* Create the PDU for the data for our request and add the three 2023141cc406Sopenharmony_ci * desired OIDs to the PDU */ 2024141cc406Sopenharmony_ci pdu = snmp_pdu_create (SNMP_MSG_GET); 2025141cc406Sopenharmony_ci 2026141cc406Sopenharmony_ci /* SNMPv2-MIB::sysDescr.0 */ 2027141cc406Sopenharmony_ci anOID_len = MAX_OID_LEN; 2028141cc406Sopenharmony_ci if (read_objid(MAGICOLOR_SNMP_SYSDESCR_OID, anOID, &anOID_len)) { 2029141cc406Sopenharmony_ci snmp_add_null_var (pdu, anOID, anOID_len); 2030141cc406Sopenharmony_ci } 2031141cc406Sopenharmony_ci /* SNMPv2-MIB::sysObjectID.0 */ 2032141cc406Sopenharmony_ci anOID_len = MAX_OID_LEN; 2033141cc406Sopenharmony_ci if (read_objid(MAGICOLOR_SNMP_SYSOBJECT_OID, anOID, &anOID_len)) { 2034141cc406Sopenharmony_ci snmp_add_null_var (pdu, anOID, anOID_len); 2035141cc406Sopenharmony_ci } 2036141cc406Sopenharmony_ci /* IF-MIB::ifPhysAddress.1 */ 2037141cc406Sopenharmony_ci anOID_len = MAX_OID_LEN; 2038141cc406Sopenharmony_ci if (read_objid(MAGICOLOR_SNMP_MAC_OID, anOID, &anOID_len)) { 2039141cc406Sopenharmony_ci snmp_add_null_var (pdu, anOID, anOID_len); 2040141cc406Sopenharmony_ci } 2041141cc406Sopenharmony_ci /* TODO: Add more interesting OIDs, in particular vendor OIDs */ 2042141cc406Sopenharmony_ci 2043141cc406Sopenharmony_ci /* Now send out the request and wait for responses for some time. 2044141cc406Sopenharmony_ci * If we get a response, connect to that device (in the callback), 2045141cc406Sopenharmony_ci * otherwise we probably don't have a magicolor device in the 2046141cc406Sopenharmony_ci * LAN (or SNMP is turned off, in which case we have no way to detect 2047141cc406Sopenharmony_ci * it. 2048141cc406Sopenharmony_ci */ 2049141cc406Sopenharmony_ci DBG(100, "%s: Sending SNMP packet\n", __func__); 2050141cc406Sopenharmony_ci if (host) { 2051141cc406Sopenharmony_ci /* sync request to given hostname, immediately read the reply */ 2052141cc406Sopenharmony_ci netsnmp_pdu *response = 0; 2053141cc406Sopenharmony_ci int status = snmp_synch_response(ss, pdu, &response); 2054141cc406Sopenharmony_ci if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) { 2055141cc406Sopenharmony_ci magic.nr = mc_network_discovery_handle (response, &magic); 2056141cc406Sopenharmony_ci } 2057141cc406Sopenharmony_ci if (response) 2058141cc406Sopenharmony_ci snmp_free_pdu(response); 2059141cc406Sopenharmony_ci 2060141cc406Sopenharmony_ci 2061141cc406Sopenharmony_ci } else { 2062141cc406Sopenharmony_ci /* No hostname, so do a broadcast */ 2063141cc406Sopenharmony_ci struct timeval nowtime, endtime; /* end time for SNMP scan */ 2064141cc406Sopenharmony_ci struct timeval timeout; 2065141cc406Sopenharmony_ci int i=0; 2066141cc406Sopenharmony_ci 2067141cc406Sopenharmony_ci if (!snmp_send(ss, pdu)) { 2068141cc406Sopenharmony_ci snmp_free_pdu(pdu); 2069141cc406Sopenharmony_ci DBG(100, "%s: Sending SNMP packet NOT successful\n", __func__); 2070141cc406Sopenharmony_ci return 0; 2071141cc406Sopenharmony_ci } 2072141cc406Sopenharmony_ci /* listen for responses for MC_AutoDetectionTimeout milliseconds: */ 2073141cc406Sopenharmony_ci /* First get the final timeout time */ 2074141cc406Sopenharmony_ci gettimeofday (&nowtime, NULL); 2075141cc406Sopenharmony_ci timeout.tv_sec = MC_SNMP_Timeout / 1000; 2076141cc406Sopenharmony_ci timeout.tv_usec = (MC_SNMP_Timeout % 1000) * 1000; 2077141cc406Sopenharmony_ci timeradd (&nowtime, &timeout, &endtime); 2078141cc406Sopenharmony_ci 2079141cc406Sopenharmony_ci while (timercmp(&nowtime, &endtime, <)) { 2080141cc406Sopenharmony_ci int fds = 0, block = 0; 2081141cc406Sopenharmony_ci fd_set fdset; 2082141cc406Sopenharmony_ci DBG(1, " loop=%d\n", i++); 2083141cc406Sopenharmony_ci timeout.tv_sec = 0; 2084141cc406Sopenharmony_ci /* Use a 125ms timeout for select. If we get a response, 2085141cc406Sopenharmony_ci * the loop will be entered earlier again, anyway */ 2086141cc406Sopenharmony_ci timeout.tv_usec = 125000; 2087141cc406Sopenharmony_ci FD_ZERO (&fdset); 2088141cc406Sopenharmony_ci snmp_select_info (&fds, &fdset, &timeout, &block); 2089141cc406Sopenharmony_ci fds = select (fds, &fdset, NULL, NULL, /*block?NULL:*/&timeout); 2090141cc406Sopenharmony_ci if (fds) snmp_read(&fdset); 2091141cc406Sopenharmony_ci else snmp_timeout(); 2092141cc406Sopenharmony_ci gettimeofday(&nowtime, NULL); 2093141cc406Sopenharmony_ci } 2094141cc406Sopenharmony_ci /* Clean up the data in magic */ 2095141cc406Sopenharmony_ci while (magic.handled) { 2096141cc406Sopenharmony_ci snmp_ip *tmp = magic.handled->next; 2097141cc406Sopenharmony_ci free (magic.handled); 2098141cc406Sopenharmony_ci magic.handled = tmp; 2099141cc406Sopenharmony_ci } 2100141cc406Sopenharmony_ci while (magic.detected) { 2101141cc406Sopenharmony_ci snmp_ip *tmp = magic.detected->next; 2102141cc406Sopenharmony_ci free (magic.detected); 2103141cc406Sopenharmony_ci magic.detected = tmp; 2104141cc406Sopenharmony_ci } 2105141cc406Sopenharmony_ci } 2106141cc406Sopenharmony_ci 2107141cc406Sopenharmony_ci /* Clean up */ 2108141cc406Sopenharmony_ci snmp_close(ss); 2109141cc406Sopenharmony_ci SOCK_CLEANUP; 2110141cc406Sopenharmony_ci DBG (5, "%s: Discovered %d host(s)\n", __func__, magic.nr); 2111141cc406Sopenharmony_ci return magic.nr; 2112141cc406Sopenharmony_ci 2113141cc406Sopenharmony_ci#else 2114141cc406Sopenharmony_ci DBG (1, "%s: net-snmp library not enabled, auto-detecting network scanners not supported.\n", __func__); 2115141cc406Sopenharmony_ci NOT_USED (host); 2116141cc406Sopenharmony_ci return 0; 2117141cc406Sopenharmony_ci#endif 2118141cc406Sopenharmony_ci} 2119141cc406Sopenharmony_ci 2120141cc406Sopenharmony_cistatic SANE_Status 2121141cc406Sopenharmony_ciattach(const char *name, int type) 2122141cc406Sopenharmony_ci{ 2123141cc406Sopenharmony_ci SANE_Status status; 2124141cc406Sopenharmony_ci Magicolor_Scanner *s; 2125141cc406Sopenharmony_ci 2126141cc406Sopenharmony_ci DBG(7, "%s: devname = %s, type = %d\n", __func__, name, type); 2127141cc406Sopenharmony_ci 2128141cc406Sopenharmony_ci s = device_detect(name, type, &status); 2129141cc406Sopenharmony_ci if(s == NULL) 2130141cc406Sopenharmony_ci return status; 2131141cc406Sopenharmony_ci 2132141cc406Sopenharmony_ci close_scanner(s); 2133141cc406Sopenharmony_ci free(s); 2134141cc406Sopenharmony_ci return status; 2135141cc406Sopenharmony_ci} 2136141cc406Sopenharmony_ci 2137141cc406Sopenharmony_ciSANE_Status 2138141cc406Sopenharmony_ciattach_one_usb(const char *dev) 2139141cc406Sopenharmony_ci{ 2140141cc406Sopenharmony_ci DBG(7, "%s: dev = %s\n", __func__, dev); 2141141cc406Sopenharmony_ci return attach(dev, SANE_MAGICOLOR_USB); 2142141cc406Sopenharmony_ci} 2143141cc406Sopenharmony_ci 2144141cc406Sopenharmony_cistatic SANE_Status 2145141cc406Sopenharmony_ciattach_one_net(const char *dev, unsigned int model) 2146141cc406Sopenharmony_ci{ 2147141cc406Sopenharmony_ci char name[1024]; 2148141cc406Sopenharmony_ci 2149141cc406Sopenharmony_ci DBG(7, "%s: dev = %s\n", __func__, dev); 2150141cc406Sopenharmony_ci if (model > 0) { 2151141cc406Sopenharmony_ci snprintf(name, 1024, "net:%s?model=0x%x", dev, model); 2152141cc406Sopenharmony_ci } else { 2153141cc406Sopenharmony_ci snprintf(name, 1024, "net:%s", dev); 2154141cc406Sopenharmony_ci } 2155141cc406Sopenharmony_ci 2156141cc406Sopenharmony_ci return attach(name, SANE_MAGICOLOR_NET); 2157141cc406Sopenharmony_ci} 2158141cc406Sopenharmony_ci 2159141cc406Sopenharmony_cistatic SANE_Status 2160141cc406Sopenharmony_ciattach_one_config(SANEI_Config __sane_unused__ *config, const char *line, 2161141cc406Sopenharmony_ci void *data) 2162141cc406Sopenharmony_ci{ 2163141cc406Sopenharmony_ci int vendor, product, timeout; 2164141cc406Sopenharmony_ci SANE_Bool local_only = *(SANE_Bool*) data; 2165141cc406Sopenharmony_ci int len = strlen(line); 2166141cc406Sopenharmony_ci 2167141cc406Sopenharmony_ci DBG(7, "%s: len = %d, line = %s\n", __func__, len, line); 2168141cc406Sopenharmony_ci 2169141cc406Sopenharmony_ci if (sscanf(line, "usb %i %i", &vendor, &product) == 2) { 2170141cc406Sopenharmony_ci /* add the vendor and product IDs to the list of 2171141cc406Sopenharmony_ci * known devices before we call the attach function */ 2172141cc406Sopenharmony_ci 2173141cc406Sopenharmony_ci int numIds = sanei_magicolor_getNumberOfUSBProductIds(); 2174141cc406Sopenharmony_ci 2175141cc406Sopenharmony_ci if (vendor != SANE_MAGICOLOR_VENDOR_ID) 2176141cc406Sopenharmony_ci return SANE_STATUS_INVAL; /* this is not a KONICA MINOLTA device */ 2177141cc406Sopenharmony_ci 2178141cc406Sopenharmony_ci sanei_magicolor_usb_product_ids[numIds - 1] = product; 2179141cc406Sopenharmony_ci sanei_usb_attach_matching_devices(line, attach_one_usb); 2180141cc406Sopenharmony_ci 2181141cc406Sopenharmony_ci } else if (strncmp(line, "usb", 3) == 0 && len == 3) { 2182141cc406Sopenharmony_ci int i, numIds; 2183141cc406Sopenharmony_ci 2184141cc406Sopenharmony_ci numIds = sanei_magicolor_getNumberOfUSBProductIds(); 2185141cc406Sopenharmony_ci 2186141cc406Sopenharmony_ci for (i = 0; i < numIds; i++) { 2187141cc406Sopenharmony_ci sanei_usb_find_devices(SANE_MAGICOLOR_VENDOR_ID, 2188141cc406Sopenharmony_ci sanei_magicolor_usb_product_ids[i], attach_one_usb); 2189141cc406Sopenharmony_ci } 2190141cc406Sopenharmony_ci 2191141cc406Sopenharmony_ci } else if (strncmp(line, "net", 3) == 0) { 2192141cc406Sopenharmony_ci 2193141cc406Sopenharmony_ci if (!local_only) { 2194141cc406Sopenharmony_ci /* remove the "net" sub string */ 2195141cc406Sopenharmony_ci const char *name = 2196141cc406Sopenharmony_ci sanei_config_skip_whitespace(line + 3); 2197141cc406Sopenharmony_ci char IP[1024]; 2198141cc406Sopenharmony_ci unsigned int model = 0; 2199141cc406Sopenharmony_ci 2200141cc406Sopenharmony_ci if (strncmp(name, "autodiscovery", 13) == 0) { 2201141cc406Sopenharmony_ci DBG (50, "%s: Initiating network autodiscovervy via SNMP\n", __func__); 2202141cc406Sopenharmony_ci mc_network_discovery(NULL); 2203141cc406Sopenharmony_ci } else if (sscanf(name, "%s %x", IP, &model) == 2) { 2204141cc406Sopenharmony_ci DBG(50, "%s: Using network device on IP %s, forcing model 0x%x\n", __func__, IP, model); 2205141cc406Sopenharmony_ci attach_one_net(IP, model); 2206141cc406Sopenharmony_ci } else { 2207141cc406Sopenharmony_ci /* use SNMP to detect the type. If not successful, 2208141cc406Sopenharmony_ci * add the host with model type 0 */ 2209141cc406Sopenharmony_ci DBG(50, "%s: Using network device on IP %s, trying to autodetect model\n", __func__, IP); 2210141cc406Sopenharmony_ci if (mc_network_discovery(name)==0) { 2211141cc406Sopenharmony_ci DBG(1, "%s: Autodetecting device model failed, using default model\n", __func__); 2212141cc406Sopenharmony_ci attach_one_net(name, 0); 2213141cc406Sopenharmony_ci } 2214141cc406Sopenharmony_ci } 2215141cc406Sopenharmony_ci } 2216141cc406Sopenharmony_ci 2217141cc406Sopenharmony_ci } else if (sscanf(line, "snmp-timeout %i\n", &timeout)) { 2218141cc406Sopenharmony_ci /* Timeout for SNMP network discovery */ 2219141cc406Sopenharmony_ci DBG(50, "%s: SNMP timeout set to %d\n", __func__, timeout); 2220141cc406Sopenharmony_ci MC_SNMP_Timeout = timeout; 2221141cc406Sopenharmony_ci 2222141cc406Sopenharmony_ci } else if (sscanf(line, "scan-data-timeout %i\n", &timeout)) { 2223141cc406Sopenharmony_ci /* Timeout for scan data requests */ 2224141cc406Sopenharmony_ci DBG(50, "%s: Scan data timeout set to %d\n", __func__, timeout); 2225141cc406Sopenharmony_ci MC_Scan_Data_Timeout = timeout; 2226141cc406Sopenharmony_ci 2227141cc406Sopenharmony_ci } else if (sscanf(line, "request-timeout %i\n", &timeout)) { 2228141cc406Sopenharmony_ci /* Timeout for all other read requests */ 2229141cc406Sopenharmony_ci DBG(50, "%s: Request timeout set to %d\n", __func__, timeout); 2230141cc406Sopenharmony_ci MC_Request_Timeout = timeout; 2231141cc406Sopenharmony_ci 2232141cc406Sopenharmony_ci } else { 2233141cc406Sopenharmony_ci /* TODO: Warning about unparsable line! */ 2234141cc406Sopenharmony_ci } 2235141cc406Sopenharmony_ci 2236141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2237141cc406Sopenharmony_ci} 2238141cc406Sopenharmony_ci 2239141cc406Sopenharmony_cistatic void 2240141cc406Sopenharmony_cifree_devices(void) 2241141cc406Sopenharmony_ci{ 2242141cc406Sopenharmony_ci Magicolor_Device *dev, *next; 2243141cc406Sopenharmony_ci 2244141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 2245141cc406Sopenharmony_ci 2246141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = next) { 2247141cc406Sopenharmony_ci next = dev->next; 2248141cc406Sopenharmony_ci free(dev->name); 2249141cc406Sopenharmony_ci free(dev->model); 2250141cc406Sopenharmony_ci free(dev); 2251141cc406Sopenharmony_ci } 2252141cc406Sopenharmony_ci 2253141cc406Sopenharmony_ci if (devlist) 2254141cc406Sopenharmony_ci free(devlist); 2255141cc406Sopenharmony_ci devlist = NULL; 2256141cc406Sopenharmony_ci first_dev = NULL; 2257141cc406Sopenharmony_ci} 2258141cc406Sopenharmony_ci 2259141cc406Sopenharmony_ciSANE_Status 2260141cc406Sopenharmony_cisane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize) 2261141cc406Sopenharmony_ci{ 2262141cc406Sopenharmony_ci DBG_INIT(); 2263141cc406Sopenharmony_ci DBG(2, "%s: " PACKAGE " " VERSION "\n", __func__); 2264141cc406Sopenharmony_ci 2265141cc406Sopenharmony_ci DBG(1, "magicolor backend, version %i.%i.%i\n", 2266141cc406Sopenharmony_ci MAGICOLOR_VERSION, MAGICOLOR_REVISION, MAGICOLOR_BUILD); 2267141cc406Sopenharmony_ci 2268141cc406Sopenharmony_ci if (version_code != NULL) 2269141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 2270141cc406Sopenharmony_ci MAGICOLOR_BUILD); 2271141cc406Sopenharmony_ci 2272141cc406Sopenharmony_ci sanei_usb_init(); 2273141cc406Sopenharmony_ci 2274141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2275141cc406Sopenharmony_ci} 2276141cc406Sopenharmony_ci 2277141cc406Sopenharmony_ci/* Clean up the list of attached scanners. */ 2278141cc406Sopenharmony_civoid 2279141cc406Sopenharmony_cisane_exit(void) 2280141cc406Sopenharmony_ci{ 2281141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 2282141cc406Sopenharmony_ci free_devices(); 2283141cc406Sopenharmony_ci} 2284141cc406Sopenharmony_ci 2285141cc406Sopenharmony_ciSANE_Status 2286141cc406Sopenharmony_cisane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only) 2287141cc406Sopenharmony_ci{ 2288141cc406Sopenharmony_ci Magicolor_Device *dev, *s, *prev=0; 2289141cc406Sopenharmony_ci int i; 2290141cc406Sopenharmony_ci 2291141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 2292141cc406Sopenharmony_ci 2293141cc406Sopenharmony_ci sanei_usb_init(); 2294141cc406Sopenharmony_ci 2295141cc406Sopenharmony_ci /* mark all existing scanners as missing, attach_one will remove mark */ 2296141cc406Sopenharmony_ci for (s = first_dev; s; s = s->next) { 2297141cc406Sopenharmony_ci s->missing = 1; 2298141cc406Sopenharmony_ci } 2299141cc406Sopenharmony_ci 2300141cc406Sopenharmony_ci /* Read the config, mark each device as found, possibly add new devs */ 2301141cc406Sopenharmony_ci sanei_configure_attach(MAGICOLOR_CONFIG_FILE, NULL, 2302141cc406Sopenharmony_ci attach_one_config, &local_only); 2303141cc406Sopenharmony_ci 2304141cc406Sopenharmony_ci /*delete missing scanners from list*/ 2305141cc406Sopenharmony_ci for (s = first_dev; s;) { 2306141cc406Sopenharmony_ci if (s->missing) { 2307141cc406Sopenharmony_ci DBG (5, "%s: missing scanner %s\n", __func__, s->name); 2308141cc406Sopenharmony_ci 2309141cc406Sopenharmony_ci /*splice s out of list by changing pointer in prev to next*/ 2310141cc406Sopenharmony_ci if (prev) { 2311141cc406Sopenharmony_ci prev->next = s->next; 2312141cc406Sopenharmony_ci free (s); 2313141cc406Sopenharmony_ci s = prev->next; 2314141cc406Sopenharmony_ci num_devices--; 2315141cc406Sopenharmony_ci } else { 2316141cc406Sopenharmony_ci /*remove s from head of list */ 2317141cc406Sopenharmony_ci first_dev = s->next; 2318141cc406Sopenharmony_ci free(s); 2319141cc406Sopenharmony_ci s = first_dev; 2320141cc406Sopenharmony_ci prev=NULL; 2321141cc406Sopenharmony_ci num_devices--; 2322141cc406Sopenharmony_ci } 2323141cc406Sopenharmony_ci } else { 2324141cc406Sopenharmony_ci prev = s; 2325141cc406Sopenharmony_ci s = prev->next; 2326141cc406Sopenharmony_ci } 2327141cc406Sopenharmony_ci } 2328141cc406Sopenharmony_ci 2329141cc406Sopenharmony_ci DBG (15, "%s: found %d scanner(s)\n", __func__, num_devices); 2330141cc406Sopenharmony_ci for (s = first_dev; s; s=s->next) { 2331141cc406Sopenharmony_ci DBG (15, "%s: found scanner %s\n", __func__, s->name); 2332141cc406Sopenharmony_ci } 2333141cc406Sopenharmony_ci 2334141cc406Sopenharmony_ci if (devlist) 2335141cc406Sopenharmony_ci free (devlist); 2336141cc406Sopenharmony_ci 2337141cc406Sopenharmony_ci devlist = malloc((num_devices + 1) * sizeof(devlist[0])); 2338141cc406Sopenharmony_ci if (!devlist) { 2339141cc406Sopenharmony_ci DBG(1, "out of memory (line %d)\n", __LINE__); 2340141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2341141cc406Sopenharmony_ci } 2342141cc406Sopenharmony_ci 2343141cc406Sopenharmony_ci DBG(5, "%s - results:\n", __func__); 2344141cc406Sopenharmony_ci 2345141cc406Sopenharmony_ci for (i = 0, dev = first_dev; i < num_devices && dev; dev = dev->next, i++) { 2346141cc406Sopenharmony_ci DBG(1, " %d (%d): %s\n", i, dev->connection, dev->model); 2347141cc406Sopenharmony_ci devlist[i] = &dev->sane; 2348141cc406Sopenharmony_ci } 2349141cc406Sopenharmony_ci 2350141cc406Sopenharmony_ci devlist[i] = NULL; 2351141cc406Sopenharmony_ci 2352141cc406Sopenharmony_ci if(device_list){ 2353141cc406Sopenharmony_ci *device_list = devlist; 2354141cc406Sopenharmony_ci } 2355141cc406Sopenharmony_ci 2356141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2357141cc406Sopenharmony_ci} 2358141cc406Sopenharmony_ci 2359141cc406Sopenharmony_cistatic SANE_Status 2360141cc406Sopenharmony_ciinit_options(Magicolor_Scanner *s) 2361141cc406Sopenharmony_ci{ 2362141cc406Sopenharmony_ci int i; 2363141cc406Sopenharmony_ci SANE_Word *res_list; 2364141cc406Sopenharmony_ci 2365141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; i++) { 2366141cc406Sopenharmony_ci s->opt[i].size = sizeof(SANE_Word); 2367141cc406Sopenharmony_ci s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 2368141cc406Sopenharmony_ci } 2369141cc406Sopenharmony_ci 2370141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 2371141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 2372141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; 2373141cc406Sopenharmony_ci s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 2374141cc406Sopenharmony_ci s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; 2375141cc406Sopenharmony_ci 2376141cc406Sopenharmony_ci /* "Scan Mode" group: */ 2377141cc406Sopenharmony_ci 2378141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].name = SANE_NAME_STANDARD; 2379141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].title = SANE_TITLE_STANDARD; 2380141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].desc = SANE_DESC_STANDARD; 2381141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; 2382141cc406Sopenharmony_ci s->opt[OPT_MODE_GROUP].cap = 0; 2383141cc406Sopenharmony_ci 2384141cc406Sopenharmony_ci /* scan mode */ 2385141cc406Sopenharmony_ci s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; 2386141cc406Sopenharmony_ci s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; 2387141cc406Sopenharmony_ci s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; 2388141cc406Sopenharmony_ci s->opt[OPT_MODE].type = SANE_TYPE_STRING; 2389141cc406Sopenharmony_ci s->opt[OPT_MODE].size = max_string_size(mode_list); 2390141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 2391141cc406Sopenharmony_ci s->opt[OPT_MODE].constraint.string_list = mode_list; 2392141cc406Sopenharmony_ci s->val[OPT_MODE].w = 0; /* Binary */ 2393141cc406Sopenharmony_ci 2394141cc406Sopenharmony_ci /* bit depth */ 2395141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; 2396141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; 2397141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; 2398141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT; 2399141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].unit = SANE_UNIT_NONE; 2400141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; 2401141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].constraint.word_list = s->hw->cap->depth_list; 2402141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; 2403141cc406Sopenharmony_ci s->val[OPT_BIT_DEPTH].w = s->hw->cap->depth_list[1]; /* the first "real" element is the default */ 2404141cc406Sopenharmony_ci 2405141cc406Sopenharmony_ci if (s->hw->cap->depth_list[0] == 1) /* only one element in the list -> hide the option */ 2406141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; 2407141cc406Sopenharmony_ci 2408141cc406Sopenharmony_ci 2409141cc406Sopenharmony_ci /* brightness */ 2410141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; 2411141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; 2412141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; 2413141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; 2414141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; 2415141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; 2416141cc406Sopenharmony_ci s->opt[OPT_BRIGHTNESS].constraint.range = &s->hw->cap->brightness; 2417141cc406Sopenharmony_ci s->val[OPT_BRIGHTNESS].w = 5; /* Normal */ 2418141cc406Sopenharmony_ci 2419141cc406Sopenharmony_ci /* resolution */ 2420141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; 2421141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; 2422141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; 2423141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; 2424141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; 2425141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; 2426141cc406Sopenharmony_ci res_list = malloc((s->hw->cap->res_list_size + 1) * sizeof(SANE_Word)); 2427141cc406Sopenharmony_ci if (res_list == NULL) { 2428141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2429141cc406Sopenharmony_ci } 2430141cc406Sopenharmony_ci *(res_list) = s->hw->cap->res_list_size; 2431141cc406Sopenharmony_ci memcpy(&(res_list[1]), s->hw->cap->res_list, s->hw->cap->res_list_size * sizeof(SANE_Word)); 2432141cc406Sopenharmony_ci s->opt[OPT_RESOLUTION].constraint.word_list = res_list; 2433141cc406Sopenharmony_ci s->val[OPT_RESOLUTION].w = s->hw->cap->dpi_range.min; 2434141cc406Sopenharmony_ci 2435141cc406Sopenharmony_ci 2436141cc406Sopenharmony_ci /* preview */ 2437141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; 2438141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; 2439141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; 2440141cc406Sopenharmony_ci s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; 2441141cc406Sopenharmony_ci s->val[OPT_PREVIEW].w = SANE_FALSE; 2442141cc406Sopenharmony_ci 2443141cc406Sopenharmony_ci /* source */ 2444141cc406Sopenharmony_ci s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; 2445141cc406Sopenharmony_ci s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; 2446141cc406Sopenharmony_ci s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; 2447141cc406Sopenharmony_ci s->opt[OPT_SOURCE].type = SANE_TYPE_STRING; 2448141cc406Sopenharmony_ci s->opt[OPT_SOURCE].size = max_string_size(source_list); 2449141cc406Sopenharmony_ci s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 2450141cc406Sopenharmony_ci s->opt[OPT_SOURCE].constraint.string_list = source_list; 2451141cc406Sopenharmony_ci s->val[OPT_SOURCE].w = 0; /* always use Flatbed as default */ 2452141cc406Sopenharmony_ci 2453141cc406Sopenharmony_ci s->opt[OPT_ADF_MODE].name = "adf-mode"; 2454141cc406Sopenharmony_ci s->opt[OPT_ADF_MODE].title = SANE_I18N("ADF Mode"); 2455141cc406Sopenharmony_ci s->opt[OPT_ADF_MODE].desc = 2456141cc406Sopenharmony_ci SANE_I18N("Selects the ADF mode (simplex/duplex)"); 2457141cc406Sopenharmony_ci s->opt[OPT_ADF_MODE].type = SANE_TYPE_STRING; 2458141cc406Sopenharmony_ci s->opt[OPT_ADF_MODE].size = max_string_size(adf_mode_list); 2459141cc406Sopenharmony_ci s->opt[OPT_ADF_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 2460141cc406Sopenharmony_ci s->opt[OPT_ADF_MODE].constraint.string_list = adf_mode_list; 2461141cc406Sopenharmony_ci s->val[OPT_ADF_MODE].w = 0; /* simplex */ 2462141cc406Sopenharmony_ci if ((!s->hw->cap->ADF) || (s->hw->cap->adf_duplex == SANE_FALSE)) 2463141cc406Sopenharmony_ci s->opt[OPT_ADF_MODE].cap |= SANE_CAP_INACTIVE; 2464141cc406Sopenharmony_ci 2465141cc406Sopenharmony_ci 2466141cc406Sopenharmony_ci /* "Geometry" group: */ 2467141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].name = SANE_NAME_GEOMETRY; 2468141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY; 2469141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].desc = SANE_DESC_GEOMETRY; 2470141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; 2471141cc406Sopenharmony_ci s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; 2472141cc406Sopenharmony_ci 2473141cc406Sopenharmony_ci /* top-left x */ 2474141cc406Sopenharmony_ci s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; 2475141cc406Sopenharmony_ci s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; 2476141cc406Sopenharmony_ci s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; 2477141cc406Sopenharmony_ci s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; 2478141cc406Sopenharmony_ci s->opt[OPT_TL_X].unit = SANE_UNIT_MM; 2479141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 2480141cc406Sopenharmony_ci s->opt[OPT_TL_X].constraint.range = s->hw->x_range; 2481141cc406Sopenharmony_ci s->val[OPT_TL_X].w = 0; 2482141cc406Sopenharmony_ci 2483141cc406Sopenharmony_ci /* top-left y */ 2484141cc406Sopenharmony_ci s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; 2485141cc406Sopenharmony_ci s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 2486141cc406Sopenharmony_ci s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 2487141cc406Sopenharmony_ci s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; 2488141cc406Sopenharmony_ci s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; 2489141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 2490141cc406Sopenharmony_ci s->opt[OPT_TL_Y].constraint.range = s->hw->y_range; 2491141cc406Sopenharmony_ci s->val[OPT_TL_Y].w = 0; 2492141cc406Sopenharmony_ci 2493141cc406Sopenharmony_ci /* bottom-right x */ 2494141cc406Sopenharmony_ci s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; 2495141cc406Sopenharmony_ci s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; 2496141cc406Sopenharmony_ci s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; 2497141cc406Sopenharmony_ci s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; 2498141cc406Sopenharmony_ci s->opt[OPT_BR_X].unit = SANE_UNIT_MM; 2499141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 2500141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = s->hw->x_range; 2501141cc406Sopenharmony_ci s->val[OPT_BR_X].w = s->hw->x_range->max; 2502141cc406Sopenharmony_ci 2503141cc406Sopenharmony_ci /* bottom-right y */ 2504141cc406Sopenharmony_ci s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; 2505141cc406Sopenharmony_ci s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 2506141cc406Sopenharmony_ci s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 2507141cc406Sopenharmony_ci s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; 2508141cc406Sopenharmony_ci s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; 2509141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 2510141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = s->hw->y_range; 2511141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = s->hw->y_range->max; 2512141cc406Sopenharmony_ci 2513141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2514141cc406Sopenharmony_ci} 2515141cc406Sopenharmony_ci 2516141cc406Sopenharmony_ciSANE_Status 2517141cc406Sopenharmony_cisane_open(SANE_String_Const name, SANE_Handle *handle) 2518141cc406Sopenharmony_ci{ 2519141cc406Sopenharmony_ci SANE_Status status; 2520141cc406Sopenharmony_ci Magicolor_Scanner *s = NULL; 2521141cc406Sopenharmony_ci 2522141cc406Sopenharmony_ci int l = strlen(name); 2523141cc406Sopenharmony_ci 2524141cc406Sopenharmony_ci DBG(7, "%s: name = %s\n", __func__, name); 2525141cc406Sopenharmony_ci 2526141cc406Sopenharmony_ci /* probe if empty device name provided */ 2527141cc406Sopenharmony_ci if (l == 0) { 2528141cc406Sopenharmony_ci 2529141cc406Sopenharmony_ci status = sane_get_devices(NULL,0); 2530141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 2531141cc406Sopenharmony_ci return status; 2532141cc406Sopenharmony_ci } 2533141cc406Sopenharmony_ci 2534141cc406Sopenharmony_ci if (first_dev == NULL) { 2535141cc406Sopenharmony_ci DBG(1, "no device detected\n"); 2536141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2537141cc406Sopenharmony_ci } 2538141cc406Sopenharmony_ci 2539141cc406Sopenharmony_ci s = device_detect(first_dev->sane.name, first_dev->connection, 2540141cc406Sopenharmony_ci &status); 2541141cc406Sopenharmony_ci if (s == NULL) { 2542141cc406Sopenharmony_ci DBG(1, "cannot open a perfectly valid device (%s)," 2543141cc406Sopenharmony_ci " please report to the authors\n", name); 2544141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2545141cc406Sopenharmony_ci } 2546141cc406Sopenharmony_ci 2547141cc406Sopenharmony_ci } else { 2548141cc406Sopenharmony_ci 2549141cc406Sopenharmony_ci if (strncmp(name, "net:", 4) == 0) { 2550141cc406Sopenharmony_ci s = device_detect(name, SANE_MAGICOLOR_NET, &status); 2551141cc406Sopenharmony_ci if (s == NULL) 2552141cc406Sopenharmony_ci return status; 2553141cc406Sopenharmony_ci } else if (strncmp(name, "libusb:", 7) == 0) { 2554141cc406Sopenharmony_ci s = device_detect(name, SANE_MAGICOLOR_USB, &status); 2555141cc406Sopenharmony_ci if (s == NULL) 2556141cc406Sopenharmony_ci return status; 2557141cc406Sopenharmony_ci } else { 2558141cc406Sopenharmony_ci 2559141cc406Sopenharmony_ci /* as a last resort, check for a match 2560141cc406Sopenharmony_ci * in the device list. This should handle platforms without libusb. 2561141cc406Sopenharmony_ci */ 2562141cc406Sopenharmony_ci if (first_dev == NULL) { 2563141cc406Sopenharmony_ci status = sane_get_devices(NULL,0); 2564141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 2565141cc406Sopenharmony_ci return status; 2566141cc406Sopenharmony_ci } 2567141cc406Sopenharmony_ci } 2568141cc406Sopenharmony_ci 2569141cc406Sopenharmony_ci s = device_detect(name, SANE_MAGICOLOR_NODEV, &status); 2570141cc406Sopenharmony_ci if (s == NULL) { 2571141cc406Sopenharmony_ci DBG(1, "invalid device name: %s\n", name); 2572141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2573141cc406Sopenharmony_ci } 2574141cc406Sopenharmony_ci } 2575141cc406Sopenharmony_ci } 2576141cc406Sopenharmony_ci 2577141cc406Sopenharmony_ci 2578141cc406Sopenharmony_ci /* s is always valid here */ 2579141cc406Sopenharmony_ci 2580141cc406Sopenharmony_ci DBG(1, "handle obtained\n"); 2581141cc406Sopenharmony_ci 2582141cc406Sopenharmony_ci init_options(s); 2583141cc406Sopenharmony_ci 2584141cc406Sopenharmony_ci *handle = (SANE_Handle) s; 2585141cc406Sopenharmony_ci 2586141cc406Sopenharmony_ci status = open_scanner(s); 2587141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 2588141cc406Sopenharmony_ci free(s); 2589141cc406Sopenharmony_ci return status; 2590141cc406Sopenharmony_ci } 2591141cc406Sopenharmony_ci 2592141cc406Sopenharmony_ci return status; 2593141cc406Sopenharmony_ci} 2594141cc406Sopenharmony_ci 2595141cc406Sopenharmony_civoid 2596141cc406Sopenharmony_cisane_close(SANE_Handle handle) 2597141cc406Sopenharmony_ci{ 2598141cc406Sopenharmony_ci Magicolor_Scanner *s; 2599141cc406Sopenharmony_ci 2600141cc406Sopenharmony_ci /* 2601141cc406Sopenharmony_ci * XXX Test if there is still data pending from 2602141cc406Sopenharmony_ci * the scanner. If so, then do a cancel 2603141cc406Sopenharmony_ci */ 2604141cc406Sopenharmony_ci 2605141cc406Sopenharmony_ci s = (Magicolor_Scanner *) handle; 2606141cc406Sopenharmony_ci 2607141cc406Sopenharmony_ci if (s->fd != -1) 2608141cc406Sopenharmony_ci close_scanner(s); 2609141cc406Sopenharmony_ci 2610141cc406Sopenharmony_ci free(s); 2611141cc406Sopenharmony_ci} 2612141cc406Sopenharmony_ci 2613141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 2614141cc406Sopenharmony_cisane_get_option_descriptor(SANE_Handle handle, SANE_Int option) 2615141cc406Sopenharmony_ci{ 2616141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 2617141cc406Sopenharmony_ci 2618141cc406Sopenharmony_ci if (option < 0 || option >= NUM_OPTIONS) 2619141cc406Sopenharmony_ci return NULL; 2620141cc406Sopenharmony_ci 2621141cc406Sopenharmony_ci return s->opt + option; 2622141cc406Sopenharmony_ci} 2623141cc406Sopenharmony_ci 2624141cc406Sopenharmony_cistatic const SANE_String_Const * 2625141cc406Sopenharmony_cisearch_string_list(const SANE_String_Const *list, SANE_String value) 2626141cc406Sopenharmony_ci{ 2627141cc406Sopenharmony_ci while (*list != NULL && strcmp(value, *list) != 0) 2628141cc406Sopenharmony_ci list++; 2629141cc406Sopenharmony_ci 2630141cc406Sopenharmony_ci return ((*list == NULL) ? NULL : list); 2631141cc406Sopenharmony_ci} 2632141cc406Sopenharmony_ci 2633141cc406Sopenharmony_ci/* 2634141cc406Sopenharmony_ci Activate, deactivate an option. Subroutines so we can add 2635141cc406Sopenharmony_ci debugging info if we want. The change flag is set to TRUE 2636141cc406Sopenharmony_ci if we changed an option. If we did not change an option, 2637141cc406Sopenharmony_ci then the value of the changed flag is not modified. 2638141cc406Sopenharmony_ci*/ 2639141cc406Sopenharmony_ci 2640141cc406Sopenharmony_cistatic void 2641141cc406Sopenharmony_ciactivateOption(Magicolor_Scanner *s, SANE_Int option, SANE_Bool *change) 2642141cc406Sopenharmony_ci{ 2643141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE(s->opt[option].cap)) { 2644141cc406Sopenharmony_ci s->opt[option].cap &= ~SANE_CAP_INACTIVE; 2645141cc406Sopenharmony_ci *change = SANE_TRUE; 2646141cc406Sopenharmony_ci } 2647141cc406Sopenharmony_ci} 2648141cc406Sopenharmony_ci 2649141cc406Sopenharmony_cistatic void 2650141cc406Sopenharmony_cideactivateOption(Magicolor_Scanner *s, SANE_Int option, SANE_Bool *change) 2651141cc406Sopenharmony_ci{ 2652141cc406Sopenharmony_ci if (SANE_OPTION_IS_ACTIVE(s->opt[option].cap)) { 2653141cc406Sopenharmony_ci s->opt[option].cap |= SANE_CAP_INACTIVE; 2654141cc406Sopenharmony_ci *change = SANE_TRUE; 2655141cc406Sopenharmony_ci } 2656141cc406Sopenharmony_ci} 2657141cc406Sopenharmony_ci 2658141cc406Sopenharmony_cistatic SANE_Status 2659141cc406Sopenharmony_cigetvalue(SANE_Handle handle, SANE_Int option, void *value) 2660141cc406Sopenharmony_ci{ 2661141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 2662141cc406Sopenharmony_ci SANE_Option_Descriptor *sopt = &(s->opt[option]); 2663141cc406Sopenharmony_ci Option_Value *sval = &(s->val[option]); 2664141cc406Sopenharmony_ci 2665141cc406Sopenharmony_ci DBG(17, "%s: option = %d\n", __func__, option); 2666141cc406Sopenharmony_ci 2667141cc406Sopenharmony_ci switch (option) { 2668141cc406Sopenharmony_ci 2669141cc406Sopenharmony_ci case OPT_NUM_OPTS: 2670141cc406Sopenharmony_ci case OPT_BIT_DEPTH: 2671141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 2672141cc406Sopenharmony_ci case OPT_RESOLUTION: 2673141cc406Sopenharmony_ci case OPT_PREVIEW: 2674141cc406Sopenharmony_ci case OPT_TL_X: 2675141cc406Sopenharmony_ci case OPT_TL_Y: 2676141cc406Sopenharmony_ci case OPT_BR_X: 2677141cc406Sopenharmony_ci case OPT_BR_Y: 2678141cc406Sopenharmony_ci *((SANE_Word *) value) = sval->w; 2679141cc406Sopenharmony_ci break; 2680141cc406Sopenharmony_ci 2681141cc406Sopenharmony_ci case OPT_MODE: 2682141cc406Sopenharmony_ci case OPT_SOURCE: 2683141cc406Sopenharmony_ci case OPT_ADF_MODE: 2684141cc406Sopenharmony_ci strcpy((char *) value, sopt->constraint.string_list[sval->w]); 2685141cc406Sopenharmony_ci break; 2686141cc406Sopenharmony_ci 2687141cc406Sopenharmony_ci default: 2688141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2689141cc406Sopenharmony_ci } 2690141cc406Sopenharmony_ci 2691141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2692141cc406Sopenharmony_ci} 2693141cc406Sopenharmony_ci 2694141cc406Sopenharmony_ci 2695141cc406Sopenharmony_ci/* 2696141cc406Sopenharmony_ci * Handles setting the source (flatbed, or auto document feeder (ADF)). 2697141cc406Sopenharmony_ci * 2698141cc406Sopenharmony_ci */ 2699141cc406Sopenharmony_ci 2700141cc406Sopenharmony_cistatic void 2701141cc406Sopenharmony_cichange_source(Magicolor_Scanner *s, SANE_Int optindex, char *value) 2702141cc406Sopenharmony_ci{ 2703141cc406Sopenharmony_ci int force_max = SANE_FALSE; 2704141cc406Sopenharmony_ci SANE_Bool dummy; 2705141cc406Sopenharmony_ci 2706141cc406Sopenharmony_ci DBG(1, "%s: optindex = %d, source = '%s'\n", __func__, optindex, 2707141cc406Sopenharmony_ci value); 2708141cc406Sopenharmony_ci 2709141cc406Sopenharmony_ci if (s->val[OPT_SOURCE].w == optindex) 2710141cc406Sopenharmony_ci return; 2711141cc406Sopenharmony_ci 2712141cc406Sopenharmony_ci s->val[OPT_SOURCE].w = optindex; 2713141cc406Sopenharmony_ci 2714141cc406Sopenharmony_ci if (s->val[OPT_TL_X].w == s->hw->x_range->min 2715141cc406Sopenharmony_ci && s->val[OPT_TL_Y].w == s->hw->y_range->min 2716141cc406Sopenharmony_ci && s->val[OPT_BR_X].w == s->hw->x_range->max 2717141cc406Sopenharmony_ci && s->val[OPT_BR_Y].w == s->hw->y_range->max) { 2718141cc406Sopenharmony_ci force_max = SANE_TRUE; 2719141cc406Sopenharmony_ci } 2720141cc406Sopenharmony_ci 2721141cc406Sopenharmony_ci if (strcmp(ADF_STR, value) == 0) { 2722141cc406Sopenharmony_ci s->hw->x_range = &s->hw->cap->adf_x_range; 2723141cc406Sopenharmony_ci s->hw->y_range = &s->hw->cap->adf_y_range; 2724141cc406Sopenharmony_ci if (s->hw->cap->adf_duplex) { 2725141cc406Sopenharmony_ci activateOption(s, OPT_ADF_MODE, &dummy); 2726141cc406Sopenharmony_ci } else { 2727141cc406Sopenharmony_ci deactivateOption(s, OPT_ADF_MODE, &dummy); 2728141cc406Sopenharmony_ci s->val[OPT_ADF_MODE].w = 0; 2729141cc406Sopenharmony_ci } 2730141cc406Sopenharmony_ci 2731141cc406Sopenharmony_ci DBG(1, "adf activated (%d)\n",s->hw->cap->adf_duplex); 2732141cc406Sopenharmony_ci 2733141cc406Sopenharmony_ci } else { 2734141cc406Sopenharmony_ci /* ADF not active */ 2735141cc406Sopenharmony_ci s->hw->x_range = &s->hw->cap->fbf_x_range; 2736141cc406Sopenharmony_ci s->hw->y_range = &s->hw->cap->fbf_y_range; 2737141cc406Sopenharmony_ci 2738141cc406Sopenharmony_ci deactivateOption(s, OPT_ADF_MODE, &dummy); 2739141cc406Sopenharmony_ci } 2740141cc406Sopenharmony_ci 2741141cc406Sopenharmony_ci s->opt[OPT_BR_X].constraint.range = s->hw->x_range; 2742141cc406Sopenharmony_ci s->opt[OPT_BR_Y].constraint.range = s->hw->y_range; 2743141cc406Sopenharmony_ci 2744141cc406Sopenharmony_ci if (s->val[OPT_TL_X].w < s->hw->x_range->min || force_max) 2745141cc406Sopenharmony_ci s->val[OPT_TL_X].w = s->hw->x_range->min; 2746141cc406Sopenharmony_ci 2747141cc406Sopenharmony_ci if (s->val[OPT_TL_Y].w < s->hw->y_range->min || force_max) 2748141cc406Sopenharmony_ci s->val[OPT_TL_Y].w = s->hw->y_range->min; 2749141cc406Sopenharmony_ci 2750141cc406Sopenharmony_ci if (s->val[OPT_BR_X].w > s->hw->x_range->max || force_max) 2751141cc406Sopenharmony_ci s->val[OPT_BR_X].w = s->hw->x_range->max; 2752141cc406Sopenharmony_ci 2753141cc406Sopenharmony_ci if (s->val[OPT_BR_Y].w > s->hw->y_range->max || force_max) 2754141cc406Sopenharmony_ci s->val[OPT_BR_Y].w = s->hw->y_range->max; 2755141cc406Sopenharmony_ci 2756141cc406Sopenharmony_ci} 2757141cc406Sopenharmony_ci 2758141cc406Sopenharmony_cistatic SANE_Status 2759141cc406Sopenharmony_cisetvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info) 2760141cc406Sopenharmony_ci{ 2761141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 2762141cc406Sopenharmony_ci SANE_Option_Descriptor *sopt = &(s->opt[option]); 2763141cc406Sopenharmony_ci Option_Value *sval = &(s->val[option]); 2764141cc406Sopenharmony_ci 2765141cc406Sopenharmony_ci SANE_Status status; 2766141cc406Sopenharmony_ci const SANE_String_Const *optval = NULL; 2767141cc406Sopenharmony_ci int optindex = 0; 2768141cc406Sopenharmony_ci SANE_Bool reload = SANE_FALSE; 2769141cc406Sopenharmony_ci 2770141cc406Sopenharmony_ci DBG(17, "%s: option = %d, value = %p, as word: %d\n", __func__, option, value, *(SANE_Word *) value); 2771141cc406Sopenharmony_ci 2772141cc406Sopenharmony_ci status = sanei_constrain_value(sopt, value, info); 2773141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2774141cc406Sopenharmony_ci return status; 2775141cc406Sopenharmony_ci 2776141cc406Sopenharmony_ci if (info && value && (*info & SANE_INFO_INEXACT) 2777141cc406Sopenharmony_ci && sopt->type == SANE_TYPE_INT) 2778141cc406Sopenharmony_ci DBG(17, "%s: constrained val = %d\n", __func__, 2779141cc406Sopenharmony_ci *(SANE_Word *) value); 2780141cc406Sopenharmony_ci 2781141cc406Sopenharmony_ci if (sopt->constraint_type == SANE_CONSTRAINT_STRING_LIST) { 2782141cc406Sopenharmony_ci optval = search_string_list(sopt->constraint.string_list, 2783141cc406Sopenharmony_ci (char *) value); 2784141cc406Sopenharmony_ci if (optval == NULL) 2785141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2786141cc406Sopenharmony_ci optindex = optval - sopt->constraint.string_list; 2787141cc406Sopenharmony_ci } 2788141cc406Sopenharmony_ci 2789141cc406Sopenharmony_ci switch (option) { 2790141cc406Sopenharmony_ci 2791141cc406Sopenharmony_ci case OPT_MODE: 2792141cc406Sopenharmony_ci { 2793141cc406Sopenharmony_ci sval->w = optindex; 2794141cc406Sopenharmony_ci /* if binary, then disable the bit depth selection */ 2795141cc406Sopenharmony_ci if (optindex == 0) { 2796141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; 2797141cc406Sopenharmony_ci } else { 2798141cc406Sopenharmony_ci if (s->hw->cap->depth_list[0] == 1) 2799141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap |= 2800141cc406Sopenharmony_ci SANE_CAP_INACTIVE; 2801141cc406Sopenharmony_ci else { 2802141cc406Sopenharmony_ci s->opt[OPT_BIT_DEPTH].cap &= 2803141cc406Sopenharmony_ci ~SANE_CAP_INACTIVE; 2804141cc406Sopenharmony_ci s->val[OPT_BIT_DEPTH].w = 2805141cc406Sopenharmony_ci mode_params[optindex].depth; 2806141cc406Sopenharmony_ci } 2807141cc406Sopenharmony_ci } 2808141cc406Sopenharmony_ci reload = SANE_TRUE; 2809141cc406Sopenharmony_ci break; 2810141cc406Sopenharmony_ci } 2811141cc406Sopenharmony_ci 2812141cc406Sopenharmony_ci case OPT_BIT_DEPTH: 2813141cc406Sopenharmony_ci sval->w = *((SANE_Word *) value); 2814141cc406Sopenharmony_ci mode_params[s->val[OPT_MODE].w].depth = sval->w; 2815141cc406Sopenharmony_ci reload = SANE_TRUE; 2816141cc406Sopenharmony_ci break; 2817141cc406Sopenharmony_ci 2818141cc406Sopenharmony_ci case OPT_RESOLUTION: 2819141cc406Sopenharmony_ci sval->w = *((SANE_Word *) value); 2820141cc406Sopenharmony_ci DBG(17, "setting resolution to %d\n", sval->w); 2821141cc406Sopenharmony_ci reload = SANE_TRUE; 2822141cc406Sopenharmony_ci break; 2823141cc406Sopenharmony_ci 2824141cc406Sopenharmony_ci case OPT_BR_X: 2825141cc406Sopenharmony_ci case OPT_BR_Y: 2826141cc406Sopenharmony_ci if (SANE_UNFIX(*((SANE_Word *) value)) == 0) { 2827141cc406Sopenharmony_ci DBG(17, "invalid br-x or br-y\n"); 2828141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2829141cc406Sopenharmony_ci } 2830141cc406Sopenharmony_ci // fall through 2831141cc406Sopenharmony_ci case OPT_TL_X: 2832141cc406Sopenharmony_ci case OPT_TL_Y: 2833141cc406Sopenharmony_ci sval->w = *((SANE_Word *) value); 2834141cc406Sopenharmony_ci DBG(17, "setting size to %f\n", SANE_UNFIX(sval->w)); 2835141cc406Sopenharmony_ci if (NULL != info) 2836141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 2837141cc406Sopenharmony_ci break; 2838141cc406Sopenharmony_ci 2839141cc406Sopenharmony_ci case OPT_SOURCE: 2840141cc406Sopenharmony_ci change_source(s, optindex, (char *) value); 2841141cc406Sopenharmony_ci reload = SANE_TRUE; 2842141cc406Sopenharmony_ci break; 2843141cc406Sopenharmony_ci 2844141cc406Sopenharmony_ci case OPT_ADF_MODE: 2845141cc406Sopenharmony_ci sval->w = optindex; /* Simple lists */ 2846141cc406Sopenharmony_ci break; 2847141cc406Sopenharmony_ci 2848141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 2849141cc406Sopenharmony_ci case OPT_PREVIEW: /* needed? */ 2850141cc406Sopenharmony_ci sval->w = *((SANE_Word *) value); 2851141cc406Sopenharmony_ci break; 2852141cc406Sopenharmony_ci 2853141cc406Sopenharmony_ci default: 2854141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2855141cc406Sopenharmony_ci } 2856141cc406Sopenharmony_ci 2857141cc406Sopenharmony_ci if (reload && info != NULL) 2858141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; 2859141cc406Sopenharmony_ci 2860141cc406Sopenharmony_ci DBG(17, "%s: end\n", __func__); 2861141cc406Sopenharmony_ci 2862141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2863141cc406Sopenharmony_ci} 2864141cc406Sopenharmony_ci 2865141cc406Sopenharmony_ciSANE_Status 2866141cc406Sopenharmony_cisane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, 2867141cc406Sopenharmony_ci void *value, SANE_Int *info) 2868141cc406Sopenharmony_ci{ 2869141cc406Sopenharmony_ci DBG(17, "%s: action = %x, option = %d\n", __func__, action, option); 2870141cc406Sopenharmony_ci 2871141cc406Sopenharmony_ci if (option < 0 || option >= NUM_OPTIONS) 2872141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2873141cc406Sopenharmony_ci 2874141cc406Sopenharmony_ci if (info != NULL) 2875141cc406Sopenharmony_ci *info = 0; 2876141cc406Sopenharmony_ci 2877141cc406Sopenharmony_ci switch (action) { 2878141cc406Sopenharmony_ci case SANE_ACTION_GET_VALUE: 2879141cc406Sopenharmony_ci return getvalue(handle, option, value); 2880141cc406Sopenharmony_ci 2881141cc406Sopenharmony_ci case SANE_ACTION_SET_VALUE: 2882141cc406Sopenharmony_ci return setvalue(handle, option, value, info); 2883141cc406Sopenharmony_ci 2884141cc406Sopenharmony_ci default: 2885141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2886141cc406Sopenharmony_ci } 2887141cc406Sopenharmony_ci 2888141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2889141cc406Sopenharmony_ci} 2890141cc406Sopenharmony_ci 2891141cc406Sopenharmony_ciSANE_Status 2892141cc406Sopenharmony_cisane_get_parameters(SANE_Handle handle, SANE_Parameters *params) 2893141cc406Sopenharmony_ci{ 2894141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 2895141cc406Sopenharmony_ci 2896141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 2897141cc406Sopenharmony_ci 2898141cc406Sopenharmony_ci if (params == NULL) 2899141cc406Sopenharmony_ci DBG(1, "%s: params is NULL\n", __func__); 2900141cc406Sopenharmony_ci 2901141cc406Sopenharmony_ci /* 2902141cc406Sopenharmony_ci * If sane_start was already called, then just retrieve the parameters 2903141cc406Sopenharmony_ci * from the scanner data structure 2904141cc406Sopenharmony_ci */ 2905141cc406Sopenharmony_ci 2906141cc406Sopenharmony_ci if (!s->eof && s->ptr != NULL) { 2907141cc406Sopenharmony_ci DBG(5, "scan in progress, returning saved params structure\n"); 2908141cc406Sopenharmony_ci } else { 2909141cc406Sopenharmony_ci /* otherwise initialize the params structure and gather the data */ 2910141cc406Sopenharmony_ci mc_init_parameters(s); 2911141cc406Sopenharmony_ci } 2912141cc406Sopenharmony_ci 2913141cc406Sopenharmony_ci if (params != NULL) 2914141cc406Sopenharmony_ci *params = s->params; 2915141cc406Sopenharmony_ci 2916141cc406Sopenharmony_ci print_params(s->params); 2917141cc406Sopenharmony_ci 2918141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2919141cc406Sopenharmony_ci} 2920141cc406Sopenharmony_ci 2921141cc406Sopenharmony_ci/* 2922141cc406Sopenharmony_ci * This function is part of the SANE API and gets called from the front end to 2923141cc406Sopenharmony_ci * start the scan process. 2924141cc406Sopenharmony_ci */ 2925141cc406Sopenharmony_ci 2926141cc406Sopenharmony_ciSANE_Status 2927141cc406Sopenharmony_cisane_start(SANE_Handle handle) 2928141cc406Sopenharmony_ci{ 2929141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 2930141cc406Sopenharmony_ci SANE_Status status; 2931141cc406Sopenharmony_ci 2932141cc406Sopenharmony_ci DBG(5, "%s\n", __func__); 2933141cc406Sopenharmony_ci 2934141cc406Sopenharmony_ci /* calc scanning parameters */ 2935141cc406Sopenharmony_ci status = mc_init_parameters(s); 2936141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2937141cc406Sopenharmony_ci return status; 2938141cc406Sopenharmony_ci 2939141cc406Sopenharmony_ci print_params(s->params); 2940141cc406Sopenharmony_ci 2941141cc406Sopenharmony_ci /* set scanning parameters; also query the current image 2942141cc406Sopenharmony_ci * parameters from the sanner and save 2943141cc406Sopenharmony_ci * them to s->params */ 2944141cc406Sopenharmony_ci status = mc_set_scanning_parameters(s); 2945141cc406Sopenharmony_ci 2946141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2947141cc406Sopenharmony_ci return status; 2948141cc406Sopenharmony_ci 2949141cc406Sopenharmony_ci /* if we scan from ADF, check if it is loaded */ 2950141cc406Sopenharmony_ci if (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) == 0) { 2951141cc406Sopenharmony_ci status = mc_check_adf(s); 2952141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2953141cc406Sopenharmony_ci return status; 2954141cc406Sopenharmony_ci } 2955141cc406Sopenharmony_ci 2956141cc406Sopenharmony_ci /* prepare buffer here so that a memory allocation failure 2957141cc406Sopenharmony_ci * will leave the scanner in a sane state. 2958141cc406Sopenharmony_ci */ 2959141cc406Sopenharmony_ci s->buf = realloc(s->buf, s->block_len); 2960141cc406Sopenharmony_ci if (s->buf == NULL) 2961141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2962141cc406Sopenharmony_ci 2963141cc406Sopenharmony_ci s->eof = SANE_FALSE; 2964141cc406Sopenharmony_ci s->ptr = s->end = s->buf; 2965141cc406Sopenharmony_ci s->canceling = SANE_FALSE; 2966141cc406Sopenharmony_ci 2967141cc406Sopenharmony_ci /* start scanning */ 2968141cc406Sopenharmony_ci DBG(1, "%s: scanning...\n", __func__); 2969141cc406Sopenharmony_ci 2970141cc406Sopenharmony_ci status = mc_start_scan(s); 2971141cc406Sopenharmony_ci 2972141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 2973141cc406Sopenharmony_ci DBG(1, "%s: start failed: %s\n", __func__, 2974141cc406Sopenharmony_ci sane_strstatus(status)); 2975141cc406Sopenharmony_ci 2976141cc406Sopenharmony_ci return status; 2977141cc406Sopenharmony_ci } 2978141cc406Sopenharmony_ci 2979141cc406Sopenharmony_ci return status; 2980141cc406Sopenharmony_ci} 2981141cc406Sopenharmony_ci 2982141cc406Sopenharmony_ci/* this moves data from our buffers to SANE */ 2983141cc406Sopenharmony_ci 2984141cc406Sopenharmony_ciSANE_Status 2985141cc406Sopenharmony_cisane_read(SANE_Handle handle, SANE_Byte *data, SANE_Int max_length, 2986141cc406Sopenharmony_ci SANE_Int *length) 2987141cc406Sopenharmony_ci{ 2988141cc406Sopenharmony_ci SANE_Status status; 2989141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 2990141cc406Sopenharmony_ci 2991141cc406Sopenharmony_ci if (s->buf == NULL || s->canceling) 2992141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 2993141cc406Sopenharmony_ci 2994141cc406Sopenharmony_ci *length = 0; 2995141cc406Sopenharmony_ci 2996141cc406Sopenharmony_ci status = mc_read(s); 2997141cc406Sopenharmony_ci 2998141cc406Sopenharmony_ci if (status == SANE_STATUS_CANCELLED) { 2999141cc406Sopenharmony_ci mc_scan_finish(s); 3000141cc406Sopenharmony_ci return status; 3001141cc406Sopenharmony_ci } 3002141cc406Sopenharmony_ci 3003141cc406Sopenharmony_ci DBG(18, "moving data %p %p, %d (%d lines)\n", 3004141cc406Sopenharmony_ci (void *) s->ptr, (void *) s->end, 3005141cc406Sopenharmony_ci max_length, max_length / s->params.bytes_per_line); 3006141cc406Sopenharmony_ci 3007141cc406Sopenharmony_ci mc_copy_image_data(s, data, max_length, length); 3008141cc406Sopenharmony_ci 3009141cc406Sopenharmony_ci DBG(18, "%d lines read, status: %d\n", 3010141cc406Sopenharmony_ci *length / s->params.bytes_per_line, status); 3011141cc406Sopenharmony_ci 3012141cc406Sopenharmony_ci /* continue reading if appropriate */ 3013141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 3014141cc406Sopenharmony_ci return status; 3015141cc406Sopenharmony_ci 3016141cc406Sopenharmony_ci mc_scan_finish(s); 3017141cc406Sopenharmony_ci 3018141cc406Sopenharmony_ci return status; 3019141cc406Sopenharmony_ci} 3020141cc406Sopenharmony_ci 3021141cc406Sopenharmony_ci/* 3022141cc406Sopenharmony_ci * void sane_cancel(SANE_Handle handle) 3023141cc406Sopenharmony_ci * 3024141cc406Sopenharmony_ci * Set the cancel flag to true. The next time the backend requests data 3025141cc406Sopenharmony_ci * from the scanner the CAN message will be sent. 3026141cc406Sopenharmony_ci */ 3027141cc406Sopenharmony_ci 3028141cc406Sopenharmony_civoid 3029141cc406Sopenharmony_cisane_cancel(SANE_Handle handle) 3030141cc406Sopenharmony_ci{ 3031141cc406Sopenharmony_ci Magicolor_Scanner *s = (Magicolor_Scanner *) handle; 3032141cc406Sopenharmony_ci 3033141cc406Sopenharmony_ci s->canceling = SANE_TRUE; 3034141cc406Sopenharmony_ci} 3035141cc406Sopenharmony_ci 3036141cc406Sopenharmony_ci/* 3037141cc406Sopenharmony_ci * SANE_Status sane_set_io_mode() 3038141cc406Sopenharmony_ci * 3039141cc406Sopenharmony_ci * not supported - for asynchronous I/O 3040141cc406Sopenharmony_ci */ 3041141cc406Sopenharmony_ci 3042141cc406Sopenharmony_ciSANE_Status 3043141cc406Sopenharmony_cisane_set_io_mode(SANE_Handle __sane_unused__ handle, 3044141cc406Sopenharmony_ci SANE_Bool __sane_unused__ non_blocking) 3045141cc406Sopenharmony_ci{ 3046141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 3047141cc406Sopenharmony_ci} 3048141cc406Sopenharmony_ci 3049141cc406Sopenharmony_ci/* 3050141cc406Sopenharmony_ci * SANE_Status sane_get_select_fd() 3051141cc406Sopenharmony_ci * 3052141cc406Sopenharmony_ci * not supported - for asynchronous I/O 3053141cc406Sopenharmony_ci */ 3054141cc406Sopenharmony_ci 3055141cc406Sopenharmony_ciSANE_Status 3056141cc406Sopenharmony_cisane_get_select_fd(SANE_Handle __sane_unused__ handle, 3057141cc406Sopenharmony_ci SANE_Int __sane_unused__ *fd) 3058141cc406Sopenharmony_ci{ 3059141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 3060141cc406Sopenharmony_ci} 3061