1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2002 Sergey Vlasov <vsu@altlinux.ru> 4141cc406Sopenharmony_ci Copyright (C) 2002 - 2007 Henning Geinitz <sane@geinitz.org> 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci This file is part of the SANE package. 7141cc406Sopenharmony_ci 8141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 9141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 10141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 11141cc406Sopenharmony_ci License, or (at your option) any later version. 12141cc406Sopenharmony_ci 13141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 14141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 15141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16141cc406Sopenharmony_ci General Public License for more details. 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 19141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 22141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 25141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 26141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 27141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 28141cc406Sopenharmony_ci account of linking the SANE library code into it. 29141cc406Sopenharmony_ci 30141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 31141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 32141cc406Sopenharmony_ci License. 33141cc406Sopenharmony_ci 34141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 35141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 36141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 37141cc406Sopenharmony_ci 38141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 39141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 40141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 41141cc406Sopenharmony_ci*/ 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci/** @file 44141cc406Sopenharmony_ci * @brief Implementation of the low-level scanner interface functions. 45141cc406Sopenharmony_ci */ 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci#include "gt68xx_low.h" 48141cc406Sopenharmony_ci 49141cc406Sopenharmony_ci#include "../include/sane/sane.h" 50141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h" 51141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 52141cc406Sopenharmony_ci 53141cc406Sopenharmony_ci#include <stdlib.h> 54141cc406Sopenharmony_ci#include <string.h> 55141cc406Sopenharmony_ci 56141cc406Sopenharmony_ci#ifdef USE_FORK 57141cc406Sopenharmony_ci#include <sys/wait.h> 58141cc406Sopenharmony_ci#include <unistd.h> 59141cc406Sopenharmony_ci#include "gt68xx_shm_channel.c" 60141cc406Sopenharmony_ci#endif 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci/** Check that the device pointer is not NULL. 63141cc406Sopenharmony_ci * 64141cc406Sopenharmony_ci * @param dev Pointer to the device object (GT68xx_Device). 65141cc406Sopenharmony_ci * @param func_name Function name (for use in debug messages). 66141cc406Sopenharmony_ci */ 67141cc406Sopenharmony_ci#define CHECK_DEV_NOT_NULL(dev, func_name) \ 68141cc406Sopenharmony_ci do { \ 69141cc406Sopenharmony_ci IF_DBG( \ 70141cc406Sopenharmony_ci if (!(dev)) \ 71141cc406Sopenharmony_ci { \ 72141cc406Sopenharmony_ci DBG (0, "BUG: NULL device\n"); \ 73141cc406Sopenharmony_ci return SANE_STATUS_INVAL; \ 74141cc406Sopenharmony_ci } \ 75141cc406Sopenharmony_ci ) \ 76141cc406Sopenharmony_ci } while (SANE_FALSE) 77141cc406Sopenharmony_ci 78141cc406Sopenharmony_ci/** Check that the device is open. 79141cc406Sopenharmony_ci * 80141cc406Sopenharmony_ci * @param dev Pointer to the device object (GT68xx_Device). 81141cc406Sopenharmony_ci * @param func_name Function name (for use in debug messages). 82141cc406Sopenharmony_ci */ 83141cc406Sopenharmony_ci#define CHECK_DEV_OPEN(dev, func_name) \ 84141cc406Sopenharmony_ci do { \ 85141cc406Sopenharmony_ci IF_DBG( \ 86141cc406Sopenharmony_ci CHECK_DEV_NOT_NULL ((dev), (func_name)); \ 87141cc406Sopenharmony_ci if ((dev)->fd == -1) \ 88141cc406Sopenharmony_ci { \ 89141cc406Sopenharmony_ci DBG (0, "%s: BUG: device %p not open\n", (func_name), \ 90141cc406Sopenharmony_ci ((void *) dev)); \ 91141cc406Sopenharmony_ci return SANE_STATUS_INVAL; \ 92141cc406Sopenharmony_ci } \ 93141cc406Sopenharmony_ci ) \ 94141cc406Sopenharmony_ci } while (SANE_FALSE) 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_ci/** Check that the device is open and active. 97141cc406Sopenharmony_ci * 98141cc406Sopenharmony_ci * @param dev Pointer to the device (GT68xx_Device). 99141cc406Sopenharmony_ci * @param func_name Function name (for use in debug messages). 100141cc406Sopenharmony_ci */ 101141cc406Sopenharmony_ci#define CHECK_DEV_ACTIVE(dev, func_name) \ 102141cc406Sopenharmony_ci do { \ 103141cc406Sopenharmony_ci IF_DBG( \ 104141cc406Sopenharmony_ci CHECK_DEV_OPEN ((dev), (func_name)); \ 105141cc406Sopenharmony_ci if (!(dev)->active) \ 106141cc406Sopenharmony_ci { \ 107141cc406Sopenharmony_ci DBG (0, "%s: BUG: device %p not active\n", (func_name), \ 108141cc406Sopenharmony_ci ((void *) dev)); \ 109141cc406Sopenharmony_ci return SANE_STATUS_INVAL; \ 110141cc406Sopenharmony_ci } \ 111141cc406Sopenharmony_ci ) \ 112141cc406Sopenharmony_ci } while (SANE_FALSE) 113141cc406Sopenharmony_ci 114141cc406Sopenharmony_ci 115141cc406Sopenharmony_ci#ifndef NDEBUG 116141cc406Sopenharmony_ci 117141cc406Sopenharmony_ci/** Dump a request packet for debugging purposes. 118141cc406Sopenharmony_ci * 119141cc406Sopenharmony_ci * @param prefix String printed before the packet contents. 120141cc406Sopenharmony_ci * @param req The request packet to be dumped. 121141cc406Sopenharmony_ci */ 122141cc406Sopenharmony_cistatic void 123141cc406Sopenharmony_cidump_req (SANE_String_Const prefix, GT68xx_Packet req) 124141cc406Sopenharmony_ci{ 125141cc406Sopenharmony_ci int i; 126141cc406Sopenharmony_ci char buf[GT68XX_PACKET_SIZE * 3 + 1]; 127141cc406Sopenharmony_ci 128141cc406Sopenharmony_ci for (i = 0; i < GT68XX_PACKET_SIZE; ++i) 129141cc406Sopenharmony_ci sprintf (buf + i * 3, " %02x", req[i]); 130141cc406Sopenharmony_ci DBG (8, "%s%s\n", prefix, buf); 131141cc406Sopenharmony_ci} 132141cc406Sopenharmony_ci 133141cc406Sopenharmony_ci#endif /* not NDEBUG */ 134141cc406Sopenharmony_ci 135141cc406Sopenharmony_ci/** Dump a request packet if the debug level is at 8 or above. 136141cc406Sopenharmony_ci * 137141cc406Sopenharmony_ci * @param prefix String printed before the packet contents. 138141cc406Sopenharmony_ci * @param req The request packet to be dumped. 139141cc406Sopenharmony_ci */ 140141cc406Sopenharmony_ci#define DUMP_REQ(prefix, req) \ 141141cc406Sopenharmony_ci do { IF_DBG( if (DBG_LEVEL >= 8) dump_req ((prefix), (req)); ) } while (0) 142141cc406Sopenharmony_ci 143141cc406Sopenharmony_ci 144141cc406Sopenharmony_ciSANE_Status 145141cc406Sopenharmony_cigt68xx_device_new (GT68xx_Device ** dev_return) 146141cc406Sopenharmony_ci{ 147141cc406Sopenharmony_ci GT68xx_Device *dev; 148141cc406Sopenharmony_ci 149141cc406Sopenharmony_ci DBG (7, "gt68xx_device_new: enter\n"); 150141cc406Sopenharmony_ci if (!dev_return) 151141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 152141cc406Sopenharmony_ci 153141cc406Sopenharmony_ci dev = (GT68xx_Device *) malloc (sizeof (GT68xx_Device)); 154141cc406Sopenharmony_ci 155141cc406Sopenharmony_ci if (!dev) 156141cc406Sopenharmony_ci { 157141cc406Sopenharmony_ci DBG (3, "gt68xx_device_new: couldn't malloc %lu bytes for device\n", 158141cc406Sopenharmony_ci (u_long) sizeof (GT68xx_Device)); 159141cc406Sopenharmony_ci *dev_return = 0; 160141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 161141cc406Sopenharmony_ci } 162141cc406Sopenharmony_ci *dev_return = dev; 163141cc406Sopenharmony_ci 164141cc406Sopenharmony_ci memset (dev, 0, sizeof (GT68xx_Device)); 165141cc406Sopenharmony_ci 166141cc406Sopenharmony_ci dev->fd = -1; 167141cc406Sopenharmony_ci dev->active = SANE_FALSE; 168141cc406Sopenharmony_ci 169141cc406Sopenharmony_ci dev->model = NULL; 170141cc406Sopenharmony_ci dev->command_set_private = NULL; 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_ci dev->read_buffer = NULL; 173141cc406Sopenharmony_ci dev->read_buffer_size = 32768; 174141cc406Sopenharmony_ci 175141cc406Sopenharmony_ci dev->manual_selection = SANE_FALSE; 176141cc406Sopenharmony_ci 177141cc406Sopenharmony_ci dev->scan_started = SANE_FALSE; 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci#ifdef USE_FORK 180141cc406Sopenharmony_ci dev->shm_channel = NULL; 181141cc406Sopenharmony_ci#endif /* USE_FORK */ 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_ci DBG (7, "gt68xx_device_new:: leave: ok\n"); 184141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 185141cc406Sopenharmony_ci} 186141cc406Sopenharmony_ci 187141cc406Sopenharmony_ciSANE_Status 188141cc406Sopenharmony_cigt68xx_device_free (GT68xx_Device * dev) 189141cc406Sopenharmony_ci{ 190141cc406Sopenharmony_ci DBG (7, "gt68xx_device_free: enter: dev=%p\n", (void *) dev); 191141cc406Sopenharmony_ci if (dev) 192141cc406Sopenharmony_ci { 193141cc406Sopenharmony_ci if (dev->active) 194141cc406Sopenharmony_ci gt68xx_device_deactivate (dev); 195141cc406Sopenharmony_ci 196141cc406Sopenharmony_ci if (dev->fd != -1) 197141cc406Sopenharmony_ci gt68xx_device_close (dev); 198141cc406Sopenharmony_ci 199141cc406Sopenharmony_ci if (dev->model && dev->model->allocated) 200141cc406Sopenharmony_ci { 201141cc406Sopenharmony_ci DBG (7, "gt68xx_device_free: freeing model data %p\n", 202141cc406Sopenharmony_ci (void *) dev->model); 203141cc406Sopenharmony_ci free (dev->model); 204141cc406Sopenharmony_ci } 205141cc406Sopenharmony_ci 206141cc406Sopenharmony_ci DBG (7, "gt68xx_device_free: freeing dev\n"); 207141cc406Sopenharmony_ci free (dev); 208141cc406Sopenharmony_ci } 209141cc406Sopenharmony_ci DBG (7, "gt68xx_device_free: leave: ok\n"); 210141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 211141cc406Sopenharmony_ci} 212141cc406Sopenharmony_ci 213141cc406Sopenharmony_cistatic GT68xx_USB_Device_Entry * 214141cc406Sopenharmony_cigt68xx_find_usb_device_entry (SANE_Word vendor, SANE_Word product) 215141cc406Sopenharmony_ci{ 216141cc406Sopenharmony_ci GT68xx_USB_Device_Entry *entry; 217141cc406Sopenharmony_ci 218141cc406Sopenharmony_ci for (entry = gt68xx_usb_device_list; entry->model; ++entry) 219141cc406Sopenharmony_ci { 220141cc406Sopenharmony_ci if (vendor == entry->vendor && product == entry->product) 221141cc406Sopenharmony_ci return entry; 222141cc406Sopenharmony_ci } 223141cc406Sopenharmony_ci 224141cc406Sopenharmony_ci return NULL; 225141cc406Sopenharmony_ci} 226141cc406Sopenharmony_ci 227141cc406Sopenharmony_cistatic SANE_Status 228141cc406Sopenharmony_cigt68xx_device_identify (GT68xx_Device * dev) 229141cc406Sopenharmony_ci{ 230141cc406Sopenharmony_ci SANE_Status status; 231141cc406Sopenharmony_ci SANE_Word vendor, product; 232141cc406Sopenharmony_ci GT68xx_USB_Device_Entry *entry; 233141cc406Sopenharmony_ci 234141cc406Sopenharmony_ci CHECK_DEV_OPEN (dev, "gt68xx_device_identify"); 235141cc406Sopenharmony_ci 236141cc406Sopenharmony_ci status = sanei_usb_get_vendor_product (dev->fd, &vendor, &product); 237141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 238141cc406Sopenharmony_ci { 239141cc406Sopenharmony_ci DBG (3, "gt68xx_device_identify: error getting USB id: %s\n", 240141cc406Sopenharmony_ci sane_strstatus (status)); 241141cc406Sopenharmony_ci return status; 242141cc406Sopenharmony_ci } 243141cc406Sopenharmony_ci 244141cc406Sopenharmony_ci entry = gt68xx_find_usb_device_entry (vendor, product); 245141cc406Sopenharmony_ci 246141cc406Sopenharmony_ci if (entry) 247141cc406Sopenharmony_ci { 248141cc406Sopenharmony_ci dev->model = entry->model; 249141cc406Sopenharmony_ci } 250141cc406Sopenharmony_ci else 251141cc406Sopenharmony_ci { 252141cc406Sopenharmony_ci dev->model = NULL; 253141cc406Sopenharmony_ci DBG (3, "gt68xx_device_identify: unknown USB device (vendor 0x%04x, " 254141cc406Sopenharmony_ci "product 0x%04x)\n", vendor, product); 255141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 256141cc406Sopenharmony_ci } 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 259141cc406Sopenharmony_ci} 260141cc406Sopenharmony_ci 261141cc406Sopenharmony_ciSANE_Status 262141cc406Sopenharmony_cigt68xx_device_open (GT68xx_Device * dev, const char *dev_name) 263141cc406Sopenharmony_ci{ 264141cc406Sopenharmony_ci SANE_Status status; 265141cc406Sopenharmony_ci SANE_Int fd; 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci DBG (7, "gt68xx_device_open: enter: dev=%p\n", (void *) dev); 268141cc406Sopenharmony_ci 269141cc406Sopenharmony_ci CHECK_DEV_NOT_NULL (dev, "gt68xx_device_open"); 270141cc406Sopenharmony_ci 271141cc406Sopenharmony_ci if (dev->fd != -1) 272141cc406Sopenharmony_ci { 273141cc406Sopenharmony_ci DBG (3, "gt68xx_device_open: device already open\n"); 274141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 275141cc406Sopenharmony_ci } 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci status = sanei_usb_open (dev_name, &fd); 278141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 279141cc406Sopenharmony_ci { 280141cc406Sopenharmony_ci DBG (3, "gt68xx_device_open: sanei_usb_open failed: %s\n", 281141cc406Sopenharmony_ci sane_strstatus (status)); 282141cc406Sopenharmony_ci return status; 283141cc406Sopenharmony_ci } 284141cc406Sopenharmony_ci 285141cc406Sopenharmony_ci dev->fd = fd; 286141cc406Sopenharmony_ci 287141cc406Sopenharmony_ci if (!dev->model) 288141cc406Sopenharmony_ci gt68xx_device_identify (dev); 289141cc406Sopenharmony_ci 290141cc406Sopenharmony_ci DBG (7, "gt68xx_device_open: leave: ok\n"); 291141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 292141cc406Sopenharmony_ci} 293141cc406Sopenharmony_ci 294141cc406Sopenharmony_ciSANE_Status 295141cc406Sopenharmony_cigt68xx_device_close (GT68xx_Device * dev) 296141cc406Sopenharmony_ci{ 297141cc406Sopenharmony_ci DBG (7, "gt68xx_device_close: enter: dev=%p\n", (void *) dev); 298141cc406Sopenharmony_ci 299141cc406Sopenharmony_ci CHECK_DEV_OPEN (dev, "gt68xx_device_close"); 300141cc406Sopenharmony_ci 301141cc406Sopenharmony_ci if (dev->active) 302141cc406Sopenharmony_ci gt68xx_device_deactivate (dev); 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ci sanei_usb_close (dev->fd); 305141cc406Sopenharmony_ci dev->fd = -1; 306141cc406Sopenharmony_ci 307141cc406Sopenharmony_ci DBG (7, "gt68xx_device_close: leave: ok\n"); 308141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 309141cc406Sopenharmony_ci} 310141cc406Sopenharmony_ci 311141cc406Sopenharmony_ciSANE_Bool 312141cc406Sopenharmony_cigt68xx_device_is_configured (GT68xx_Device * dev) 313141cc406Sopenharmony_ci{ 314141cc406Sopenharmony_ci if (dev && dev->model && dev->model->command_set) 315141cc406Sopenharmony_ci return SANE_TRUE; 316141cc406Sopenharmony_ci else 317141cc406Sopenharmony_ci return SANE_FALSE; 318141cc406Sopenharmony_ci} 319141cc406Sopenharmony_ci 320141cc406Sopenharmony_ciSANE_Status 321141cc406Sopenharmony_cigt68xx_device_set_model (GT68xx_Device * dev, GT68xx_Model * model) 322141cc406Sopenharmony_ci{ 323141cc406Sopenharmony_ci if (dev->active) 324141cc406Sopenharmony_ci { 325141cc406Sopenharmony_ci DBG (3, "gt68xx_device_set_model: device already active\n"); 326141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 327141cc406Sopenharmony_ci } 328141cc406Sopenharmony_ci 329141cc406Sopenharmony_ci if (dev->model && dev->model->allocated) 330141cc406Sopenharmony_ci free (dev->model); 331141cc406Sopenharmony_ci 332141cc406Sopenharmony_ci dev->model = model; 333141cc406Sopenharmony_ci 334141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 335141cc406Sopenharmony_ci} 336141cc406Sopenharmony_ci 337141cc406Sopenharmony_cistatic SANE_Bool 338141cc406Sopenharmony_cigt68xx_device_get_model (SANE_String name, GT68xx_Model ** model) 339141cc406Sopenharmony_ci{ 340141cc406Sopenharmony_ci GT68xx_USB_Device_Entry *entry; 341141cc406Sopenharmony_ci 342141cc406Sopenharmony_ci for (entry = gt68xx_usb_device_list; entry->model; ++entry) 343141cc406Sopenharmony_ci { 344141cc406Sopenharmony_ci if (strcmp (name, entry->model->name) == 0) 345141cc406Sopenharmony_ci { 346141cc406Sopenharmony_ci *model = entry->model; 347141cc406Sopenharmony_ci return SANE_TRUE; 348141cc406Sopenharmony_ci } 349141cc406Sopenharmony_ci } 350141cc406Sopenharmony_ci return SANE_FALSE; 351141cc406Sopenharmony_ci} 352141cc406Sopenharmony_ci 353141cc406Sopenharmony_ci 354141cc406Sopenharmony_ciSANE_Status 355141cc406Sopenharmony_cigt68xx_device_activate (GT68xx_Device * dev) 356141cc406Sopenharmony_ci{ 357141cc406Sopenharmony_ci SANE_Status status; 358141cc406Sopenharmony_ci CHECK_DEV_OPEN (dev, "gt68xx_device_activate"); 359141cc406Sopenharmony_ci if (dev->active) 360141cc406Sopenharmony_ci { 361141cc406Sopenharmony_ci DBG (3, "gt68xx_device_activate: device already active\n"); 362141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 363141cc406Sopenharmony_ci } 364141cc406Sopenharmony_ci 365141cc406Sopenharmony_ci if (!gt68xx_device_is_configured (dev)) 366141cc406Sopenharmony_ci { 367141cc406Sopenharmony_ci DBG (3, "gt68xx_device_activate: device is not configured\n"); 368141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 369141cc406Sopenharmony_ci } 370141cc406Sopenharmony_ci 371141cc406Sopenharmony_ci DBG (7, "gt68xx_device_activate: model \"%s\"\n", dev->model->name); 372141cc406Sopenharmony_ci if (dev->model->command_set->activate) 373141cc406Sopenharmony_ci { 374141cc406Sopenharmony_ci status = (*dev->model->command_set->activate) (dev); 375141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 376141cc406Sopenharmony_ci { 377141cc406Sopenharmony_ci DBG (3, "gt68xx_device_activate: command-set-specific " 378141cc406Sopenharmony_ci "activate failed: %s\n", sane_strstatus (status)); 379141cc406Sopenharmony_ci return status; 380141cc406Sopenharmony_ci } 381141cc406Sopenharmony_ci } 382141cc406Sopenharmony_ci dev->afe = malloc (sizeof (*dev->afe)); 383141cc406Sopenharmony_ci dev->exposure = malloc (sizeof (*dev->exposure)); 384141cc406Sopenharmony_ci if (!dev->afe || !dev->exposure) 385141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 386141cc406Sopenharmony_ci memcpy (dev->afe, &dev->model->afe_params, sizeof (*dev->afe)); 387141cc406Sopenharmony_ci memcpy (dev->exposure, &dev->model->exposure, sizeof (*dev->exposure)); 388141cc406Sopenharmony_ci dev->gamma_value = dev->model->default_gamma_value; 389141cc406Sopenharmony_ci dev->active = SANE_TRUE; 390141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 391141cc406Sopenharmony_ci} 392141cc406Sopenharmony_ci 393141cc406Sopenharmony_ciSANE_Status 394141cc406Sopenharmony_cigt68xx_device_deactivate (GT68xx_Device * dev) 395141cc406Sopenharmony_ci{ 396141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 397141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_deactivate"); 398141cc406Sopenharmony_ci if (dev->read_active) 399141cc406Sopenharmony_ci gt68xx_device_read_finish (dev); 400141cc406Sopenharmony_ci if (dev->model->command_set->deactivate) 401141cc406Sopenharmony_ci { 402141cc406Sopenharmony_ci status = (*dev->model->command_set->deactivate) (dev); 403141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 404141cc406Sopenharmony_ci { 405141cc406Sopenharmony_ci DBG (3, 406141cc406Sopenharmony_ci "gt68xx_device_deactivate: command set-specific deactivate failed: %s\n", 407141cc406Sopenharmony_ci sane_strstatus (status)); 408141cc406Sopenharmony_ci /* proceed with deactivate anyway */ 409141cc406Sopenharmony_ci } 410141cc406Sopenharmony_ci } 411141cc406Sopenharmony_ci if (dev->afe) 412141cc406Sopenharmony_ci free (dev->afe); 413141cc406Sopenharmony_ci dev->afe = 0; 414141cc406Sopenharmony_ci if (dev->exposure) 415141cc406Sopenharmony_ci free (dev->exposure); 416141cc406Sopenharmony_ci dev->exposure = 0; 417141cc406Sopenharmony_ci dev->active = SANE_FALSE; 418141cc406Sopenharmony_ci return status; 419141cc406Sopenharmony_ci} 420141cc406Sopenharmony_ci 421141cc406Sopenharmony_ciSANE_Status 422141cc406Sopenharmony_cigt68xx_device_memory_write (GT68xx_Device * dev, 423141cc406Sopenharmony_ci SANE_Word addr, SANE_Word size, SANE_Byte * data) 424141cc406Sopenharmony_ci{ 425141cc406Sopenharmony_ci SANE_Status status; 426141cc406Sopenharmony_ci DBG (8, 427141cc406Sopenharmony_ci "gt68xx_device_memory_write: dev=%p, addr=0x%x, size=0x%x, data=%p\n", 428141cc406Sopenharmony_ci (void *) dev, addr, size, (void *) data); 429141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_memory_write"); 430141cc406Sopenharmony_ci status = 431141cc406Sopenharmony_ci sanei_usb_control_msg (dev->fd, 0x40, 432141cc406Sopenharmony_ci dev->model->command_set->request, 433141cc406Sopenharmony_ci dev->model->command_set->memory_write_value, 434141cc406Sopenharmony_ci addr, size, data); 435141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 436141cc406Sopenharmony_ci { 437141cc406Sopenharmony_ci DBG (3, 438141cc406Sopenharmony_ci "gt68xx_device_memory_write: sanei_usb_control_msg failed: %s\n", 439141cc406Sopenharmony_ci sane_strstatus (status)); 440141cc406Sopenharmony_ci } 441141cc406Sopenharmony_ci return status; 442141cc406Sopenharmony_ci} 443141cc406Sopenharmony_ci 444141cc406Sopenharmony_ciSANE_Status 445141cc406Sopenharmony_cigt68xx_device_memory_read (GT68xx_Device * dev, 446141cc406Sopenharmony_ci SANE_Word addr, SANE_Word size, SANE_Byte * data) 447141cc406Sopenharmony_ci{ 448141cc406Sopenharmony_ci SANE_Status status; 449141cc406Sopenharmony_ci DBG (8, 450141cc406Sopenharmony_ci "gt68xx_device_memory_read: dev=%p, addr=0x%x, size=0x%x, data=%p\n", 451141cc406Sopenharmony_ci (void *) dev, addr, size, (void *) data); 452141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_memory_read"); 453141cc406Sopenharmony_ci status = 454141cc406Sopenharmony_ci sanei_usb_control_msg (dev->fd, 0xc0, 455141cc406Sopenharmony_ci dev->model->command_set->request, 456141cc406Sopenharmony_ci dev->model->command_set->memory_read_value, 457141cc406Sopenharmony_ci addr, size, data); 458141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 459141cc406Sopenharmony_ci { 460141cc406Sopenharmony_ci DBG (3, 461141cc406Sopenharmony_ci "gt68xx_device_memory_read: sanei_usb_control_msg failed: %s\n", 462141cc406Sopenharmony_ci sane_strstatus (status)); 463141cc406Sopenharmony_ci } 464141cc406Sopenharmony_ci 465141cc406Sopenharmony_ci return status; 466141cc406Sopenharmony_ci} 467141cc406Sopenharmony_ci 468141cc406Sopenharmony_cistatic SANE_Status 469141cc406Sopenharmony_cigt68xx_device_generic_req (GT68xx_Device * dev, 470141cc406Sopenharmony_ci SANE_Byte request_type, SANE_Word request, 471141cc406Sopenharmony_ci SANE_Word cmd_value, SANE_Word cmd_index, 472141cc406Sopenharmony_ci SANE_Word res_value, SANE_Word res_index, 473141cc406Sopenharmony_ci GT68xx_Packet cmd, GT68xx_Packet res, 474141cc406Sopenharmony_ci size_t res_size) 475141cc406Sopenharmony_ci{ 476141cc406Sopenharmony_ci SANE_Status status; 477141cc406Sopenharmony_ci DBG (7, "gt68xx_device_generic_req: command=0x%02x\n", cmd[0]); 478141cc406Sopenharmony_ci DUMP_REQ (">>", cmd); 479141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_generic_req"); 480141cc406Sopenharmony_ci status = sanei_usb_control_msg (dev->fd, 481141cc406Sopenharmony_ci request_type, request, cmd_value, 482141cc406Sopenharmony_ci cmd_index, GT68XX_PACKET_SIZE, cmd); 483141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 484141cc406Sopenharmony_ci { 485141cc406Sopenharmony_ci DBG (3, "gt68xx_device_generic_req: writing command failed: %s\n", 486141cc406Sopenharmony_ci sane_strstatus (status)); 487141cc406Sopenharmony_ci return status; 488141cc406Sopenharmony_ci } 489141cc406Sopenharmony_ci 490141cc406Sopenharmony_ci memset (res, 0, sizeof (GT68xx_Packet)); 491141cc406Sopenharmony_ci status = sanei_usb_control_msg (dev->fd, 492141cc406Sopenharmony_ci request_type | 0x80, request, 493141cc406Sopenharmony_ci res_value, res_index, res_size, res); 494141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 495141cc406Sopenharmony_ci { 496141cc406Sopenharmony_ci DBG (3, "gt68xx_device_generic_req: reading response failed: %s\n", 497141cc406Sopenharmony_ci sane_strstatus (status)); 498141cc406Sopenharmony_ci return status; 499141cc406Sopenharmony_ci } 500141cc406Sopenharmony_ci 501141cc406Sopenharmony_ci DUMP_REQ ("<<", res); 502141cc406Sopenharmony_ci return status; 503141cc406Sopenharmony_ci} 504141cc406Sopenharmony_ci 505141cc406Sopenharmony_ciSANE_Status 506141cc406Sopenharmony_cigt68xx_device_req (GT68xx_Device * dev, GT68xx_Packet cmd, GT68xx_Packet res) 507141cc406Sopenharmony_ci{ 508141cc406Sopenharmony_ci GT68xx_Command_Set *command_set = dev->model->command_set; 509141cc406Sopenharmony_ci return gt68xx_device_generic_req (dev, 510141cc406Sopenharmony_ci command_set->request_type, 511141cc406Sopenharmony_ci command_set->request, 512141cc406Sopenharmony_ci command_set->send_cmd_value, 513141cc406Sopenharmony_ci command_set->send_cmd_index, 514141cc406Sopenharmony_ci command_set->recv_res_value, 515141cc406Sopenharmony_ci command_set->recv_res_index, cmd, 516141cc406Sopenharmony_ci res, GT68XX_PACKET_SIZE); 517141cc406Sopenharmony_ci} 518141cc406Sopenharmony_ci 519141cc406Sopenharmony_ciSANE_Status 520141cc406Sopenharmony_cigt68xx_device_small_req (GT68xx_Device * dev, GT68xx_Packet cmd, 521141cc406Sopenharmony_ci GT68xx_Packet res) 522141cc406Sopenharmony_ci{ 523141cc406Sopenharmony_ci GT68xx_Command_Set *command_set = dev->model->command_set; 524141cc406Sopenharmony_ci GT68xx_Packet fixed_cmd; 525141cc406Sopenharmony_ci int i; 526141cc406Sopenharmony_ci for (i = 0; i < 8; ++i) 527141cc406Sopenharmony_ci memcpy (fixed_cmd + i * 8, cmd, 8); 528141cc406Sopenharmony_ci return gt68xx_device_generic_req (dev, 529141cc406Sopenharmony_ci command_set->request_type, 530141cc406Sopenharmony_ci command_set->request, 531141cc406Sopenharmony_ci command_set->send_small_cmd_value, 532141cc406Sopenharmony_ci command_set->send_small_cmd_index, 533141cc406Sopenharmony_ci command_set->recv_small_res_value, 534141cc406Sopenharmony_ci command_set->recv_small_res_index, 535141cc406Sopenharmony_ci fixed_cmd, res, 0x08); 536141cc406Sopenharmony_ci} 537141cc406Sopenharmony_ci 538141cc406Sopenharmony_ci 539141cc406Sopenharmony_ciSANE_Status 540141cc406Sopenharmony_cigt68xx_device_download_firmware (GT68xx_Device * dev, 541141cc406Sopenharmony_ci SANE_Byte * data, SANE_Word size) 542141cc406Sopenharmony_ci{ 543141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_download_firmware"); 544141cc406Sopenharmony_ci if (dev->model->command_set->download_firmware) 545141cc406Sopenharmony_ci return (*dev->model->command_set->download_firmware) (dev, data, size); 546141cc406Sopenharmony_ci else 547141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 548141cc406Sopenharmony_ci} 549141cc406Sopenharmony_ci 550141cc406Sopenharmony_ciSANE_Status 551141cc406Sopenharmony_cigt68xx_device_get_power_status (GT68xx_Device * dev, SANE_Bool * power_ok) 552141cc406Sopenharmony_ci{ 553141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_get_power_status"); 554141cc406Sopenharmony_ci if (dev->model->command_set->get_power_status) 555141cc406Sopenharmony_ci return (*dev->model->command_set->get_power_status) (dev, power_ok); 556141cc406Sopenharmony_ci else 557141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 558141cc406Sopenharmony_ci} 559141cc406Sopenharmony_ci 560141cc406Sopenharmony_ciSANE_Status 561141cc406Sopenharmony_cigt68xx_device_get_ta_status (GT68xx_Device * dev, SANE_Bool * ta_attached) 562141cc406Sopenharmony_ci{ 563141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_get_ta_status"); 564141cc406Sopenharmony_ci if (dev->model->command_set->get_ta_status) 565141cc406Sopenharmony_ci return (*dev->model->command_set->get_ta_status) (dev, ta_attached); 566141cc406Sopenharmony_ci else 567141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 568141cc406Sopenharmony_ci} 569141cc406Sopenharmony_ci 570141cc406Sopenharmony_ciSANE_Status 571141cc406Sopenharmony_cigt68xx_device_lamp_control (GT68xx_Device * dev, SANE_Bool fb_lamp, 572141cc406Sopenharmony_ci SANE_Bool ta_lamp) 573141cc406Sopenharmony_ci{ 574141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_lamp_control"); 575141cc406Sopenharmony_ci if (dev->model->command_set->lamp_control) 576141cc406Sopenharmony_ci return (*dev->model->command_set->lamp_control) (dev, fb_lamp, ta_lamp); 577141cc406Sopenharmony_ci else 578141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 579141cc406Sopenharmony_ci} 580141cc406Sopenharmony_ci 581141cc406Sopenharmony_ciSANE_Status 582141cc406Sopenharmony_cigt68xx_device_is_moving (GT68xx_Device * dev, SANE_Bool * moving) 583141cc406Sopenharmony_ci{ 584141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_is_moving"); 585141cc406Sopenharmony_ci if (dev->model->command_set->is_moving) 586141cc406Sopenharmony_ci return (*dev->model->command_set->is_moving) (dev, moving); 587141cc406Sopenharmony_ci else 588141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 589141cc406Sopenharmony_ci} 590141cc406Sopenharmony_ci 591141cc406Sopenharmony_ci/* currently not used */ 592141cc406Sopenharmony_ci#if 0 593141cc406Sopenharmony_cistatic SANE_Status 594141cc406Sopenharmony_cigt68xx_device_move_relative (GT68xx_Device * dev, SANE_Int distance) 595141cc406Sopenharmony_ci{ 596141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_move_relative"); 597141cc406Sopenharmony_ci if (dev->model->command_set->move_relative) 598141cc406Sopenharmony_ci return (*dev->model->command_set->move_relative) (dev, distance); 599141cc406Sopenharmony_ci else 600141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 601141cc406Sopenharmony_ci} 602141cc406Sopenharmony_ci#endif 603141cc406Sopenharmony_ci 604141cc406Sopenharmony_ciSANE_Status 605141cc406Sopenharmony_cigt68xx_device_carriage_home (GT68xx_Device * dev) 606141cc406Sopenharmony_ci{ 607141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_carriage_home"); 608141cc406Sopenharmony_ci if (dev->model->command_set->carriage_home) 609141cc406Sopenharmony_ci return (*dev->model->command_set->carriage_home) (dev); 610141cc406Sopenharmony_ci else 611141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 612141cc406Sopenharmony_ci} 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ciSANE_Status 615141cc406Sopenharmony_cigt68xx_device_paperfeed (GT68xx_Device * dev) 616141cc406Sopenharmony_ci{ 617141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_paperfeed"); 618141cc406Sopenharmony_ci if (dev->model->command_set->paperfeed) 619141cc406Sopenharmony_ci return (*dev->model->command_set->paperfeed) (dev); 620141cc406Sopenharmony_ci else 621141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 622141cc406Sopenharmony_ci} 623141cc406Sopenharmony_ci 624141cc406Sopenharmony_ciSANE_Status 625141cc406Sopenharmony_cigt68xx_device_start_scan (GT68xx_Device * dev) 626141cc406Sopenharmony_ci{ 627141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_start_scan"); 628141cc406Sopenharmony_ci if (dev->model->command_set->start_scan) 629141cc406Sopenharmony_ci { 630141cc406Sopenharmony_ci if (!dev->scan_started) 631141cc406Sopenharmony_ci { 632141cc406Sopenharmony_ci dev->scan_started = SANE_TRUE; 633141cc406Sopenharmony_ci return (*dev->model->command_set->start_scan) (dev); 634141cc406Sopenharmony_ci } 635141cc406Sopenharmony_ci return SANE_STATUS_DEVICE_BUSY; 636141cc406Sopenharmony_ci } 637141cc406Sopenharmony_ci else 638141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 639141cc406Sopenharmony_ci} 640141cc406Sopenharmony_ci 641141cc406Sopenharmony_ciSANE_Status 642141cc406Sopenharmony_cigt68xx_device_read_scanned_data (GT68xx_Device * dev, SANE_Bool * ready) 643141cc406Sopenharmony_ci{ 644141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_scanned_data"); 645141cc406Sopenharmony_ci if (dev->model->command_set->read_scanned_data) 646141cc406Sopenharmony_ci return (*dev->model->command_set->read_scanned_data) (dev, ready); 647141cc406Sopenharmony_ci else 648141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 649141cc406Sopenharmony_ci} 650141cc406Sopenharmony_ci 651141cc406Sopenharmony_ciSANE_Status 652141cc406Sopenharmony_cigt68xx_device_setup_scan (GT68xx_Device * dev, 653141cc406Sopenharmony_ci GT68xx_Scan_Request * request, 654141cc406Sopenharmony_ci GT68xx_Scan_Action action, 655141cc406Sopenharmony_ci GT68xx_Scan_Parameters * params) 656141cc406Sopenharmony_ci{ 657141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_setup_scan"); 658141cc406Sopenharmony_ci if (dev->model->command_set->setup_scan) 659141cc406Sopenharmony_ci return (*dev->model->command_set->setup_scan) (dev, request, action, 660141cc406Sopenharmony_ci params); 661141cc406Sopenharmony_ci else 662141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 663141cc406Sopenharmony_ci} 664141cc406Sopenharmony_ci 665141cc406Sopenharmony_ciSANE_Status 666141cc406Sopenharmony_cigt68xx_device_set_afe (GT68xx_Device * dev, GT68xx_AFE_Parameters * params) 667141cc406Sopenharmony_ci{ 668141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_set_afe"); 669141cc406Sopenharmony_ci if (dev->model->command_set->set_afe) 670141cc406Sopenharmony_ci return (*dev->model->command_set->set_afe) (dev, params); 671141cc406Sopenharmony_ci else 672141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 673141cc406Sopenharmony_ci} 674141cc406Sopenharmony_ci 675141cc406Sopenharmony_ciSANE_Status 676141cc406Sopenharmony_cigt68xx_device_set_exposure_time (GT68xx_Device * dev, 677141cc406Sopenharmony_ci GT68xx_Exposure_Parameters * params) 678141cc406Sopenharmony_ci{ 679141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_set_exposure_time"); 680141cc406Sopenharmony_ci if (dev->model->command_set->set_exposure_time) 681141cc406Sopenharmony_ci return (*dev->model->command_set->set_exposure_time) (dev, params); 682141cc406Sopenharmony_ci else 683141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 684141cc406Sopenharmony_ci} 685141cc406Sopenharmony_ci 686141cc406Sopenharmony_ciSANE_Status 687141cc406Sopenharmony_cigt68xx_device_stop_scan (GT68xx_Device * dev) 688141cc406Sopenharmony_ci{ 689141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_stop_scan"); 690141cc406Sopenharmony_ci if (dev->model->command_set->stop_scan) 691141cc406Sopenharmony_ci { 692141cc406Sopenharmony_ci if (dev->scan_started) 693141cc406Sopenharmony_ci { 694141cc406Sopenharmony_ci dev->scan_started = SANE_FALSE; 695141cc406Sopenharmony_ci return (*dev->model->command_set->stop_scan) (dev); 696141cc406Sopenharmony_ci } 697141cc406Sopenharmony_ci return SANE_STATUS_GOOD; // Essentially a NOP. 698141cc406Sopenharmony_ci } 699141cc406Sopenharmony_ci else 700141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 701141cc406Sopenharmony_ci} 702141cc406Sopenharmony_ci 703141cc406Sopenharmony_ciSANE_Status 704141cc406Sopenharmony_cigt68xx_device_read_raw (GT68xx_Device * dev, SANE_Byte * buffer, 705141cc406Sopenharmony_ci size_t * size) 706141cc406Sopenharmony_ci{ 707141cc406Sopenharmony_ci SANE_Status status; 708141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_raw"); 709141cc406Sopenharmony_ci DBG (7, "gt68xx_device_read_raw: enter: size=%lu\n", (unsigned long) *size); 710141cc406Sopenharmony_ci status = sanei_usb_read_bulk (dev->fd, buffer, size); 711141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 712141cc406Sopenharmony_ci { 713141cc406Sopenharmony_ci DBG (3, "gt68xx_device_read_raw: bulk read failed: %s\n", 714141cc406Sopenharmony_ci sane_strstatus (status)); 715141cc406Sopenharmony_ci return status; 716141cc406Sopenharmony_ci } 717141cc406Sopenharmony_ci DBG (7, "gt68xx_device_read_raw: leave: size=%lu\n", (unsigned long) *size); 718141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 719141cc406Sopenharmony_ci} 720141cc406Sopenharmony_ci 721141cc406Sopenharmony_ciSANE_Status 722141cc406Sopenharmony_cigt68xx_device_set_read_buffer_size (GT68xx_Device * dev, size_t buffer_size) 723141cc406Sopenharmony_ci{ 724141cc406Sopenharmony_ci CHECK_DEV_NOT_NULL (dev, "gt68xx_device_set_read_buffer_size"); 725141cc406Sopenharmony_ci if (dev->read_active) 726141cc406Sopenharmony_ci { 727141cc406Sopenharmony_ci DBG (3, "gt68xx_device_set_read_buffer_size: BUG: read already " 728141cc406Sopenharmony_ci "active\n"); 729141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 730141cc406Sopenharmony_ci } 731141cc406Sopenharmony_ci 732141cc406Sopenharmony_ci buffer_size = (buffer_size + 63UL) & ~63UL; 733141cc406Sopenharmony_ci if (buffer_size > 0) 734141cc406Sopenharmony_ci { 735141cc406Sopenharmony_ci dev->requested_buffer_size = buffer_size; 736141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 737141cc406Sopenharmony_ci } 738141cc406Sopenharmony_ci 739141cc406Sopenharmony_ci DBG (3, "gt68xx_device_set_read_buffer_size: bad buffer size\n"); 740141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 741141cc406Sopenharmony_ci} 742141cc406Sopenharmony_ci 743141cc406Sopenharmony_ciSANE_Status 744141cc406Sopenharmony_cigt68xx_device_read_prepare (GT68xx_Device * dev, 745141cc406Sopenharmony_ci size_t expected_count, SANE_Bool final_scan) 746141cc406Sopenharmony_ci{ 747141cc406Sopenharmony_ci size_t buffer_size; 748141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_prepare"); 749141cc406Sopenharmony_ci if (dev->read_active) 750141cc406Sopenharmony_ci { 751141cc406Sopenharmony_ci DBG (3, "gt68xx_device_read_prepare: read already active\n"); 752141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 753141cc406Sopenharmony_ci } 754141cc406Sopenharmony_ci DBG (5, "gt68xx_device_read_prepare: total size: %lu bytes\n", 755141cc406Sopenharmony_ci (unsigned long) expected_count); 756141cc406Sopenharmony_ci buffer_size = dev->requested_buffer_size; 757141cc406Sopenharmony_ci DBG (5, "gt68xx_device_read_prepare: requested buffer size: %lu\n", 758141cc406Sopenharmony_ci (unsigned long) buffer_size); 759141cc406Sopenharmony_ci if (buffer_size > expected_count) 760141cc406Sopenharmony_ci { 761141cc406Sopenharmony_ci buffer_size = (expected_count + 63UL) & ~63UL; 762141cc406Sopenharmony_ci } 763141cc406Sopenharmony_ci DBG (5, "gt68xx_device_read_prepare: real size: %lu\n", 764141cc406Sopenharmony_ci (unsigned long) buffer_size); 765141cc406Sopenharmony_ci dev->read_buffer_size = buffer_size; 766141cc406Sopenharmony_ci dev->read_buffer = (SANE_Byte *) malloc (buffer_size); 767141cc406Sopenharmony_ci if (!dev->read_buffer) 768141cc406Sopenharmony_ci { 769141cc406Sopenharmony_ci DBG (3, 770141cc406Sopenharmony_ci "gt68xx_device_read_prepare: not enough memory for the read buffer (%lu bytes)\n", 771141cc406Sopenharmony_ci (unsigned long) buffer_size); 772141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 773141cc406Sopenharmony_ci } 774141cc406Sopenharmony_ci 775141cc406Sopenharmony_ci dev->read_active = SANE_TRUE; 776141cc406Sopenharmony_ci dev->final_scan = final_scan; 777141cc406Sopenharmony_ci dev->read_pos = dev->read_bytes_in_buffer = 0; 778141cc406Sopenharmony_ci dev->read_bytes_left = expected_count; 779141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 780141cc406Sopenharmony_ci} 781141cc406Sopenharmony_ci 782141cc406Sopenharmony_ci#ifdef USE_FORK 783141cc406Sopenharmony_ci 784141cc406Sopenharmony_cistatic SANE_Status 785141cc406Sopenharmony_cigt68xx_reader_process (GT68xx_Device * dev) 786141cc406Sopenharmony_ci{ 787141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 788141cc406Sopenharmony_ci SANE_Int buffer_id; 789141cc406Sopenharmony_ci SANE_Byte *buffer_addr; 790141cc406Sopenharmony_ci size_t size; 791141cc406Sopenharmony_ci SANE_Int line = 0; 792141cc406Sopenharmony_ci size_t read_bytes_left = dev->read_bytes_left; 793141cc406Sopenharmony_ci shm_channel_writer_init (dev->shm_channel); 794141cc406Sopenharmony_ci while (read_bytes_left > 0) 795141cc406Sopenharmony_ci { 796141cc406Sopenharmony_ci status = shm_channel_writer_get_buffer (dev->shm_channel, 797141cc406Sopenharmony_ci &buffer_id, &buffer_addr); 798141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 799141cc406Sopenharmony_ci break; 800141cc406Sopenharmony_ci DBG (9, "gt68xx_reader_process: buffer %d: get\n", buffer_id); 801141cc406Sopenharmony_ci size = dev->read_buffer_size; 802141cc406Sopenharmony_ci DBG (9, "gt68xx_reader_process: buffer %d: trying to read %lu bytes " 803141cc406Sopenharmony_ci "(%lu bytes left, line %d)\n", buffer_id, (unsigned long) size, 804141cc406Sopenharmony_ci (unsigned long) read_bytes_left, line); 805141cc406Sopenharmony_ci status = gt68xx_device_read_raw (dev, buffer_addr, &size); 806141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 807141cc406Sopenharmony_ci break; 808141cc406Sopenharmony_ci DBG (9, 809141cc406Sopenharmony_ci "gt68xx_reader_process: buffer %d: read %lu bytes (line %d)\n", 810141cc406Sopenharmony_ci buffer_id, (unsigned long) size, line); 811141cc406Sopenharmony_ci status = 812141cc406Sopenharmony_ci shm_channel_writer_put_buffer (dev->shm_channel, buffer_id, size); 813141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 814141cc406Sopenharmony_ci break; 815141cc406Sopenharmony_ci DBG (9, "gt68xx_reader_process: buffer %d: put\n", buffer_id); 816141cc406Sopenharmony_ci read_bytes_left -= size; 817141cc406Sopenharmony_ci line++; 818141cc406Sopenharmony_ci } 819141cc406Sopenharmony_ci DBG (9, "gt68xx_reader_process: finished, now sleeping\n"); 820141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 821141cc406Sopenharmony_ci return status; 822141cc406Sopenharmony_ci sleep (5 * 60); /* wait until we are killed (or timeout) */ 823141cc406Sopenharmony_ci shm_channel_writer_close (dev->shm_channel); 824141cc406Sopenharmony_ci return status; 825141cc406Sopenharmony_ci} 826141cc406Sopenharmony_ci 827141cc406Sopenharmony_cistatic SANE_Status 828141cc406Sopenharmony_cigt68xx_device_read_start_fork (GT68xx_Device * dev) 829141cc406Sopenharmony_ci{ 830141cc406Sopenharmony_ci SANE_Status status; 831141cc406Sopenharmony_ci int pid; 832141cc406Sopenharmony_ci if (dev->shm_channel) 833141cc406Sopenharmony_ci { 834141cc406Sopenharmony_ci DBG (3, 835141cc406Sopenharmony_ci "gt68xx_device_read_start_fork: BUG: shm_channel already created\n"); 836141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 837141cc406Sopenharmony_ci } 838141cc406Sopenharmony_ci 839141cc406Sopenharmony_ci status = 840141cc406Sopenharmony_ci shm_channel_new (dev->read_buffer_size, SHM_BUFFERS, &dev->shm_channel); 841141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 842141cc406Sopenharmony_ci { 843141cc406Sopenharmony_ci DBG (3, 844141cc406Sopenharmony_ci "gt68xx_device_read_start_fork: cannot create shared memory channel: " 845141cc406Sopenharmony_ci "%s\n", sane_strstatus (status)); 846141cc406Sopenharmony_ci dev->shm_channel = NULL; 847141cc406Sopenharmony_ci return status; 848141cc406Sopenharmony_ci } 849141cc406Sopenharmony_ci 850141cc406Sopenharmony_ci pid = fork (); 851141cc406Sopenharmony_ci if (pid == -1) 852141cc406Sopenharmony_ci { 853141cc406Sopenharmony_ci DBG (3, "gt68xx_device_read_start_fork: cannot fork: %s\n", 854141cc406Sopenharmony_ci strerror (errno)); 855141cc406Sopenharmony_ci shm_channel_free (dev->shm_channel); 856141cc406Sopenharmony_ci dev->shm_channel = NULL; 857141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 858141cc406Sopenharmony_ci } 859141cc406Sopenharmony_ci 860141cc406Sopenharmony_ci if (pid == 0) 861141cc406Sopenharmony_ci { 862141cc406Sopenharmony_ci /* Child process */ 863141cc406Sopenharmony_ci status = gt68xx_reader_process (dev); 864141cc406Sopenharmony_ci _exit (status); 865141cc406Sopenharmony_ci } 866141cc406Sopenharmony_ci else 867141cc406Sopenharmony_ci { 868141cc406Sopenharmony_ci /* Parent process */ 869141cc406Sopenharmony_ci dev->reader_pid = pid; 870141cc406Sopenharmony_ci shm_channel_reader_init (dev->shm_channel); 871141cc406Sopenharmony_ci shm_channel_reader_start (dev->shm_channel); 872141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 873141cc406Sopenharmony_ci } 874141cc406Sopenharmony_ci} 875141cc406Sopenharmony_ci 876141cc406Sopenharmony_ci#endif /* USE_FORK */ 877141cc406Sopenharmony_ci 878141cc406Sopenharmony_ci 879141cc406Sopenharmony_cistatic SANE_Status 880141cc406Sopenharmony_cigt68xx_device_read_start (GT68xx_Device * dev) 881141cc406Sopenharmony_ci{ 882141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_start"); 883141cc406Sopenharmony_ci#ifdef USE_FORK 884141cc406Sopenharmony_ci /* Don't fork a separate process for every calibration scan. */ 885141cc406Sopenharmony_ci if (dev->final_scan) 886141cc406Sopenharmony_ci return gt68xx_device_read_start_fork (dev); 887141cc406Sopenharmony_ci#endif /* USE_FORK */ 888141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 889141cc406Sopenharmony_ci} 890141cc406Sopenharmony_ci 891141cc406Sopenharmony_ciSANE_Status 892141cc406Sopenharmony_cigt68xx_device_read (GT68xx_Device * dev, SANE_Byte * buffer, size_t * size) 893141cc406Sopenharmony_ci{ 894141cc406Sopenharmony_ci SANE_Status status; 895141cc406Sopenharmony_ci size_t byte_count = 0; 896141cc406Sopenharmony_ci size_t left_to_read = *size; 897141cc406Sopenharmony_ci size_t transfer_size, block_size, raw_block_size; 898141cc406Sopenharmony_ci#ifdef USE_FORK 899141cc406Sopenharmony_ci SANE_Int buffer_id; 900141cc406Sopenharmony_ci SANE_Byte *buffer_addr; 901141cc406Sopenharmony_ci SANE_Int buffer_bytes; 902141cc406Sopenharmony_ci#endif /* USE_FORK */ 903141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_read"); 904141cc406Sopenharmony_ci if (!dev->read_active) 905141cc406Sopenharmony_ci { 906141cc406Sopenharmony_ci DBG (3, "gt68xx_device_read: read not active\n"); 907141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 908141cc406Sopenharmony_ci } 909141cc406Sopenharmony_ci 910141cc406Sopenharmony_ci while (left_to_read > 0) 911141cc406Sopenharmony_ci { 912141cc406Sopenharmony_ci if (dev->read_bytes_in_buffer == 0) 913141cc406Sopenharmony_ci { 914141cc406Sopenharmony_ci block_size = dev->read_buffer_size; 915141cc406Sopenharmony_ci if (block_size > dev->read_bytes_left) 916141cc406Sopenharmony_ci block_size = dev->read_bytes_left; 917141cc406Sopenharmony_ci if (block_size == 0) 918141cc406Sopenharmony_ci break; 919141cc406Sopenharmony_ci raw_block_size = (block_size + 63UL) & ~63UL; 920141cc406Sopenharmony_ci DBG (7, "gt68xx_device_read: trying to read %ld bytes\n", 921141cc406Sopenharmony_ci (long) raw_block_size); 922141cc406Sopenharmony_ci#ifdef USE_FORK 923141cc406Sopenharmony_ci if (dev->shm_channel) 924141cc406Sopenharmony_ci { 925141cc406Sopenharmony_ci status = shm_channel_reader_get_buffer (dev->shm_channel, 926141cc406Sopenharmony_ci &buffer_id, 927141cc406Sopenharmony_ci &buffer_addr, 928141cc406Sopenharmony_ci &buffer_bytes); 929141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD && buffer_addr != NULL) 930141cc406Sopenharmony_ci { 931141cc406Sopenharmony_ci DBG (9, "gt68xx_device_read: buffer %d: get\n", buffer_id); 932141cc406Sopenharmony_ci memcpy (dev->read_buffer, buffer_addr, buffer_bytes); 933141cc406Sopenharmony_ci shm_channel_reader_put_buffer (dev->shm_channel, buffer_id); 934141cc406Sopenharmony_ci DBG (9, "gt68xx_device_read: buffer %d: put\n", buffer_id); 935141cc406Sopenharmony_ci } 936141cc406Sopenharmony_ci } 937141cc406Sopenharmony_ci else 938141cc406Sopenharmony_ci#endif /* USE_FORK */ 939141cc406Sopenharmony_ci status = gt68xx_device_read_raw (dev, dev->read_buffer, 940141cc406Sopenharmony_ci &raw_block_size); 941141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 942141cc406Sopenharmony_ci { 943141cc406Sopenharmony_ci DBG (3, "gt68xx_device_read: read failed\n"); 944141cc406Sopenharmony_ci return status; 945141cc406Sopenharmony_ci } 946141cc406Sopenharmony_ci dev->read_pos = 0; 947141cc406Sopenharmony_ci dev->read_bytes_in_buffer = block_size; 948141cc406Sopenharmony_ci dev->read_bytes_left -= block_size; 949141cc406Sopenharmony_ci } 950141cc406Sopenharmony_ci 951141cc406Sopenharmony_ci transfer_size = left_to_read; 952141cc406Sopenharmony_ci if (transfer_size > dev->read_bytes_in_buffer) 953141cc406Sopenharmony_ci transfer_size = dev->read_bytes_in_buffer; 954141cc406Sopenharmony_ci if (transfer_size > 0) 955141cc406Sopenharmony_ci { 956141cc406Sopenharmony_ci memcpy (buffer, dev->read_buffer + dev->read_pos, transfer_size); 957141cc406Sopenharmony_ci dev->read_pos += transfer_size; 958141cc406Sopenharmony_ci dev->read_bytes_in_buffer -= transfer_size; 959141cc406Sopenharmony_ci byte_count += transfer_size; 960141cc406Sopenharmony_ci left_to_read -= transfer_size; 961141cc406Sopenharmony_ci buffer += transfer_size; 962141cc406Sopenharmony_ci } 963141cc406Sopenharmony_ci } 964141cc406Sopenharmony_ci 965141cc406Sopenharmony_ci *size = byte_count; 966141cc406Sopenharmony_ci if (byte_count == 0) 967141cc406Sopenharmony_ci return SANE_STATUS_EOF; 968141cc406Sopenharmony_ci else 969141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 970141cc406Sopenharmony_ci} 971141cc406Sopenharmony_ci 972141cc406Sopenharmony_ciSANE_Status 973141cc406Sopenharmony_cigt68xx_device_read_finish (GT68xx_Device * dev) 974141cc406Sopenharmony_ci{ 975141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 976141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_read_finish"); 977141cc406Sopenharmony_ci if (!dev->read_active) 978141cc406Sopenharmony_ci { 979141cc406Sopenharmony_ci DBG (3, "gt68xx_device_read_finish: read not active\n"); 980141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 981141cc406Sopenharmony_ci } 982141cc406Sopenharmony_ci 983141cc406Sopenharmony_ci DBG (7, "gt68xx_device_read_finish: read_bytes_left = %ld\n", 984141cc406Sopenharmony_ci (long) dev->read_bytes_left); 985141cc406Sopenharmony_ci#ifdef USE_FORK 986141cc406Sopenharmony_ci if (dev->reader_pid != 0) 987141cc406Sopenharmony_ci { 988141cc406Sopenharmony_ci int pid_status; 989141cc406Sopenharmony_ci /* usleep (100000); */ 990141cc406Sopenharmony_ci DBG (7, "gt68xx_device_read_finish: trying to kill reader process\n"); 991141cc406Sopenharmony_ci kill (dev->reader_pid, SIGKILL); 992141cc406Sopenharmony_ci waitpid (dev->reader_pid, &pid_status, 0); 993141cc406Sopenharmony_ci if (WIFEXITED (pid_status)) 994141cc406Sopenharmony_ci status = WEXITSTATUS (pid_status); 995141cc406Sopenharmony_ci DBG (7, "gt68xx_device_read_finish: reader process killed\n"); 996141cc406Sopenharmony_ci dev->reader_pid = 0; 997141cc406Sopenharmony_ci } 998141cc406Sopenharmony_ci if (dev->shm_channel) 999141cc406Sopenharmony_ci { 1000141cc406Sopenharmony_ci shm_channel_free (dev->shm_channel); 1001141cc406Sopenharmony_ci dev->shm_channel = NULL; 1002141cc406Sopenharmony_ci } 1003141cc406Sopenharmony_ci 1004141cc406Sopenharmony_ci#endif /* USE_FORK */ 1005141cc406Sopenharmony_ci 1006141cc406Sopenharmony_ci free (dev->read_buffer); 1007141cc406Sopenharmony_ci dev->read_buffer = NULL; 1008141cc406Sopenharmony_ci dev->read_active = SANE_FALSE; 1009141cc406Sopenharmony_ci DBG (7, "gt68xx_device_read_finish: exit (%s)\n", sane_strstatus (status)); 1010141cc406Sopenharmony_ci return status; 1011141cc406Sopenharmony_ci} 1012141cc406Sopenharmony_ci 1013141cc406Sopenharmony_cistatic SANE_Status 1014141cc406Sopenharmony_cigt68xx_device_check_result (GT68xx_Packet res, SANE_Byte command) 1015141cc406Sopenharmony_ci{ 1016141cc406Sopenharmony_ci if (res[0] != 0) 1017141cc406Sopenharmony_ci { 1018141cc406Sopenharmony_ci DBG (1, "gt68xx_device_check_result: result was %2X %2X " 1019141cc406Sopenharmony_ci "(expected: %2X %2X)\n", res[0], res[1], 0, command); 1020141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 1021141cc406Sopenharmony_ci } 1022141cc406Sopenharmony_ci /* The Gt681xfw.usb firmware doesn't return the command byte 1023141cc406Sopenharmony_ci in the second byte, so we can't rely on that test */ 1024141cc406Sopenharmony_ci if (res[1] != command) 1025141cc406Sopenharmony_ci DBG (5, "gt68xx_device_check_result: warning: result was %2X %2X " 1026141cc406Sopenharmony_ci "(expected: %2X %2X)\n", res[0], res[1], 0, command); 1027141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1028141cc406Sopenharmony_ci} 1029141cc406Sopenharmony_ci 1030141cc406Sopenharmony_ciSANE_Status 1031141cc406Sopenharmony_cigt68xx_device_get_id (GT68xx_Device * dev) 1032141cc406Sopenharmony_ci{ 1033141cc406Sopenharmony_ci CHECK_DEV_ACTIVE (dev, "gt68xx_device_get_id"); 1034141cc406Sopenharmony_ci if (dev->model->command_set->get_id) 1035141cc406Sopenharmony_ci return (*dev->model->command_set->get_id) (dev); 1036141cc406Sopenharmony_ci else 1037141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 1038141cc406Sopenharmony_ci} 1039141cc406Sopenharmony_ci 1040141cc406Sopenharmony_cistatic void 1041141cc406Sopenharmony_cigt68xx_device_fix_descriptor (GT68xx_Device * dev) 1042141cc406Sopenharmony_ci{ 1043141cc406Sopenharmony_ci SANE_Byte data[8]; 1044141cc406Sopenharmony_ci sanei_usb_control_msg (dev->fd, 0x80, 0x06, 0x01 << 8, 0, 8, data); 1045141cc406Sopenharmony_ci} 1046141cc406Sopenharmony_ci 1047141cc406Sopenharmony_ci 1048141cc406Sopenharmony_ci/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ 1049