1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci This file is part of the SANE package. 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 6141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 7141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 8141cc406Sopenharmony_ci License, or (at your option) any later version. 9141cc406Sopenharmony_ci 10141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 11141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 12141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13141cc406Sopenharmony_ci General Public License for more details. 14141cc406Sopenharmony_ci 15141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 16141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 19141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 22141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 23141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 24141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 25141cc406Sopenharmony_ci account of linking the SANE library code into it. 26141cc406Sopenharmony_ci 27141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 28141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 29141cc406Sopenharmony_ci License. 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 32141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 33141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 36141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 37141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci -------------------------------------------------------------------------- 40141cc406Sopenharmony_ci 41141cc406Sopenharmony_ci This file implements a SANE backend for HP ScanJet 3500 series scanners. 42141cc406Sopenharmony_ci Currently supported: 43141cc406Sopenharmony_ci - HP ScanJet 3500C 44141cc406Sopenharmony_ci - HP ScanJet 3530C 45141cc406Sopenharmony_ci - HP ScanJet 3570C 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci SANE FLOW DIAGRAM 48141cc406Sopenharmony_ci 49141cc406Sopenharmony_ci - sane_init() : initialize backend, attach scanners 50141cc406Sopenharmony_ci . - sane_get_devices() : query list of scanner devices 51141cc406Sopenharmony_ci . - sane_open() : open a particular scanner device 52141cc406Sopenharmony_ci . . - sane_set_io_mode : set blocking mode 53141cc406Sopenharmony_ci . . - sane_get_select_fd : get scanner fd 54141cc406Sopenharmony_ci . . - sane_get_option_descriptor() : get option information 55141cc406Sopenharmony_ci . . - sane_control_option() : change option values 56141cc406Sopenharmony_ci . . 57141cc406Sopenharmony_ci . . - sane_start() : start image acquisition 58141cc406Sopenharmony_ci . . - sane_get_parameters() : returns actual scan parameters 59141cc406Sopenharmony_ci . . - sane_read() : read image data (from pipe) 60141cc406Sopenharmony_ci . . 61141cc406Sopenharmony_ci . . - sane_cancel() : cancel operation 62141cc406Sopenharmony_ci . - sane_close() : close opened scanner device 63141cc406Sopenharmony_ci - sane_exit() : terminate use of backend 64141cc406Sopenharmony_ci 65141cc406Sopenharmony_ci 66141cc406Sopenharmony_ci There are some device specific routines in this file that are in "#if 0" 67141cc406Sopenharmony_ci sections - these are left in place for documentation purposes in case 68141cc406Sopenharmony_ci somebody wants to implement features that use those routines. 69141cc406Sopenharmony_ci 70141cc406Sopenharmony_ci*/ 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */ 73141cc406Sopenharmony_ci 74141cc406Sopenharmony_ci#include "../include/sane/config.h" 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci#include <errno.h> 77141cc406Sopenharmony_ci#include <fcntl.h> 78141cc406Sopenharmony_ci#include <limits.h> 79141cc406Sopenharmony_ci#include <signal.h> 80141cc406Sopenharmony_ci#include <stdio.h> 81141cc406Sopenharmony_ci#include <stdlib.h> 82141cc406Sopenharmony_ci#include <string.h> 83141cc406Sopenharmony_ci#include <ctype.h> 84141cc406Sopenharmony_ci#include <time.h> 85141cc406Sopenharmony_ci#include <math.h> 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_ci#include <sys/types.h> 88141cc406Sopenharmony_ci#include <unistd.h> 89141cc406Sopenharmony_ci#ifdef HAVE_LIBC_H 90141cc406Sopenharmony_ci# include <libc.h> /* NeXTStep/OpenStep */ 91141cc406Sopenharmony_ci#endif 92141cc406Sopenharmony_ci 93141cc406Sopenharmony_ci#include "../include/sane/sane.h" 94141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 95141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 96141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 97141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h" 98141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 99141cc406Sopenharmony_ci 100141cc406Sopenharmony_ci#define RTCMD_GETREG 0x80 101141cc406Sopenharmony_ci#define RTCMD_READSRAM 0x81 102141cc406Sopenharmony_ci 103141cc406Sopenharmony_ci#define RTCMD_SETREG 0x88 104141cc406Sopenharmony_ci#define RTCMD_WRITESRAM 0x89 105141cc406Sopenharmony_ci 106141cc406Sopenharmony_ci#define RTCMD_NVRAMCONTROL 0x8a 107141cc406Sopenharmony_ci 108141cc406Sopenharmony_ci#define RTCMD_BYTESAVAIL 0x90 109141cc406Sopenharmony_ci#define RTCMD_READBYTES 0x91 110141cc406Sopenharmony_ci 111141cc406Sopenharmony_ci#define RT_CHANNEL_ALL 0 112141cc406Sopenharmony_ci#define RT_CHANNEL_RED 1 113141cc406Sopenharmony_ci#define RT_CHANNEL_GREEN 2 114141cc406Sopenharmony_ci#define RT_CHANNEL_BLUE 3 115141cc406Sopenharmony_ci 116141cc406Sopenharmony_citypedef int (*rts8801_callback) (void *param, unsigned bytes, void *data); 117141cc406Sopenharmony_ci 118141cc406Sopenharmony_ci#define DEBUG 1 119141cc406Sopenharmony_ci#define SCANNER_UNIT_TO_FIXED_MM(number) SANE_FIX(number * MM_PER_INCH / 1200) 120141cc406Sopenharmony_ci#define FIXED_MM_TO_SCANNER_UNIT(number) SANE_UNFIX(number) * 1200 / MM_PER_INCH 121141cc406Sopenharmony_ci 122141cc406Sopenharmony_ci#define MSG_ERR 1 123141cc406Sopenharmony_ci#define MSG_USER 5 124141cc406Sopenharmony_ci#define MSG_INFO 6 125141cc406Sopenharmony_ci#define FLOW_CONTROL 10 126141cc406Sopenharmony_ci#define MSG_IO 15 127141cc406Sopenharmony_ci#define MSG_IO_READ 17 128141cc406Sopenharmony_ci#define IO_CMD 20 129141cc406Sopenharmony_ci#define IO_CMD_RES 20 130141cc406Sopenharmony_ci#define MSG_GET 25 131141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */ 132141cc406Sopenharmony_ci 133141cc406Sopenharmony_cienum hp3500_option 134141cc406Sopenharmony_ci{ 135141cc406Sopenharmony_ci OPT_NUM_OPTS = 0, 136141cc406Sopenharmony_ci 137141cc406Sopenharmony_ci OPT_RESOLUTION, 138141cc406Sopenharmony_ci OPT_GEOMETRY_GROUP, 139141cc406Sopenharmony_ci OPT_TL_X, 140141cc406Sopenharmony_ci OPT_TL_Y, 141141cc406Sopenharmony_ci OPT_BR_X, 142141cc406Sopenharmony_ci OPT_BR_Y, 143141cc406Sopenharmony_ci OPT_MODE_GROUP, 144141cc406Sopenharmony_ci OPT_MODE, 145141cc406Sopenharmony_ci OPT_BRIGHTNESS, 146141cc406Sopenharmony_ci OPT_CONTRAST, 147141cc406Sopenharmony_ci OPT_GAMMA, 148141cc406Sopenharmony_ci 149141cc406Sopenharmony_ci NUM_OPTIONS 150141cc406Sopenharmony_ci}; 151141cc406Sopenharmony_ci 152141cc406Sopenharmony_citypedef struct 153141cc406Sopenharmony_ci{ 154141cc406Sopenharmony_ci int left; 155141cc406Sopenharmony_ci int top; 156141cc406Sopenharmony_ci int right; 157141cc406Sopenharmony_ci int bottom; 158141cc406Sopenharmony_ci} hp3500_rect; 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_cistruct hp3500_data 161141cc406Sopenharmony_ci{ 162141cc406Sopenharmony_ci struct hp3500_data *next; 163141cc406Sopenharmony_ci char *devicename; 164141cc406Sopenharmony_ci 165141cc406Sopenharmony_ci int sfd; 166141cc406Sopenharmony_ci int pipe_r; 167141cc406Sopenharmony_ci int pipe_w; 168141cc406Sopenharmony_ci SANE_Pid reader_pid; 169141cc406Sopenharmony_ci 170141cc406Sopenharmony_ci int resolution; 171141cc406Sopenharmony_ci int mode; 172141cc406Sopenharmony_ci 173141cc406Sopenharmony_ci time_t last_scan; 174141cc406Sopenharmony_ci 175141cc406Sopenharmony_ci hp3500_rect request_mm; 176141cc406Sopenharmony_ci hp3500_rect actual_mm; 177141cc406Sopenharmony_ci hp3500_rect fullres_pixels; 178141cc406Sopenharmony_ci hp3500_rect actres_pixels; 179141cc406Sopenharmony_ci 180141cc406Sopenharmony_ci int rounded_left; 181141cc406Sopenharmony_ci int rounded_top; 182141cc406Sopenharmony_ci int rounded_right; 183141cc406Sopenharmony_ci int rounded_bottom; 184141cc406Sopenharmony_ci 185141cc406Sopenharmony_ci int bytes_per_scan_line; 186141cc406Sopenharmony_ci int scan_width_pixels; 187141cc406Sopenharmony_ci int scan_height_pixels; 188141cc406Sopenharmony_ci 189141cc406Sopenharmony_ci int brightness; 190141cc406Sopenharmony_ci int contrast; 191141cc406Sopenharmony_ci 192141cc406Sopenharmony_ci double gamma; 193141cc406Sopenharmony_ci 194141cc406Sopenharmony_ci SANE_Option_Descriptor opt[NUM_OPTIONS]; 195141cc406Sopenharmony_ci SANE_Device sane; 196141cc406Sopenharmony_ci}; 197141cc406Sopenharmony_ci 198141cc406Sopenharmony_cistruct hp3500_write_info 199141cc406Sopenharmony_ci{ 200141cc406Sopenharmony_ci struct hp3500_data *scanner; 201141cc406Sopenharmony_ci int bytesleft; 202141cc406Sopenharmony_ci}; 203141cc406Sopenharmony_ci 204141cc406Sopenharmony_citypedef struct detailed_calibration_data 205141cc406Sopenharmony_ci{ 206141cc406Sopenharmony_ci unsigned char const *channeldata[3]; 207141cc406Sopenharmony_ci unsigned resolution_divisor; 208141cc406Sopenharmony_ci} detailed_calibration_data; 209141cc406Sopenharmony_ci 210141cc406Sopenharmony_cistatic struct hp3500_data *first_dev = 0; 211141cc406Sopenharmony_cistatic struct hp3500_data **new_dev = &first_dev; 212141cc406Sopenharmony_cistatic int num_devices = 0; 213141cc406Sopenharmony_cistatic SANE_Int res_list[] = 214141cc406Sopenharmony_ci { 9, 50, 75, 100, 150, 200, 300, 400, 600, 1200 }; 215141cc406Sopenharmony_cistatic const SANE_Range range_x = 216141cc406Sopenharmony_ci { 0, SANE_FIX (215.9), SANE_FIX (MM_PER_INCH / 1200) }; 217141cc406Sopenharmony_cistatic const SANE_Range range_y = 218141cc406Sopenharmony_ci { 0, SANE_FIX (298.7), SANE_FIX (MM_PER_INCH / 1200) }; 219141cc406Sopenharmony_cistatic const SANE_Range range_brightness = 220141cc406Sopenharmony_ci { 0, 255, 0 }; 221141cc406Sopenharmony_cistatic const SANE_Range range_contrast = 222141cc406Sopenharmony_ci { 0, 255, 0 }; 223141cc406Sopenharmony_cistatic const SANE_Range range_gamma = 224141cc406Sopenharmony_ci { SANE_FIX (0.2), SANE_FIX(4.0), SANE_FIX(0.01) }; 225141cc406Sopenharmony_ci 226141cc406Sopenharmony_ci 227141cc406Sopenharmony_ci#define HP3500_COLOR_SCAN 0 228141cc406Sopenharmony_ci#define HP3500_GRAY_SCAN 1 229141cc406Sopenharmony_ci#define HP3500_LINEART_SCAN 2 230141cc406Sopenharmony_ci#define HP3500_TOTAL_SCANS 3 231141cc406Sopenharmony_ci 232141cc406Sopenharmony_cistatic char const *scan_mode_list[HP3500_TOTAL_SCANS + 1] = { 0 }; 233141cc406Sopenharmony_ci 234141cc406Sopenharmony_cistatic SANE_Status attachScanner (const char *name); 235141cc406Sopenharmony_cistatic SANE_Status init_options (struct hp3500_data *scanner); 236141cc406Sopenharmony_cistatic int reader_process (void *); 237141cc406Sopenharmony_cistatic void calculateDerivedValues (struct hp3500_data *scanner); 238141cc406Sopenharmony_cistatic void do_reset (struct hp3500_data *scanner); 239141cc406Sopenharmony_cistatic void do_cancel (struct hp3500_data *scanner); 240141cc406Sopenharmony_cistatic size_t max_string_size(char const **); 241141cc406Sopenharmony_ci 242141cc406Sopenharmony_ci/* 243141cc406Sopenharmony_ci * used by sane_get_devices 244141cc406Sopenharmony_ci */ 245141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0; 246141cc406Sopenharmony_ci 247141cc406Sopenharmony_ci/* 248141cc406Sopenharmony_ci * SANE Interface 249141cc406Sopenharmony_ci */ 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_ci 252141cc406Sopenharmony_ci/** 253141cc406Sopenharmony_ci * Called by SANE initially. 254141cc406Sopenharmony_ci * 255141cc406Sopenharmony_ci * From the SANE spec: 256141cc406Sopenharmony_ci * This function must be called before any other SANE function can be 257141cc406Sopenharmony_ci * called. The behavior of a SANE backend is undefined if this 258141cc406Sopenharmony_ci * function is not called first. The version code of the backend is 259141cc406Sopenharmony_ci * returned in the value pointed to by version_code. If that pointer 260141cc406Sopenharmony_ci * is NULL, no version code is returned. Argument authorize is either 261141cc406Sopenharmony_ci * a pointer to a function that is invoked when the backend requires 262141cc406Sopenharmony_ci * authentication for a specific resource or NULL if the frontend does 263141cc406Sopenharmony_ci * not support authentication. 264141cc406Sopenharmony_ci */ 265141cc406Sopenharmony_ciSANE_Status 266141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 267141cc406Sopenharmony_ci{ 268141cc406Sopenharmony_ci (void) authorize; /* get rid of compiler warning */ 269141cc406Sopenharmony_ci 270141cc406Sopenharmony_ci DBG_INIT (); 271141cc406Sopenharmony_ci DBG (10, "sane_init\n"); 272141cc406Sopenharmony_ci 273141cc406Sopenharmony_ci sanei_usb_init (); 274141cc406Sopenharmony_ci sanei_thread_init (); 275141cc406Sopenharmony_ci 276141cc406Sopenharmony_ci if (version_code) 277141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0); 278141cc406Sopenharmony_ci 279141cc406Sopenharmony_ci sanei_usb_find_devices (0x03f0, 0x2205, attachScanner); 280141cc406Sopenharmony_ci sanei_usb_find_devices (0x03f0, 0x2005, attachScanner); 281141cc406Sopenharmony_ci 282141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 283141cc406Sopenharmony_ci} 284141cc406Sopenharmony_ci 285141cc406Sopenharmony_ci 286141cc406Sopenharmony_ci/** 287141cc406Sopenharmony_ci * Called by SANE to find out about supported devices. 288141cc406Sopenharmony_ci * 289141cc406Sopenharmony_ci * From the SANE spec: 290141cc406Sopenharmony_ci * This function can be used to query the list of devices that are 291141cc406Sopenharmony_ci * available. If the function executes successfully, it stores a 292141cc406Sopenharmony_ci * pointer to a NULL terminated array of pointers to SANE_Device 293141cc406Sopenharmony_ci * structures in *device_list. The returned list is guaranteed to 294141cc406Sopenharmony_ci * remain unchanged and valid until (a) another call to this function 295141cc406Sopenharmony_ci * is performed or (b) a call to sane_exit() is performed. This 296141cc406Sopenharmony_ci * function can be called repeatedly to detect when new devices become 297141cc406Sopenharmony_ci * available. If argument local_only is true, only local devices are 298141cc406Sopenharmony_ci * returned (devices directly attached to the machine that SANE is 299141cc406Sopenharmony_ci * running on). If it is false, the device list includes all remote 300141cc406Sopenharmony_ci * devices that are accessible to the SANE library. 301141cc406Sopenharmony_ci * 302141cc406Sopenharmony_ci * SANE does not require that this function is called before a 303141cc406Sopenharmony_ci * sane_open() call is performed. A device name may be specified 304141cc406Sopenharmony_ci * explicitly by a user which would make it unnecessary and 305141cc406Sopenharmony_ci * undesirable to call this function first. 306141cc406Sopenharmony_ci */ 307141cc406Sopenharmony_ciSANE_Status 308141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 309141cc406Sopenharmony_ci{ 310141cc406Sopenharmony_ci int i; 311141cc406Sopenharmony_ci struct hp3500_data *dev; 312141cc406Sopenharmony_ci 313141cc406Sopenharmony_ci DBG (10, "sane_get_devices %d\n", local_only); 314141cc406Sopenharmony_ci 315141cc406Sopenharmony_ci if (devlist) 316141cc406Sopenharmony_ci free (devlist); 317141cc406Sopenharmony_ci devlist = calloc (num_devices + 1, sizeof (SANE_Device *)); 318141cc406Sopenharmony_ci if (!devlist) 319141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 320141cc406Sopenharmony_ci 321141cc406Sopenharmony_ci for (dev = first_dev, i = 0; i < num_devices; dev = dev->next) 322141cc406Sopenharmony_ci devlist[i++] = &dev->sane; 323141cc406Sopenharmony_ci devlist[i++] = 0; 324141cc406Sopenharmony_ci 325141cc406Sopenharmony_ci *device_list = devlist; 326141cc406Sopenharmony_ci 327141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 328141cc406Sopenharmony_ci} 329141cc406Sopenharmony_ci 330141cc406Sopenharmony_ci 331141cc406Sopenharmony_ci/** 332141cc406Sopenharmony_ci * Called to establish connection with the scanner. This function will 333141cc406Sopenharmony_ci * also establish meaningful defaults and initialize the options. 334141cc406Sopenharmony_ci * 335141cc406Sopenharmony_ci * From the SANE spec: 336141cc406Sopenharmony_ci * This function is used to establish a connection to a particular 337141cc406Sopenharmony_ci * device. The name of the device to be opened is passed in argument 338141cc406Sopenharmony_ci * name. If the call completes successfully, a handle for the device 339141cc406Sopenharmony_ci * is returned in *h. As a special case, specifying a zero-length 340141cc406Sopenharmony_ci * string as the device requests opening the first available device 341141cc406Sopenharmony_ci * (if there is such a device). 342141cc406Sopenharmony_ci */ 343141cc406Sopenharmony_ciSANE_Status 344141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * handle) 345141cc406Sopenharmony_ci{ 346141cc406Sopenharmony_ci struct hp3500_data *dev = NULL; 347141cc406Sopenharmony_ci struct hp3500_data *scanner = NULL; 348141cc406Sopenharmony_ci 349141cc406Sopenharmony_ci if (name[0] == 0) 350141cc406Sopenharmony_ci { 351141cc406Sopenharmony_ci DBG (10, "sane_open: no device requested, using default\n"); 352141cc406Sopenharmony_ci if (first_dev) 353141cc406Sopenharmony_ci { 354141cc406Sopenharmony_ci scanner = (struct hp3500_data *) first_dev; 355141cc406Sopenharmony_ci DBG (10, "sane_open: device %s found\n", first_dev->sane.name); 356141cc406Sopenharmony_ci } 357141cc406Sopenharmony_ci } 358141cc406Sopenharmony_ci else 359141cc406Sopenharmony_ci { 360141cc406Sopenharmony_ci DBG (10, "sane_open: device %s requested\n", name); 361141cc406Sopenharmony_ci 362141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 363141cc406Sopenharmony_ci { 364141cc406Sopenharmony_ci if (strcmp (dev->sane.name, name) == 0) 365141cc406Sopenharmony_ci { 366141cc406Sopenharmony_ci DBG (10, "sane_open: device %s found\n", name); 367141cc406Sopenharmony_ci scanner = (struct hp3500_data *) dev; 368141cc406Sopenharmony_ci } 369141cc406Sopenharmony_ci } 370141cc406Sopenharmony_ci } 371141cc406Sopenharmony_ci 372141cc406Sopenharmony_ci if (!scanner) 373141cc406Sopenharmony_ci { 374141cc406Sopenharmony_ci DBG (10, "sane_open: no device found\n"); 375141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 376141cc406Sopenharmony_ci } 377141cc406Sopenharmony_ci 378141cc406Sopenharmony_ci *handle = scanner; 379141cc406Sopenharmony_ci 380141cc406Sopenharmony_ci init_options (scanner); 381141cc406Sopenharmony_ci 382141cc406Sopenharmony_ci scanner->resolution = 200; 383141cc406Sopenharmony_ci scanner->request_mm.left = 0; 384141cc406Sopenharmony_ci scanner->request_mm.top = 0; 385141cc406Sopenharmony_ci scanner->request_mm.right = SCANNER_UNIT_TO_FIXED_MM (10200); 386141cc406Sopenharmony_ci scanner->request_mm.bottom = SCANNER_UNIT_TO_FIXED_MM (14100); 387141cc406Sopenharmony_ci scanner->mode = 0; 388141cc406Sopenharmony_ci scanner->brightness = 128; 389141cc406Sopenharmony_ci scanner->contrast = 64; 390141cc406Sopenharmony_ci scanner->gamma = 2.2; 391141cc406Sopenharmony_ci calculateDerivedValues (scanner); 392141cc406Sopenharmony_ci 393141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 394141cc406Sopenharmony_ci 395141cc406Sopenharmony_ci} 396141cc406Sopenharmony_ci 397141cc406Sopenharmony_ci 398141cc406Sopenharmony_ci/** 399141cc406Sopenharmony_ci * An advanced method we don't support but have to define. 400141cc406Sopenharmony_ci */ 401141cc406Sopenharmony_ciSANE_Status 402141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking) 403141cc406Sopenharmony_ci{ 404141cc406Sopenharmony_ci DBG (10, "sane_set_io_mode\n"); 405141cc406Sopenharmony_ci DBG (99, "%d %p\n", non_blocking, h); 406141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 407141cc406Sopenharmony_ci} 408141cc406Sopenharmony_ci 409141cc406Sopenharmony_ci 410141cc406Sopenharmony_ci/** 411141cc406Sopenharmony_ci * An advanced method we don't support but have to define. 412141cc406Sopenharmony_ci */ 413141cc406Sopenharmony_ciSANE_Status 414141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int * fdp) 415141cc406Sopenharmony_ci{ 416141cc406Sopenharmony_ci struct hp3500_data *scanner = (struct hp3500_data *) h; 417141cc406Sopenharmony_ci DBG (10, "sane_get_select_fd\n"); 418141cc406Sopenharmony_ci *fdp = scanner->pipe_r; 419141cc406Sopenharmony_ci DBG (99, "%p %d\n", h, *fdp); 420141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 421141cc406Sopenharmony_ci} 422141cc406Sopenharmony_ci 423141cc406Sopenharmony_ci 424141cc406Sopenharmony_ci/** 425141cc406Sopenharmony_ci * Returns the options we know. 426141cc406Sopenharmony_ci * 427141cc406Sopenharmony_ci * From the SANE spec: 428141cc406Sopenharmony_ci * This function is used to access option descriptors. The function 429141cc406Sopenharmony_ci * returns the option descriptor for option number n of the device 430141cc406Sopenharmony_ci * represented by handle h. Option number 0 is guaranteed to be a 431141cc406Sopenharmony_ci * valid option. Its value is an integer that specifies the number of 432141cc406Sopenharmony_ci * options that are available for device handle h (the count includes 433141cc406Sopenharmony_ci * option 0). If n is not a valid option index, the function returns 434141cc406Sopenharmony_ci * NULL. The returned option descriptor is guaranteed to remain valid 435141cc406Sopenharmony_ci * (and at the returned address) until the device is closed. 436141cc406Sopenharmony_ci */ 437141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 438141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 439141cc406Sopenharmony_ci{ 440141cc406Sopenharmony_ci struct hp3500_data *scanner = handle; 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_ci DBG (MSG_GET, 443141cc406Sopenharmony_ci "sane_get_option_descriptor: \"%s\"\n", scanner->opt[option].name); 444141cc406Sopenharmony_ci 445141cc406Sopenharmony_ci if ((unsigned) option >= NUM_OPTIONS) 446141cc406Sopenharmony_ci return NULL; 447141cc406Sopenharmony_ci return &scanner->opt[option]; 448141cc406Sopenharmony_ci} 449141cc406Sopenharmony_ci 450141cc406Sopenharmony_ci 451141cc406Sopenharmony_ci/** 452141cc406Sopenharmony_ci * Gets or sets an option value. 453141cc406Sopenharmony_ci * 454141cc406Sopenharmony_ci * From the SANE spec: 455141cc406Sopenharmony_ci * This function is used to set or inquire the current value of option 456141cc406Sopenharmony_ci * number n of the device represented by handle h. The manner in which 457141cc406Sopenharmony_ci * the option is controlled is specified by parameter action. The 458141cc406Sopenharmony_ci * possible values of this parameter are described in more detail 459141cc406Sopenharmony_ci * below. The value of the option is passed through argument val. It 460141cc406Sopenharmony_ci * is a pointer to the memory that holds the option value. The memory 461141cc406Sopenharmony_ci * area pointed to by v must be big enough to hold the entire option 462141cc406Sopenharmony_ci * value (determined by member size in the corresponding option 463141cc406Sopenharmony_ci * descriptor). 464141cc406Sopenharmony_ci * 465141cc406Sopenharmony_ci * The only exception to this rule is that when setting the value of a 466141cc406Sopenharmony_ci * string option, the string pointed to by argument v may be shorter 467141cc406Sopenharmony_ci * since the backend will stop reading the option value upon 468141cc406Sopenharmony_ci * encountering the first NUL terminator in the string. If argument i 469141cc406Sopenharmony_ci * is not NULL, the value of *i will be set to provide details on how 470141cc406Sopenharmony_ci * well the request has been met. 471141cc406Sopenharmony_ci */ 472141cc406Sopenharmony_ciSANE_Status 473141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 474141cc406Sopenharmony_ci SANE_Action action, void *val, SANE_Int * info) 475141cc406Sopenharmony_ci{ 476141cc406Sopenharmony_ci struct hp3500_data *scanner = (struct hp3500_data *) handle; 477141cc406Sopenharmony_ci SANE_Status status; 478141cc406Sopenharmony_ci SANE_Word cap; 479141cc406Sopenharmony_ci SANE_Int dummy; 480141cc406Sopenharmony_ci int i; 481141cc406Sopenharmony_ci 482141cc406Sopenharmony_ci /* Make sure that all those statements involving *info cannot break (better 483141cc406Sopenharmony_ci * than having to do "if (info) ..." everywhere!) 484141cc406Sopenharmony_ci */ 485141cc406Sopenharmony_ci if (info == 0) 486141cc406Sopenharmony_ci info = &dummy; 487141cc406Sopenharmony_ci 488141cc406Sopenharmony_ci *info = 0; 489141cc406Sopenharmony_ci 490141cc406Sopenharmony_ci if (option >= NUM_OPTIONS) 491141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 492141cc406Sopenharmony_ci 493141cc406Sopenharmony_ci cap = scanner->opt[option].cap; 494141cc406Sopenharmony_ci 495141cc406Sopenharmony_ci /* 496141cc406Sopenharmony_ci * SANE_ACTION_GET_VALUE: We have to find out the current setting and 497141cc406Sopenharmony_ci * return it in a human-readable form (often, text). 498141cc406Sopenharmony_ci */ 499141cc406Sopenharmony_ci if (action == SANE_ACTION_GET_VALUE) 500141cc406Sopenharmony_ci { 501141cc406Sopenharmony_ci DBG (MSG_GET, "sane_control_option: get value \"%s\"\n", 502141cc406Sopenharmony_ci scanner->opt[option].name); 503141cc406Sopenharmony_ci DBG (11, "\tcap = %d\n", cap); 504141cc406Sopenharmony_ci 505141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (cap)) 506141cc406Sopenharmony_ci { 507141cc406Sopenharmony_ci DBG (10, "\tinactive\n"); 508141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 509141cc406Sopenharmony_ci } 510141cc406Sopenharmony_ci 511141cc406Sopenharmony_ci switch (option) 512141cc406Sopenharmony_ci { 513141cc406Sopenharmony_ci case OPT_NUM_OPTS: 514141cc406Sopenharmony_ci *(SANE_Word *) val = NUM_OPTIONS; 515141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 516141cc406Sopenharmony_ci 517141cc406Sopenharmony_ci case OPT_RESOLUTION: 518141cc406Sopenharmony_ci *(SANE_Word *) val = scanner->resolution; 519141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 520141cc406Sopenharmony_ci 521141cc406Sopenharmony_ci case OPT_TL_X: 522141cc406Sopenharmony_ci *(SANE_Word *) val = scanner->request_mm.left; 523141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 524141cc406Sopenharmony_ci 525141cc406Sopenharmony_ci case OPT_TL_Y: 526141cc406Sopenharmony_ci *(SANE_Word *) val = scanner->request_mm.top; 527141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 528141cc406Sopenharmony_ci 529141cc406Sopenharmony_ci case OPT_BR_X: 530141cc406Sopenharmony_ci *(SANE_Word *) val = scanner->request_mm.right; 531141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 532141cc406Sopenharmony_ci 533141cc406Sopenharmony_ci case OPT_BR_Y: 534141cc406Sopenharmony_ci *(SANE_Word *) val = scanner->request_mm.bottom; 535141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 536141cc406Sopenharmony_ci 537141cc406Sopenharmony_ci case OPT_MODE: 538141cc406Sopenharmony_ci strcpy ((SANE_Char *) val, scan_mode_list[scanner->mode]); 539141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 540141cc406Sopenharmony_ci 541141cc406Sopenharmony_ci case OPT_CONTRAST: 542141cc406Sopenharmony_ci *(SANE_Word *) val = scanner->contrast; 543141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 544141cc406Sopenharmony_ci 545141cc406Sopenharmony_ci case OPT_GAMMA: 546141cc406Sopenharmony_ci *(SANE_Word *) val = SANE_FIX(scanner->gamma); 547141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 548141cc406Sopenharmony_ci 549141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 550141cc406Sopenharmony_ci *(SANE_Word *) val = scanner->brightness; 551141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 552141cc406Sopenharmony_ci } 553141cc406Sopenharmony_ci } 554141cc406Sopenharmony_ci else if (action == SANE_ACTION_SET_VALUE) 555141cc406Sopenharmony_ci { 556141cc406Sopenharmony_ci DBG (10, "sane_control_option: set value \"%s\"\n", 557141cc406Sopenharmony_ci scanner->opt[option].name); 558141cc406Sopenharmony_ci 559141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (cap)) 560141cc406Sopenharmony_ci { 561141cc406Sopenharmony_ci DBG (10, "\tinactive\n"); 562141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 563141cc406Sopenharmony_ci } 564141cc406Sopenharmony_ci 565141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (cap)) 566141cc406Sopenharmony_ci { 567141cc406Sopenharmony_ci DBG (10, "\tnot settable\n"); 568141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 569141cc406Sopenharmony_ci } 570141cc406Sopenharmony_ci 571141cc406Sopenharmony_ci status = sanei_constrain_value (scanner->opt + option, val, info); 572141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 573141cc406Sopenharmony_ci { 574141cc406Sopenharmony_ci DBG (10, "\tbad value\n"); 575141cc406Sopenharmony_ci return status; 576141cc406Sopenharmony_ci } 577141cc406Sopenharmony_ci 578141cc406Sopenharmony_ci /* 579141cc406Sopenharmony_ci * Note - for those options which can assume one of a list of 580141cc406Sopenharmony_ci * valid values, we can safely assume that they will have 581141cc406Sopenharmony_ci * exactly one of those values because that's what 582141cc406Sopenharmony_ci * sanei_constrain_value does. Hence no "else: invalid" branches 583141cc406Sopenharmony_ci * below. 584141cc406Sopenharmony_ci */ 585141cc406Sopenharmony_ci switch (option) 586141cc406Sopenharmony_ci { 587141cc406Sopenharmony_ci case OPT_RESOLUTION: 588141cc406Sopenharmony_ci if (scanner->resolution == *(SANE_Word *) val) 589141cc406Sopenharmony_ci { 590141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 591141cc406Sopenharmony_ci } 592141cc406Sopenharmony_ci scanner->resolution = (*(SANE_Word *) val); 593141cc406Sopenharmony_ci calculateDerivedValues (scanner); 594141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 595141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 596141cc406Sopenharmony_ci 597141cc406Sopenharmony_ci case OPT_TL_X: 598141cc406Sopenharmony_ci if (scanner->request_mm.left == *(SANE_Word *) val) 599141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 600141cc406Sopenharmony_ci scanner->request_mm.left = *(SANE_Word *) val; 601141cc406Sopenharmony_ci calculateDerivedValues (scanner); 602141cc406Sopenharmony_ci if (scanner->actual_mm.left != scanner->request_mm.left) 603141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 604141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 605141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 606141cc406Sopenharmony_ci 607141cc406Sopenharmony_ci case OPT_TL_Y: 608141cc406Sopenharmony_ci if (scanner->request_mm.top == *(SANE_Word *) val) 609141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 610141cc406Sopenharmony_ci scanner->request_mm.top = *(SANE_Word *) val; 611141cc406Sopenharmony_ci calculateDerivedValues (scanner); 612141cc406Sopenharmony_ci if (scanner->actual_mm.top != scanner->request_mm.top) 613141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 614141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 615141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 616141cc406Sopenharmony_ci 617141cc406Sopenharmony_ci case OPT_BR_X: 618141cc406Sopenharmony_ci if (scanner->request_mm.right == *(SANE_Word *) val) 619141cc406Sopenharmony_ci { 620141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 621141cc406Sopenharmony_ci } 622141cc406Sopenharmony_ci scanner->request_mm.right = *(SANE_Word *) val; 623141cc406Sopenharmony_ci calculateDerivedValues (scanner); 624141cc406Sopenharmony_ci if (scanner->actual_mm.right != scanner->request_mm.right) 625141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 626141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 627141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 628141cc406Sopenharmony_ci 629141cc406Sopenharmony_ci case OPT_BR_Y: 630141cc406Sopenharmony_ci if (scanner->request_mm.bottom == *(SANE_Word *) val) 631141cc406Sopenharmony_ci { 632141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 633141cc406Sopenharmony_ci } 634141cc406Sopenharmony_ci scanner->request_mm.bottom = *(SANE_Word *) val; 635141cc406Sopenharmony_ci calculateDerivedValues (scanner); 636141cc406Sopenharmony_ci if (scanner->actual_mm.bottom != scanner->request_mm.bottom) 637141cc406Sopenharmony_ci *info |= SANE_INFO_INEXACT; 638141cc406Sopenharmony_ci *info |= SANE_INFO_RELOAD_PARAMS; 639141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 640141cc406Sopenharmony_ci 641141cc406Sopenharmony_ci case OPT_MODE: 642141cc406Sopenharmony_ci for (i = 0; scan_mode_list[i]; ++i) 643141cc406Sopenharmony_ci { 644141cc406Sopenharmony_ci if (!strcmp ((SANE_Char const *) val, scan_mode_list[i])) 645141cc406Sopenharmony_ci { 646141cc406Sopenharmony_ci DBG (10, "Setting scan mode to %s (request: %s)\n", 647141cc406Sopenharmony_ci scan_mode_list[i], (SANE_Char const *) val); 648141cc406Sopenharmony_ci scanner->mode = i; 649141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 650141cc406Sopenharmony_ci } 651141cc406Sopenharmony_ci } 652141cc406Sopenharmony_ci /* Impossible */ 653141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 654141cc406Sopenharmony_ci 655141cc406Sopenharmony_ci case OPT_BRIGHTNESS: 656141cc406Sopenharmony_ci scanner->brightness = *(SANE_Word *) val; 657141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 658141cc406Sopenharmony_ci 659141cc406Sopenharmony_ci case OPT_CONTRAST: 660141cc406Sopenharmony_ci scanner->contrast = *(SANE_Word *) val; 661141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 662141cc406Sopenharmony_ci 663141cc406Sopenharmony_ci case OPT_GAMMA: 664141cc406Sopenharmony_ci scanner->gamma = SANE_UNFIX(*(SANE_Word *) val); 665141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 666141cc406Sopenharmony_ci } /* switch */ 667141cc406Sopenharmony_ci } /* else */ 668141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 669141cc406Sopenharmony_ci} 670141cc406Sopenharmony_ci 671141cc406Sopenharmony_ci/** 672141cc406Sopenharmony_ci * Called by SANE when a page acquisition operation is to be started. 673141cc406Sopenharmony_ci * 674141cc406Sopenharmony_ci */ 675141cc406Sopenharmony_ciSANE_Status 676141cc406Sopenharmony_cisane_start (SANE_Handle handle) 677141cc406Sopenharmony_ci{ 678141cc406Sopenharmony_ci struct hp3500_data *scanner = handle; 679141cc406Sopenharmony_ci int defaultFds[2]; 680141cc406Sopenharmony_ci int ret; 681141cc406Sopenharmony_ci 682141cc406Sopenharmony_ci DBG (10, "sane_start\n"); 683141cc406Sopenharmony_ci 684141cc406Sopenharmony_ci if (scanner->sfd < 0) 685141cc406Sopenharmony_ci { 686141cc406Sopenharmony_ci /* first call */ 687141cc406Sopenharmony_ci DBG (10, "sane_start opening USB device\n"); 688141cc406Sopenharmony_ci if (sanei_usb_open (scanner->sane.name, &(scanner->sfd)) != 689141cc406Sopenharmony_ci SANE_STATUS_GOOD) 690141cc406Sopenharmony_ci { 691141cc406Sopenharmony_ci DBG (MSG_ERR, 692141cc406Sopenharmony_ci "sane_start: open of %s failed:\n", scanner->sane.name); 693141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 694141cc406Sopenharmony_ci } 695141cc406Sopenharmony_ci } 696141cc406Sopenharmony_ci 697141cc406Sopenharmony_ci calculateDerivedValues (scanner); 698141cc406Sopenharmony_ci 699141cc406Sopenharmony_ci DBG (10, "\tbytes per line = %d\n", scanner->bytes_per_scan_line); 700141cc406Sopenharmony_ci DBG (10, "\tpixels_per_line = %d\n", scanner->scan_width_pixels); 701141cc406Sopenharmony_ci DBG (10, "\tlines = %d\n", scanner->scan_height_pixels); 702141cc406Sopenharmony_ci 703141cc406Sopenharmony_ci 704141cc406Sopenharmony_ci /* create a pipe, fds[0]=read-fd, fds[1]=write-fd */ 705141cc406Sopenharmony_ci if (pipe (defaultFds) < 0) 706141cc406Sopenharmony_ci { 707141cc406Sopenharmony_ci DBG (MSG_ERR, "ERROR: could not create pipe\n"); 708141cc406Sopenharmony_ci do_cancel (scanner); 709141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 710141cc406Sopenharmony_ci } 711141cc406Sopenharmony_ci 712141cc406Sopenharmony_ci scanner->pipe_r = defaultFds[0]; 713141cc406Sopenharmony_ci scanner->pipe_w = defaultFds[1]; 714141cc406Sopenharmony_ci 715141cc406Sopenharmony_ci ret = SANE_STATUS_GOOD; 716141cc406Sopenharmony_ci 717141cc406Sopenharmony_ci scanner->reader_pid = sanei_thread_begin (reader_process, scanner); 718141cc406Sopenharmony_ci time (&scanner->last_scan); 719141cc406Sopenharmony_ci 720141cc406Sopenharmony_ci if (!sanei_thread_is_valid (scanner->reader_pid)) 721141cc406Sopenharmony_ci { 722141cc406Sopenharmony_ci DBG (MSG_ERR, "cannot fork reader process.\n"); 723141cc406Sopenharmony_ci DBG (MSG_ERR, "%s", strerror (errno)); 724141cc406Sopenharmony_ci ret = SANE_STATUS_IO_ERROR; 725141cc406Sopenharmony_ci } 726141cc406Sopenharmony_ci 727141cc406Sopenharmony_ci if (sanei_thread_is_forked ()) 728141cc406Sopenharmony_ci { 729141cc406Sopenharmony_ci close (scanner->pipe_w); 730141cc406Sopenharmony_ci } 731141cc406Sopenharmony_ci 732141cc406Sopenharmony_ci if (ret == SANE_STATUS_GOOD) 733141cc406Sopenharmony_ci { 734141cc406Sopenharmony_ci DBG (10, "sane_start: ok\n"); 735141cc406Sopenharmony_ci } 736141cc406Sopenharmony_ci 737141cc406Sopenharmony_ci return ret; 738141cc406Sopenharmony_ci} 739141cc406Sopenharmony_ci 740141cc406Sopenharmony_ci 741141cc406Sopenharmony_ci/** 742141cc406Sopenharmony_ci * Called by SANE to retrieve information about the type of data 743141cc406Sopenharmony_ci * that the current scan will return. 744141cc406Sopenharmony_ci * 745141cc406Sopenharmony_ci * From the SANE spec: 746141cc406Sopenharmony_ci * This function is used to obtain the current scan parameters. The 747141cc406Sopenharmony_ci * returned parameters are guaranteed to be accurate between the time 748141cc406Sopenharmony_ci * a scan has been started (sane_start() has been called) and the 749141cc406Sopenharmony_ci * completion of that request. Outside of that window, the returned 750141cc406Sopenharmony_ci * values are best-effort estimates of what the parameters will be 751141cc406Sopenharmony_ci * when sane_start() gets invoked. 752141cc406Sopenharmony_ci * 753141cc406Sopenharmony_ci * Calling this function before a scan has actually started allows, 754141cc406Sopenharmony_ci * for example, to get an estimate of how big the scanned image will 755141cc406Sopenharmony_ci * be. The parameters passed to this function are the handle h of the 756141cc406Sopenharmony_ci * device for which the parameters should be obtained and a pointer p 757141cc406Sopenharmony_ci * to a parameter structure. 758141cc406Sopenharmony_ci */ 759141cc406Sopenharmony_ciSANE_Status 760141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 761141cc406Sopenharmony_ci{ 762141cc406Sopenharmony_ci struct hp3500_data *scanner = (struct hp3500_data *) handle; 763141cc406Sopenharmony_ci 764141cc406Sopenharmony_ci 765141cc406Sopenharmony_ci DBG (10, "sane_get_parameters\n"); 766141cc406Sopenharmony_ci 767141cc406Sopenharmony_ci calculateDerivedValues (scanner); 768141cc406Sopenharmony_ci 769141cc406Sopenharmony_ci params->format = 770141cc406Sopenharmony_ci (scanner->mode == HP3500_COLOR_SCAN) ? SANE_FRAME_RGB : SANE_FRAME_GRAY; 771141cc406Sopenharmony_ci params->depth = (scanner->mode == HP3500_LINEART_SCAN) ? 1 : 8; 772141cc406Sopenharmony_ci 773141cc406Sopenharmony_ci params->pixels_per_line = scanner->scan_width_pixels; 774141cc406Sopenharmony_ci params->lines = scanner->scan_height_pixels; 775141cc406Sopenharmony_ci 776141cc406Sopenharmony_ci params->bytes_per_line = scanner->bytes_per_scan_line; 777141cc406Sopenharmony_ci 778141cc406Sopenharmony_ci params->last_frame = 1; 779141cc406Sopenharmony_ci DBG (10, "\tdepth %d\n", params->depth); 780141cc406Sopenharmony_ci DBG (10, "\tlines %d\n", params->lines); 781141cc406Sopenharmony_ci DBG (10, "\tpixels_per_line %d\n", params->pixels_per_line); 782141cc406Sopenharmony_ci DBG (10, "\tbytes_per_line %d\n", params->bytes_per_line); 783141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 784141cc406Sopenharmony_ci} 785141cc406Sopenharmony_ci 786141cc406Sopenharmony_ci 787141cc406Sopenharmony_ci/** 788141cc406Sopenharmony_ci * Called by SANE to read data. 789141cc406Sopenharmony_ci * 790141cc406Sopenharmony_ci * In this implementation, sane_read does nothing much besides reading 791141cc406Sopenharmony_ci * data from a pipe and handing it back. On the other end of the pipe 792141cc406Sopenharmony_ci * there's the reader process which gets data from the scanner and 793141cc406Sopenharmony_ci * stuffs it into the pipe. 794141cc406Sopenharmony_ci * 795141cc406Sopenharmony_ci * From the SANE spec: 796141cc406Sopenharmony_ci * This function is used to read image data from the device 797141cc406Sopenharmony_ci * represented by handle h. Argument buf is a pointer to a memory 798141cc406Sopenharmony_ci * area that is at least maxlen bytes long. The number of bytes 799141cc406Sopenharmony_ci * returned is stored in *len. A backend must set this to zero when 800141cc406Sopenharmony_ci * the call fails (i.e., when a status other than SANE_STATUS_GOOD is 801141cc406Sopenharmony_ci * returned). 802141cc406Sopenharmony_ci * 803141cc406Sopenharmony_ci * When the call succeeds, the number of bytes returned can be 804141cc406Sopenharmony_ci * anywhere in the range from 0 to maxlen bytes. 805141cc406Sopenharmony_ci */ 806141cc406Sopenharmony_ciSANE_Status 807141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, 808141cc406Sopenharmony_ci SANE_Int max_len, SANE_Int * len) 809141cc406Sopenharmony_ci{ 810141cc406Sopenharmony_ci struct hp3500_data *scanner = (struct hp3500_data *) handle; 811141cc406Sopenharmony_ci ssize_t nread; 812141cc406Sopenharmony_ci int source = scanner->pipe_r; 813141cc406Sopenharmony_ci 814141cc406Sopenharmony_ci *len = 0; 815141cc406Sopenharmony_ci 816141cc406Sopenharmony_ci nread = read (source, buf, max_len); 817141cc406Sopenharmony_ci DBG (30, "sane_read: read %ld bytes of %ld\n", 818141cc406Sopenharmony_ci (long) nread, (long) max_len); 819141cc406Sopenharmony_ci 820141cc406Sopenharmony_ci if (nread < 0) 821141cc406Sopenharmony_ci { 822141cc406Sopenharmony_ci if (errno == EAGAIN) 823141cc406Sopenharmony_ci { 824141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 825141cc406Sopenharmony_ci } 826141cc406Sopenharmony_ci else 827141cc406Sopenharmony_ci { 828141cc406Sopenharmony_ci do_cancel (scanner); 829141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 830141cc406Sopenharmony_ci } 831141cc406Sopenharmony_ci } 832141cc406Sopenharmony_ci 833141cc406Sopenharmony_ci *len = nread; 834141cc406Sopenharmony_ci 835141cc406Sopenharmony_ci if (nread == 0) 836141cc406Sopenharmony_ci { 837141cc406Sopenharmony_ci close (source); 838141cc406Sopenharmony_ci DBG (10, "sane_read: pipe closed\n"); 839141cc406Sopenharmony_ci return SANE_STATUS_EOF; 840141cc406Sopenharmony_ci } 841141cc406Sopenharmony_ci 842141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 843141cc406Sopenharmony_ci} /* sane_read */ 844141cc406Sopenharmony_ci 845141cc406Sopenharmony_ci 846141cc406Sopenharmony_ci/** 847141cc406Sopenharmony_ci * Cancels a scan. 848141cc406Sopenharmony_ci * 849141cc406Sopenharmony_ci * It has been said on the mailing list that sane_cancel is a bit of a 850141cc406Sopenharmony_ci * misnomer because it is routinely called to signal the end of a 851141cc406Sopenharmony_ci * batch - quoting David Mosberger-Tang: 852141cc406Sopenharmony_ci * 853141cc406Sopenharmony_ci * > In other words, the idea is to have sane_start() be called, and 854141cc406Sopenharmony_ci * > collect as many images as the frontend wants (which could in turn 855141cc406Sopenharmony_ci * > consist of multiple frames each as indicated by frame-type) and 856141cc406Sopenharmony_ci * > when the frontend is done, it should call sane_cancel(). 857141cc406Sopenharmony_ci * > Sometimes it's better to think of sane_cancel() as "sane_stop()" 858141cc406Sopenharmony_ci * > but that name would have had some misleading connotations as 859141cc406Sopenharmony_ci * > well, that's why we stuck with "cancel". 860141cc406Sopenharmony_ci * 861141cc406Sopenharmony_ci * The current consensus regarding duplex and ADF scans seems to be 862141cc406Sopenharmony_ci * the following call sequence: sane_start; sane_read (repeat until 863141cc406Sopenharmony_ci * EOF); sane_start; sane_read... and then call sane_cancel if the 864141cc406Sopenharmony_ci * batch is at an end. I.e. do not call sane_cancel during the run but 865141cc406Sopenharmony_ci * as soon as you get a SANE_STATUS_NO_DOCS. 866141cc406Sopenharmony_ci * 867141cc406Sopenharmony_ci * From the SANE spec: 868141cc406Sopenharmony_ci * This function is used to immediately or as quickly as possible 869141cc406Sopenharmony_ci * cancel the currently pending operation of the device represented by 870141cc406Sopenharmony_ci * handle h. This function can be called at any time (as long as 871141cc406Sopenharmony_ci * handle h is a valid handle) but usually affects long-running 872141cc406Sopenharmony_ci * operations only (such as image is acquisition). It is safe to call 873141cc406Sopenharmony_ci * this function asynchronously (e.g., from within a signal handler). 874141cc406Sopenharmony_ci * It is important to note that completion of this operation does not 875141cc406Sopenharmony_ci * imply that the currently pending operation has been cancelled. It 876141cc406Sopenharmony_ci * only guarantees that cancellation has been initiated. Cancellation 877141cc406Sopenharmony_ci * completes only when the cancelled call returns (typically with a 878141cc406Sopenharmony_ci * status value of SANE_STATUS_CANCELLED). Since the SANE API does 879141cc406Sopenharmony_ci * not require any other operations to be re-entrant, this implies 880141cc406Sopenharmony_ci * that a frontend must not call any other operation until the 881141cc406Sopenharmony_ci * cancelled operation has returned. 882141cc406Sopenharmony_ci */ 883141cc406Sopenharmony_civoid 884141cc406Sopenharmony_cisane_cancel (SANE_Handle h) 885141cc406Sopenharmony_ci{ 886141cc406Sopenharmony_ci DBG (10, "sane_cancel\n"); 887141cc406Sopenharmony_ci do_cancel ((struct hp3500_data *) h); 888141cc406Sopenharmony_ci} 889141cc406Sopenharmony_ci 890141cc406Sopenharmony_ci 891141cc406Sopenharmony_ci/** 892141cc406Sopenharmony_ci * Ends use of the scanner. 893141cc406Sopenharmony_ci * 894141cc406Sopenharmony_ci * From the SANE spec: 895141cc406Sopenharmony_ci * This function terminates the association between the device handle 896141cc406Sopenharmony_ci * passed in argument h and the device it represents. If the device is 897141cc406Sopenharmony_ci * presently active, a call to sane_cancel() is performed first. After 898141cc406Sopenharmony_ci * this function returns, handle h must not be used anymore. 899141cc406Sopenharmony_ci */ 900141cc406Sopenharmony_civoid 901141cc406Sopenharmony_cisane_close (SANE_Handle handle) 902141cc406Sopenharmony_ci{ 903141cc406Sopenharmony_ci DBG (10, "sane_close\n"); 904141cc406Sopenharmony_ci do_reset (handle); 905141cc406Sopenharmony_ci do_cancel (handle); 906141cc406Sopenharmony_ci} 907141cc406Sopenharmony_ci 908141cc406Sopenharmony_ci 909141cc406Sopenharmony_ci/** 910141cc406Sopenharmony_ci * Terminates the backend. 911141cc406Sopenharmony_ci * 912141cc406Sopenharmony_ci * From the SANE spec: 913141cc406Sopenharmony_ci * This function must be called to terminate use of a backend. The 914141cc406Sopenharmony_ci * function will first close all device handles that still might be 915141cc406Sopenharmony_ci * open (it is recommended to close device handles explicitly through 916141cc406Sopenharmony_ci * a call to sane_clo-se(), but backends are required to release all 917141cc406Sopenharmony_ci * resources upon a call to this function). After this function 918141cc406Sopenharmony_ci * returns, no function other than sane_init() may be called 919141cc406Sopenharmony_ci * (regardless of the status value returned by sane_exit(). Neglecting 920141cc406Sopenharmony_ci * to call this function may result in some resources not being 921141cc406Sopenharmony_ci * released properly. 922141cc406Sopenharmony_ci */ 923141cc406Sopenharmony_civoid 924141cc406Sopenharmony_cisane_exit (void) 925141cc406Sopenharmony_ci{ 926141cc406Sopenharmony_ci struct hp3500_data *dev, *next; 927141cc406Sopenharmony_ci 928141cc406Sopenharmony_ci DBG (10, "sane_exit\n"); 929141cc406Sopenharmony_ci 930141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = next) 931141cc406Sopenharmony_ci { 932141cc406Sopenharmony_ci next = dev->next; 933141cc406Sopenharmony_ci free (dev->devicename); 934141cc406Sopenharmony_ci free (dev); 935141cc406Sopenharmony_ci } 936141cc406Sopenharmony_ci 937141cc406Sopenharmony_ci if (devlist) 938141cc406Sopenharmony_ci free (devlist); 939141cc406Sopenharmony_ci} 940141cc406Sopenharmony_ci 941141cc406Sopenharmony_ci/* 942141cc406Sopenharmony_ci * The scanning code 943141cc406Sopenharmony_ci */ 944141cc406Sopenharmony_ci 945141cc406Sopenharmony_cistatic SANE_Status 946141cc406Sopenharmony_ciattachScanner (const char *devicename) 947141cc406Sopenharmony_ci{ 948141cc406Sopenharmony_ci struct hp3500_data *dev; 949141cc406Sopenharmony_ci 950141cc406Sopenharmony_ci DBG (15, "attach_scanner: %s\n", devicename); 951141cc406Sopenharmony_ci 952141cc406Sopenharmony_ci for (dev = first_dev; dev; dev = dev->next) 953141cc406Sopenharmony_ci { 954141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devicename) == 0) 955141cc406Sopenharmony_ci { 956141cc406Sopenharmony_ci DBG (5, "attach_scanner: scanner already attached (is ok)!\n"); 957141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 958141cc406Sopenharmony_ci } 959141cc406Sopenharmony_ci } 960141cc406Sopenharmony_ci 961141cc406Sopenharmony_ci 962141cc406Sopenharmony_ci if (NULL == (dev = malloc (sizeof (*dev)))) 963141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 964141cc406Sopenharmony_ci memset (dev, 0, sizeof (*dev)); 965141cc406Sopenharmony_ci 966141cc406Sopenharmony_ci dev->devicename = strdup (devicename); 967141cc406Sopenharmony_ci dev->sfd = -1; 968141cc406Sopenharmony_ci dev->last_scan = 0; 969141cc406Sopenharmony_ci dev->reader_pid = (SANE_Pid) -1; 970141cc406Sopenharmony_ci dev->pipe_r = dev->pipe_w = -1; 971141cc406Sopenharmony_ci 972141cc406Sopenharmony_ci dev->sane.name = dev->devicename; 973141cc406Sopenharmony_ci dev->sane.vendor = "Hewlett-Packard"; 974141cc406Sopenharmony_ci dev->sane.model = "ScanJet 3500"; 975141cc406Sopenharmony_ci dev->sane.type = "scanner"; 976141cc406Sopenharmony_ci 977141cc406Sopenharmony_ci ++num_devices; 978141cc406Sopenharmony_ci *new_dev = dev; 979141cc406Sopenharmony_ci 980141cc406Sopenharmony_ci DBG (15, "attach_scanner: done\n"); 981141cc406Sopenharmony_ci 982141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 983141cc406Sopenharmony_ci} 984141cc406Sopenharmony_ci 985141cc406Sopenharmony_cistatic SANE_Status 986141cc406Sopenharmony_ciinit_options (struct hp3500_data *scanner) 987141cc406Sopenharmony_ci{ 988141cc406Sopenharmony_ci int i; 989141cc406Sopenharmony_ci SANE_Option_Descriptor *opt; 990141cc406Sopenharmony_ci 991141cc406Sopenharmony_ci memset (scanner->opt, 0, sizeof (scanner->opt)); 992141cc406Sopenharmony_ci 993141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; ++i) 994141cc406Sopenharmony_ci { 995141cc406Sopenharmony_ci scanner->opt[i].name = "filler"; 996141cc406Sopenharmony_ci scanner->opt[i].size = sizeof (SANE_Word); 997141cc406Sopenharmony_ci scanner->opt[i].cap = SANE_CAP_INACTIVE; 998141cc406Sopenharmony_ci } 999141cc406Sopenharmony_ci 1000141cc406Sopenharmony_ci opt = scanner->opt + OPT_NUM_OPTS; 1001141cc406Sopenharmony_ci opt->title = SANE_TITLE_NUM_OPTIONS; 1002141cc406Sopenharmony_ci opt->desc = SANE_DESC_NUM_OPTIONS; 1003141cc406Sopenharmony_ci opt->type = SANE_TYPE_INT; 1004141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_DETECT; 1005141cc406Sopenharmony_ci 1006141cc406Sopenharmony_ci opt = scanner->opt + OPT_RESOLUTION; 1007141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_RESOLUTION; 1008141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_RESOLUTION; 1009141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_RESOLUTION; 1010141cc406Sopenharmony_ci opt->type = SANE_TYPE_INT; 1011141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; 1012141cc406Sopenharmony_ci opt->constraint.word_list = res_list; 1013141cc406Sopenharmony_ci opt->unit = SANE_UNIT_DPI; 1014141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1015141cc406Sopenharmony_ci 1016141cc406Sopenharmony_ci opt = scanner->opt + OPT_GEOMETRY_GROUP; 1017141cc406Sopenharmony_ci opt->title = SANE_I18N ("Geometry"); 1018141cc406Sopenharmony_ci opt->desc = SANE_I18N ("Geometry Group"); 1019141cc406Sopenharmony_ci opt->type = SANE_TYPE_GROUP; 1020141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_NONE; 1021141cc406Sopenharmony_ci 1022141cc406Sopenharmony_ci opt = scanner->opt + OPT_TL_X; 1023141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_TL_X; 1024141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_TL_X; 1025141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_TL_X; 1026141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1027141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1028141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1029141cc406Sopenharmony_ci opt->constraint.range = &range_x; 1030141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1031141cc406Sopenharmony_ci 1032141cc406Sopenharmony_ci opt = scanner->opt + OPT_TL_Y; 1033141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_TL_Y; 1034141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_TL_Y; 1035141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_TL_Y; 1036141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1037141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1038141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1039141cc406Sopenharmony_ci opt->constraint.range = &range_y; 1040141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1041141cc406Sopenharmony_ci 1042141cc406Sopenharmony_ci opt = scanner->opt + OPT_BR_X; 1043141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_BR_X; 1044141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_BR_X; 1045141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_BR_X; 1046141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1047141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1048141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1049141cc406Sopenharmony_ci opt->constraint.range = &range_x; 1050141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1051141cc406Sopenharmony_ci 1052141cc406Sopenharmony_ci opt = scanner->opt + OPT_BR_Y; 1053141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_BR_Y; 1054141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_BR_Y; 1055141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_BR_Y; 1056141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1057141cc406Sopenharmony_ci opt->unit = SANE_UNIT_MM; 1058141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1059141cc406Sopenharmony_ci opt->constraint.range = &range_y; 1060141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1061141cc406Sopenharmony_ci 1062141cc406Sopenharmony_ci if (!scan_mode_list[0]) 1063141cc406Sopenharmony_ci { 1064141cc406Sopenharmony_ci scan_mode_list[HP3500_COLOR_SCAN] = SANE_VALUE_SCAN_MODE_COLOR; 1065141cc406Sopenharmony_ci scan_mode_list[HP3500_GRAY_SCAN] = SANE_VALUE_SCAN_MODE_GRAY; 1066141cc406Sopenharmony_ci scan_mode_list[HP3500_LINEART_SCAN] = SANE_VALUE_SCAN_MODE_LINEART; 1067141cc406Sopenharmony_ci scan_mode_list[HP3500_TOTAL_SCANS] = 0; 1068141cc406Sopenharmony_ci } 1069141cc406Sopenharmony_ci 1070141cc406Sopenharmony_ci opt = scanner->opt + OPT_MODE_GROUP; 1071141cc406Sopenharmony_ci opt->title = SANE_I18N ("Scan Mode Group"); 1072141cc406Sopenharmony_ci opt->desc = SANE_I18N ("Scan Mode Group"); 1073141cc406Sopenharmony_ci opt->type = SANE_TYPE_GROUP; 1074141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_NONE; 1075141cc406Sopenharmony_ci 1076141cc406Sopenharmony_ci opt = scanner->opt + OPT_MODE; 1077141cc406Sopenharmony_ci opt->name = SANE_NAME_SCAN_MODE; 1078141cc406Sopenharmony_ci opt->title = SANE_TITLE_SCAN_MODE; 1079141cc406Sopenharmony_ci opt->desc = SANE_DESC_SCAN_MODE; 1080141cc406Sopenharmony_ci opt->type = SANE_TYPE_STRING; 1081141cc406Sopenharmony_ci opt->size = max_string_size(scan_mode_list); 1082141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; 1083141cc406Sopenharmony_ci opt->constraint.string_list = (SANE_String_Const *) scan_mode_list; 1084141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1085141cc406Sopenharmony_ci 1086141cc406Sopenharmony_ci opt = scanner->opt + OPT_BRIGHTNESS; 1087141cc406Sopenharmony_ci opt->name = SANE_NAME_BRIGHTNESS; 1088141cc406Sopenharmony_ci opt->title = SANE_TITLE_BRIGHTNESS; 1089141cc406Sopenharmony_ci opt->desc = SANE_DESC_BRIGHTNESS; 1090141cc406Sopenharmony_ci opt->type = SANE_TYPE_INT; 1091141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1092141cc406Sopenharmony_ci opt->constraint.range = &range_brightness; 1093141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1094141cc406Sopenharmony_ci 1095141cc406Sopenharmony_ci opt = scanner->opt + OPT_CONTRAST; 1096141cc406Sopenharmony_ci opt->name = SANE_NAME_CONTRAST; 1097141cc406Sopenharmony_ci opt->title = SANE_TITLE_CONTRAST; 1098141cc406Sopenharmony_ci opt->desc = SANE_DESC_CONTRAST; 1099141cc406Sopenharmony_ci opt->type = SANE_TYPE_INT; 1100141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1101141cc406Sopenharmony_ci opt->constraint.range = &range_contrast; 1102141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1103141cc406Sopenharmony_ci 1104141cc406Sopenharmony_ci opt = scanner->opt + OPT_GAMMA; 1105141cc406Sopenharmony_ci opt->name = SANE_NAME_ANALOG_GAMMA; 1106141cc406Sopenharmony_ci opt->title = SANE_TITLE_ANALOG_GAMMA; 1107141cc406Sopenharmony_ci opt->desc = SANE_DESC_ANALOG_GAMMA; 1108141cc406Sopenharmony_ci opt->type = SANE_TYPE_FIXED; 1109141cc406Sopenharmony_ci opt->unit = SANE_UNIT_NONE; 1110141cc406Sopenharmony_ci opt->constraint_type = SANE_CONSTRAINT_RANGE; 1111141cc406Sopenharmony_ci opt->constraint.range = &range_gamma; 1112141cc406Sopenharmony_ci opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 1113141cc406Sopenharmony_ci 1114141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1115141cc406Sopenharmony_ci} 1116141cc406Sopenharmony_ci 1117141cc406Sopenharmony_cistatic void 1118141cc406Sopenharmony_cido_reset (struct hp3500_data *scanner) 1119141cc406Sopenharmony_ci{ 1120141cc406Sopenharmony_ci (void) scanner; /* kill warning */ 1121141cc406Sopenharmony_ci} 1122141cc406Sopenharmony_ci 1123141cc406Sopenharmony_cistatic void 1124141cc406Sopenharmony_cido_cancel (struct hp3500_data *scanner) 1125141cc406Sopenharmony_ci{ 1126141cc406Sopenharmony_ci if (sanei_thread_is_valid (scanner->reader_pid)) 1127141cc406Sopenharmony_ci { 1128141cc406Sopenharmony_ci 1129141cc406Sopenharmony_ci if (sanei_thread_kill (scanner->reader_pid) == 0) 1130141cc406Sopenharmony_ci { 1131141cc406Sopenharmony_ci int exit_status; 1132141cc406Sopenharmony_ci 1133141cc406Sopenharmony_ci sanei_thread_waitpid (scanner->reader_pid, &exit_status); 1134141cc406Sopenharmony_ci } 1135141cc406Sopenharmony_ci sanei_thread_invalidate (scanner->reader_pid); 1136141cc406Sopenharmony_ci } 1137141cc406Sopenharmony_ci if (scanner->pipe_r >= 0) 1138141cc406Sopenharmony_ci { 1139141cc406Sopenharmony_ci close (scanner->pipe_r); 1140141cc406Sopenharmony_ci scanner->pipe_r = -1; 1141141cc406Sopenharmony_ci } 1142141cc406Sopenharmony_ci} 1143141cc406Sopenharmony_ci 1144141cc406Sopenharmony_cistatic void 1145141cc406Sopenharmony_cicalculateDerivedValues (struct hp3500_data *scanner) 1146141cc406Sopenharmony_ci{ 1147141cc406Sopenharmony_ci 1148141cc406Sopenharmony_ci DBG (12, "calculateDerivedValues\n"); 1149141cc406Sopenharmony_ci 1150141cc406Sopenharmony_ci /* Convert the SANE_FIXED values for the scan area into 1/1200 inch 1151141cc406Sopenharmony_ci * scanner units */ 1152141cc406Sopenharmony_ci 1153141cc406Sopenharmony_ci scanner->fullres_pixels.left = 1154141cc406Sopenharmony_ci FIXED_MM_TO_SCANNER_UNIT (scanner->request_mm.left); 1155141cc406Sopenharmony_ci scanner->fullres_pixels.top = 1156141cc406Sopenharmony_ci FIXED_MM_TO_SCANNER_UNIT (scanner->request_mm.top); 1157141cc406Sopenharmony_ci scanner->fullres_pixels.right = 1158141cc406Sopenharmony_ci FIXED_MM_TO_SCANNER_UNIT (scanner->request_mm.right); 1159141cc406Sopenharmony_ci scanner->fullres_pixels.bottom = 1160141cc406Sopenharmony_ci FIXED_MM_TO_SCANNER_UNIT (scanner->request_mm.bottom); 1161141cc406Sopenharmony_ci 1162141cc406Sopenharmony_ci DBG (12, "\tleft margin: %u\n", scanner->fullres_pixels.left); 1163141cc406Sopenharmony_ci DBG (12, "\ttop margin: %u\n", scanner->fullres_pixels.top); 1164141cc406Sopenharmony_ci DBG (12, "\tright margin: %u\n", scanner->fullres_pixels.right); 1165141cc406Sopenharmony_ci DBG (12, "\tbottom margin: %u\n", scanner->fullres_pixels.bottom); 1166141cc406Sopenharmony_ci 1167141cc406Sopenharmony_ci 1168141cc406Sopenharmony_ci scanner->scan_width_pixels = 1169141cc406Sopenharmony_ci scanner->resolution * (scanner->fullres_pixels.right - 1170141cc406Sopenharmony_ci scanner->fullres_pixels.left) / 1200; 1171141cc406Sopenharmony_ci scanner->scan_height_pixels = 1172141cc406Sopenharmony_ci scanner->resolution * (scanner->fullres_pixels.bottom - 1173141cc406Sopenharmony_ci scanner->fullres_pixels.top) / 1200; 1174141cc406Sopenharmony_ci if (scanner->mode == HP3500_LINEART_SCAN) 1175141cc406Sopenharmony_ci scanner->bytes_per_scan_line = (scanner->scan_width_pixels + 7) / 8; 1176141cc406Sopenharmony_ci else if (scanner->mode == HP3500_GRAY_SCAN) 1177141cc406Sopenharmony_ci scanner->bytes_per_scan_line = scanner->scan_width_pixels; 1178141cc406Sopenharmony_ci else 1179141cc406Sopenharmony_ci scanner->bytes_per_scan_line = scanner->scan_width_pixels * 3; 1180141cc406Sopenharmony_ci 1181141cc406Sopenharmony_ci if (scanner->scan_width_pixels < 1) 1182141cc406Sopenharmony_ci scanner->scan_width_pixels = 1; 1183141cc406Sopenharmony_ci if (scanner->scan_height_pixels < 1) 1184141cc406Sopenharmony_ci scanner->scan_height_pixels = 1; 1185141cc406Sopenharmony_ci 1186141cc406Sopenharmony_ci scanner->actres_pixels.left = 1187141cc406Sopenharmony_ci scanner->fullres_pixels.left * scanner->resolution / 1200; 1188141cc406Sopenharmony_ci scanner->actres_pixels.top = 1189141cc406Sopenharmony_ci scanner->fullres_pixels.top * scanner->resolution / 1200; 1190141cc406Sopenharmony_ci scanner->actres_pixels.right = 1191141cc406Sopenharmony_ci scanner->actres_pixels.left + scanner->scan_width_pixels; 1192141cc406Sopenharmony_ci scanner->actres_pixels.bottom = 1193141cc406Sopenharmony_ci scanner->actres_pixels.top + scanner->scan_height_pixels; 1194141cc406Sopenharmony_ci 1195141cc406Sopenharmony_ci scanner->actual_mm.left = 1196141cc406Sopenharmony_ci SCANNER_UNIT_TO_FIXED_MM (scanner->fullres_pixels.left); 1197141cc406Sopenharmony_ci scanner->actual_mm.top = 1198141cc406Sopenharmony_ci SCANNER_UNIT_TO_FIXED_MM (scanner->fullres_pixels.top); 1199141cc406Sopenharmony_ci scanner->actual_mm.bottom = 1200141cc406Sopenharmony_ci SCANNER_UNIT_TO_FIXED_MM (scanner->scan_width_pixels * 1200 / 1201141cc406Sopenharmony_ci scanner->resolution); 1202141cc406Sopenharmony_ci scanner->actual_mm.right = 1203141cc406Sopenharmony_ci SCANNER_UNIT_TO_FIXED_MM (scanner->scan_height_pixels * 1200 / 1204141cc406Sopenharmony_ci scanner->resolution); 1205141cc406Sopenharmony_ci 1206141cc406Sopenharmony_ci DBG (12, "calculateDerivedValues: ok\n"); 1207141cc406Sopenharmony_ci} 1208141cc406Sopenharmony_ci 1209141cc406Sopenharmony_ci/* From here on in we have the original code written for the scanner demo */ 1210141cc406Sopenharmony_ci 1211141cc406Sopenharmony_ci#define MAX_COMMANDS_BYTES 131072 1212141cc406Sopenharmony_ci#define MAX_READ_COMMANDS 1 /* Issuing more than one register 1213141cc406Sopenharmony_ci * read command in a single request 1214141cc406Sopenharmony_ci * seems to put the device in an 1215141cc406Sopenharmony_ci * unpredictable state. 1216141cc406Sopenharmony_ci */ 1217141cc406Sopenharmony_ci#define MAX_READ_BYTES 0xffc0 1218141cc406Sopenharmony_ci 1219141cc406Sopenharmony_ci#define REG_DESTINATION_POSITION 0x60 1220141cc406Sopenharmony_ci#define REG_MOVE_CONTROL_TEST 0xb3 1221141cc406Sopenharmony_ci 1222141cc406Sopenharmony_cistatic int command_reads_outstanding = 0; 1223141cc406Sopenharmony_cistatic int command_bytes_outstanding = 0; 1224141cc406Sopenharmony_cistatic unsigned char command_buffer[MAX_COMMANDS_BYTES]; 1225141cc406Sopenharmony_cistatic int receive_bytes_outstanding = 0; 1226141cc406Sopenharmony_cistatic char *command_readmem_outstanding[MAX_READ_COMMANDS]; 1227141cc406Sopenharmony_cistatic int command_readbytes_outstanding[MAX_READ_COMMANDS]; 1228141cc406Sopenharmony_cistatic unsigned char sram_access_method = 0; 1229141cc406Sopenharmony_cistatic unsigned sram_size = 0; 1230141cc406Sopenharmony_cistatic int udh; 1231141cc406Sopenharmony_ci 1232141cc406Sopenharmony_cistatic int 1233141cc406Sopenharmony_cirt_execute_commands (void) 1234141cc406Sopenharmony_ci{ 1235141cc406Sopenharmony_ci SANE_Status result; 1236141cc406Sopenharmony_ci size_t bytes; 1237141cc406Sopenharmony_ci 1238141cc406Sopenharmony_ci if (!command_bytes_outstanding) 1239141cc406Sopenharmony_ci return 0; 1240141cc406Sopenharmony_ci 1241141cc406Sopenharmony_ci bytes = command_bytes_outstanding; 1242141cc406Sopenharmony_ci 1243141cc406Sopenharmony_ci result = sanei_usb_write_bulk (udh, /* 0x02, */ command_buffer, &bytes); 1244141cc406Sopenharmony_ci 1245141cc406Sopenharmony_ci if (result == SANE_STATUS_GOOD && receive_bytes_outstanding) 1246141cc406Sopenharmony_ci { 1247141cc406Sopenharmony_ci unsigned char readbuf[MAX_READ_BYTES]; 1248141cc406Sopenharmony_ci int total_read = 0; 1249141cc406Sopenharmony_ci 1250141cc406Sopenharmony_ci do 1251141cc406Sopenharmony_ci { 1252141cc406Sopenharmony_ci bytes = receive_bytes_outstanding - total_read; 1253141cc406Sopenharmony_ci result = sanei_usb_read_bulk (udh, 1254141cc406Sopenharmony_ci /* 0x81, */ 1255141cc406Sopenharmony_ci readbuf + total_read, &bytes); 1256141cc406Sopenharmony_ci if (result == SANE_STATUS_GOOD) 1257141cc406Sopenharmony_ci total_read += bytes; 1258141cc406Sopenharmony_ci else 1259141cc406Sopenharmony_ci break; 1260141cc406Sopenharmony_ci } 1261141cc406Sopenharmony_ci while (total_read < receive_bytes_outstanding); 1262141cc406Sopenharmony_ci if (result == SANE_STATUS_GOOD) 1263141cc406Sopenharmony_ci { 1264141cc406Sopenharmony_ci unsigned char *readptr; 1265141cc406Sopenharmony_ci int i; 1266141cc406Sopenharmony_ci 1267141cc406Sopenharmony_ci for (i = 0, readptr = readbuf; 1268141cc406Sopenharmony_ci i < command_reads_outstanding; 1269141cc406Sopenharmony_ci readptr += command_readbytes_outstanding[i++]) 1270141cc406Sopenharmony_ci { 1271141cc406Sopenharmony_ci memcpy (command_readmem_outstanding[i], 1272141cc406Sopenharmony_ci readptr, command_readbytes_outstanding[i]); 1273141cc406Sopenharmony_ci } 1274141cc406Sopenharmony_ci } 1275141cc406Sopenharmony_ci } 1276141cc406Sopenharmony_ci receive_bytes_outstanding = command_reads_outstanding = 1277141cc406Sopenharmony_ci command_bytes_outstanding = 0; 1278141cc406Sopenharmony_ci return (result == SANE_STATUS_GOOD) ? 0 : -1; 1279141cc406Sopenharmony_ci} 1280141cc406Sopenharmony_ci 1281141cc406Sopenharmony_cistatic int 1282141cc406Sopenharmony_cirt_queue_command (int command, 1283141cc406Sopenharmony_ci int reg, 1284141cc406Sopenharmony_ci int count, 1285141cc406Sopenharmony_ci int bytes, void const *data_, int readbytes, void *readdata) 1286141cc406Sopenharmony_ci{ 1287141cc406Sopenharmony_ci int len = 4 + bytes; 1288141cc406Sopenharmony_ci unsigned char *buffer; 1289141cc406Sopenharmony_ci unsigned char const *data = data_; 1290141cc406Sopenharmony_ci 1291141cc406Sopenharmony_ci /* We add "bytes" here to account for the possibility that all of the 1292141cc406Sopenharmony_ci * data bytes are 0xaa and hence require a following 0x00 byte. 1293141cc406Sopenharmony_ci */ 1294141cc406Sopenharmony_ci if (command_bytes_outstanding + len + bytes > MAX_COMMANDS_BYTES || 1295141cc406Sopenharmony_ci (readbytes && 1296141cc406Sopenharmony_ci ((command_reads_outstanding >= MAX_READ_COMMANDS) || 1297141cc406Sopenharmony_ci (receive_bytes_outstanding >= MAX_READ_BYTES)))) 1298141cc406Sopenharmony_ci { 1299141cc406Sopenharmony_ci if (rt_execute_commands () < 0) 1300141cc406Sopenharmony_ci return -1; 1301141cc406Sopenharmony_ci } 1302141cc406Sopenharmony_ci 1303141cc406Sopenharmony_ci buffer = command_buffer + command_bytes_outstanding; 1304141cc406Sopenharmony_ci 1305141cc406Sopenharmony_ci *buffer++ = command; 1306141cc406Sopenharmony_ci *buffer++ = reg; 1307141cc406Sopenharmony_ci *buffer++ = count >> 8; 1308141cc406Sopenharmony_ci *buffer++ = count; 1309141cc406Sopenharmony_ci while (bytes--) 1310141cc406Sopenharmony_ci { 1311141cc406Sopenharmony_ci *buffer++ = *data; 1312141cc406Sopenharmony_ci if (*data++ == 0xaa) 1313141cc406Sopenharmony_ci { 1314141cc406Sopenharmony_ci *buffer++ = 0; 1315141cc406Sopenharmony_ci ++len; 1316141cc406Sopenharmony_ci } 1317141cc406Sopenharmony_ci } 1318141cc406Sopenharmony_ci command_bytes_outstanding += len; 1319141cc406Sopenharmony_ci if (readbytes) 1320141cc406Sopenharmony_ci { 1321141cc406Sopenharmony_ci command_readbytes_outstanding[command_reads_outstanding] = readbytes; 1322141cc406Sopenharmony_ci command_readmem_outstanding[command_reads_outstanding] = readdata; 1323141cc406Sopenharmony_ci receive_bytes_outstanding += readbytes; 1324141cc406Sopenharmony_ci ++command_reads_outstanding; 1325141cc406Sopenharmony_ci } 1326141cc406Sopenharmony_ci 1327141cc406Sopenharmony_ci return 0; 1328141cc406Sopenharmony_ci} 1329141cc406Sopenharmony_ci 1330141cc406Sopenharmony_cistatic int 1331141cc406Sopenharmony_cirt_send_command_immediate (int command, 1332141cc406Sopenharmony_ci int reg, 1333141cc406Sopenharmony_ci int count, 1334141cc406Sopenharmony_ci int bytes, 1335141cc406Sopenharmony_ci void *data, int readbytes, void *readdata) 1336141cc406Sopenharmony_ci{ 1337141cc406Sopenharmony_ci rt_queue_command (command, reg, count, bytes, data, readbytes, readdata); 1338141cc406Sopenharmony_ci return rt_execute_commands (); 1339141cc406Sopenharmony_ci} 1340141cc406Sopenharmony_ci 1341141cc406Sopenharmony_cistatic int 1342141cc406Sopenharmony_cirt_queue_read_register (int reg, int bytes, void *data) 1343141cc406Sopenharmony_ci{ 1344141cc406Sopenharmony_ci return rt_queue_command (RTCMD_GETREG, reg, bytes, 0, 0, bytes, data); 1345141cc406Sopenharmony_ci} 1346141cc406Sopenharmony_ci 1347141cc406Sopenharmony_cistatic int 1348141cc406Sopenharmony_cirt_read_register_immediate (int reg, int bytes, void *data) 1349141cc406Sopenharmony_ci{ 1350141cc406Sopenharmony_ci if (rt_queue_read_register (reg, bytes, data) < 0) 1351141cc406Sopenharmony_ci return -1; 1352141cc406Sopenharmony_ci return rt_execute_commands (); 1353141cc406Sopenharmony_ci} 1354141cc406Sopenharmony_ci 1355141cc406Sopenharmony_cistatic int 1356141cc406Sopenharmony_cirt_queue_set_register (int reg, int bytes, void *data) 1357141cc406Sopenharmony_ci{ 1358141cc406Sopenharmony_ci return rt_queue_command (RTCMD_SETREG, reg, bytes, bytes, data, 0, 0); 1359141cc406Sopenharmony_ci} 1360141cc406Sopenharmony_ci 1361141cc406Sopenharmony_cistatic int 1362141cc406Sopenharmony_cirt_set_register_immediate (int reg, int bytes, void *data) 1363141cc406Sopenharmony_ci{ 1364141cc406Sopenharmony_ci if (reg < 0xb3 && reg + bytes > 0xb3) 1365141cc406Sopenharmony_ci { 1366141cc406Sopenharmony_ci int bytes_in_first_block = 0xb3 - reg; 1367141cc406Sopenharmony_ci 1368141cc406Sopenharmony_ci if (rt_set_register_immediate (reg, bytes_in_first_block, data) < 0 || 1369141cc406Sopenharmony_ci rt_set_register_immediate (0xb4, bytes - bytes_in_first_block - 1, 1370141cc406Sopenharmony_ci (char *) data + bytes_in_first_block + 1371141cc406Sopenharmony_ci 1) < 0) 1372141cc406Sopenharmony_ci return -1; 1373141cc406Sopenharmony_ci return 0; 1374141cc406Sopenharmony_ci } 1375141cc406Sopenharmony_ci if (rt_queue_set_register (reg, bytes, data) < 0) 1376141cc406Sopenharmony_ci return -1; 1377141cc406Sopenharmony_ci return rt_execute_commands (); 1378141cc406Sopenharmony_ci} 1379141cc406Sopenharmony_ci 1380141cc406Sopenharmony_cistatic int 1381141cc406Sopenharmony_cirt_set_one_register (int reg, int val) 1382141cc406Sopenharmony_ci{ 1383141cc406Sopenharmony_ci char r = val; 1384141cc406Sopenharmony_ci 1385141cc406Sopenharmony_ci return rt_set_register_immediate (reg, 1, &r); 1386141cc406Sopenharmony_ci} 1387141cc406Sopenharmony_ci 1388141cc406Sopenharmony_cistatic int 1389141cc406Sopenharmony_cirt_write_sram (int bytes, void *data_) 1390141cc406Sopenharmony_ci{ 1391141cc406Sopenharmony_ci unsigned char *data = (unsigned char *) data_; 1392141cc406Sopenharmony_ci 1393141cc406Sopenharmony_ci /* The number of bytes passed in could be much larger than we can transmit 1394141cc406Sopenharmony_ci * (0xffc0) bytes. With 0xaa escapes it could be even larger. Accordingly 1395141cc406Sopenharmony_ci * we need to count the 0xaa escapes and write in chunks if the number of 1396141cc406Sopenharmony_ci * bytes would otherwise exceed a limit (I have used 0xf000 as the limit). 1397141cc406Sopenharmony_ci */ 1398141cc406Sopenharmony_ci while (bytes > 0) 1399141cc406Sopenharmony_ci { 1400141cc406Sopenharmony_ci int now = 0; 1401141cc406Sopenharmony_ci int bufsize = 0; 1402141cc406Sopenharmony_ci 1403141cc406Sopenharmony_ci while (now < bytes && bufsize < 0xf000) 1404141cc406Sopenharmony_ci { 1405141cc406Sopenharmony_ci int i; 1406141cc406Sopenharmony_ci 1407141cc406Sopenharmony_ci /* Try to avoid writing part pages */ 1408141cc406Sopenharmony_ci for (i = 0; i < 32 && now < bytes; ++i) 1409141cc406Sopenharmony_ci { 1410141cc406Sopenharmony_ci ++bufsize; 1411141cc406Sopenharmony_ci if (data[now++] == 0xaa) 1412141cc406Sopenharmony_ci ++bufsize; 1413141cc406Sopenharmony_ci } 1414141cc406Sopenharmony_ci } 1415141cc406Sopenharmony_ci 1416141cc406Sopenharmony_ci if (rt_send_command_immediate (RTCMD_WRITESRAM, 0, now, now, data, 0, 1417141cc406Sopenharmony_ci 0) < 0) 1418141cc406Sopenharmony_ci return -1; 1419141cc406Sopenharmony_ci bytes -= now; 1420141cc406Sopenharmony_ci data += now; 1421141cc406Sopenharmony_ci } 1422141cc406Sopenharmony_ci return 0; 1423141cc406Sopenharmony_ci} 1424141cc406Sopenharmony_ci 1425141cc406Sopenharmony_cistatic int 1426141cc406Sopenharmony_cirt_read_sram (int bytes, void *data_) 1427141cc406Sopenharmony_ci{ 1428141cc406Sopenharmony_ci unsigned char *data = (unsigned char *) data_; 1429141cc406Sopenharmony_ci 1430141cc406Sopenharmony_ci while (bytes > 0) 1431141cc406Sopenharmony_ci { 1432141cc406Sopenharmony_ci int now = (bytes > 0xf000) ? 0xf000 : bytes; 1433141cc406Sopenharmony_ci if (rt_send_command_immediate (RTCMD_READSRAM, 0, bytes, 0, 0, bytes, 1434141cc406Sopenharmony_ci data) < 0) 1435141cc406Sopenharmony_ci return -1; 1436141cc406Sopenharmony_ci bytes -= now; 1437141cc406Sopenharmony_ci data += now; 1438141cc406Sopenharmony_ci } 1439141cc406Sopenharmony_ci return 0; 1440141cc406Sopenharmony_ci} 1441141cc406Sopenharmony_ci 1442141cc406Sopenharmony_cistatic int 1443141cc406Sopenharmony_cirt_set_sram_page (int page) 1444141cc406Sopenharmony_ci{ 1445141cc406Sopenharmony_ci unsigned char regs[2]; 1446141cc406Sopenharmony_ci 1447141cc406Sopenharmony_ci regs[0] = page; 1448141cc406Sopenharmony_ci regs[1] = page >> 8; 1449141cc406Sopenharmony_ci 1450141cc406Sopenharmony_ci return rt_set_register_immediate (0x91, 2, regs); 1451141cc406Sopenharmony_ci} 1452141cc406Sopenharmony_ci 1453141cc406Sopenharmony_cistatic int 1454141cc406Sopenharmony_cirt_detect_sram (unsigned *totalbytes, unsigned char *r93setting) 1455141cc406Sopenharmony_ci{ 1456141cc406Sopenharmony_ci char data[0x818]; 1457141cc406Sopenharmony_ci char testbuf[0x818]; 1458141cc406Sopenharmony_ci unsigned i; 1459141cc406Sopenharmony_ci int test_values[] = { 6, 2, 1, -1 }; 1460141cc406Sopenharmony_ci 1461141cc406Sopenharmony_ci for (i = 0; i < sizeof (data); ++i) 1462141cc406Sopenharmony_ci data[i] = i % 0x61; 1463141cc406Sopenharmony_ci 1464141cc406Sopenharmony_ci 1465141cc406Sopenharmony_ci for (i = 0; test_values[i] != -1; ++i) 1466141cc406Sopenharmony_ci { 1467141cc406Sopenharmony_ci if (rt_set_one_register (0x93, test_values[i]) || 1468141cc406Sopenharmony_ci rt_set_sram_page (0x81) || 1469141cc406Sopenharmony_ci rt_write_sram (0x818, data) || 1470141cc406Sopenharmony_ci rt_set_sram_page (0x81) || rt_read_sram (0x818, testbuf)) 1471141cc406Sopenharmony_ci return -1; 1472141cc406Sopenharmony_ci if (!memcmp (testbuf, data, 0x818)) 1473141cc406Sopenharmony_ci { 1474141cc406Sopenharmony_ci sram_access_method = test_values[i]; 1475141cc406Sopenharmony_ci if (r93setting) 1476141cc406Sopenharmony_ci *r93setting = sram_access_method; 1477141cc406Sopenharmony_ci break; 1478141cc406Sopenharmony_ci } 1479141cc406Sopenharmony_ci } 1480141cc406Sopenharmony_ci if (!sram_access_method) 1481141cc406Sopenharmony_ci return -1; 1482141cc406Sopenharmony_ci 1483141cc406Sopenharmony_ci for (i = 0; i < 16; ++i) 1484141cc406Sopenharmony_ci { 1485141cc406Sopenharmony_ci int j; 1486141cc406Sopenharmony_ci char write_data[32]; 1487141cc406Sopenharmony_ci char read_data[32]; 1488141cc406Sopenharmony_ci int pagesetting; 1489141cc406Sopenharmony_ci 1490141cc406Sopenharmony_ci for (j = 0; j < 16; j++) 1491141cc406Sopenharmony_ci { 1492141cc406Sopenharmony_ci write_data[j * 2] = j * 2; 1493141cc406Sopenharmony_ci write_data[j * 2 + 1] = i; 1494141cc406Sopenharmony_ci } 1495141cc406Sopenharmony_ci 1496141cc406Sopenharmony_ci pagesetting = i * 4096; 1497141cc406Sopenharmony_ci 1498141cc406Sopenharmony_ci 1499141cc406Sopenharmony_ci if (rt_set_sram_page (pagesetting) < 0 || 1500141cc406Sopenharmony_ci rt_write_sram (32, write_data) < 0) 1501141cc406Sopenharmony_ci return -1; 1502141cc406Sopenharmony_ci if (i) 1503141cc406Sopenharmony_ci { 1504141cc406Sopenharmony_ci if (rt_set_sram_page (0) < 0 || rt_read_sram (32, read_data) < 0) 1505141cc406Sopenharmony_ci return -1; 1506141cc406Sopenharmony_ci if (!memcmp (read_data, write_data, 32)) 1507141cc406Sopenharmony_ci { 1508141cc406Sopenharmony_ci sram_size = i * 0x20000; 1509141cc406Sopenharmony_ci if (totalbytes) 1510141cc406Sopenharmony_ci *totalbytes = sram_size; 1511141cc406Sopenharmony_ci return 0; 1512141cc406Sopenharmony_ci } 1513141cc406Sopenharmony_ci } 1514141cc406Sopenharmony_ci } 1515141cc406Sopenharmony_ci return -1; 1516141cc406Sopenharmony_ci} 1517141cc406Sopenharmony_ci 1518141cc406Sopenharmony_cistatic int 1519141cc406Sopenharmony_cirt_get_available_bytes (void) 1520141cc406Sopenharmony_ci{ 1521141cc406Sopenharmony_ci unsigned char data[3]; 1522141cc406Sopenharmony_ci 1523141cc406Sopenharmony_ci if (rt_queue_command (RTCMD_BYTESAVAIL, 0, 3, 0, 0, 3, data) < 0 || 1524141cc406Sopenharmony_ci rt_execute_commands () < 0) 1525141cc406Sopenharmony_ci return -1; 1526141cc406Sopenharmony_ci return ((unsigned) data[0]) | 1527141cc406Sopenharmony_ci ((unsigned) data[1] << 8) | ((unsigned) data[2] << 16); 1528141cc406Sopenharmony_ci} 1529141cc406Sopenharmony_ci 1530141cc406Sopenharmony_cistatic int 1531141cc406Sopenharmony_cirt_get_data (int bytes, void *data) 1532141cc406Sopenharmony_ci{ 1533141cc406Sopenharmony_ci while (bytes) 1534141cc406Sopenharmony_ci { 1535141cc406Sopenharmony_ci int bytesnow = bytes; 1536141cc406Sopenharmony_ci 1537141cc406Sopenharmony_ci if (bytesnow > 0xffc0) 1538141cc406Sopenharmony_ci bytesnow = 0xffc0; 1539141cc406Sopenharmony_ci if (rt_queue_command 1540141cc406Sopenharmony_ci (RTCMD_READBYTES, 0, bytesnow, 0, 0, bytesnow, data) < 0 1541141cc406Sopenharmony_ci || rt_execute_commands () < 0) 1542141cc406Sopenharmony_ci return -1; 1543141cc406Sopenharmony_ci bytes -= bytesnow; 1544141cc406Sopenharmony_ci data = (char *) data + bytesnow; 1545141cc406Sopenharmony_ci } 1546141cc406Sopenharmony_ci return 0; 1547141cc406Sopenharmony_ci} 1548141cc406Sopenharmony_ci 1549141cc406Sopenharmony_cistatic int 1550141cc406Sopenharmony_cirt_is_moving (void) 1551141cc406Sopenharmony_ci{ 1552141cc406Sopenharmony_ci char r; 1553141cc406Sopenharmony_ci 1554141cc406Sopenharmony_ci if (rt_read_register_immediate (REG_MOVE_CONTROL_TEST, 1, &r) < 0) 1555141cc406Sopenharmony_ci return -1; 1556141cc406Sopenharmony_ci if (r == 0x08) 1557141cc406Sopenharmony_ci return 1; 1558141cc406Sopenharmony_ci return 0; 1559141cc406Sopenharmony_ci} 1560141cc406Sopenharmony_ci 1561141cc406Sopenharmony_cistatic int 1562141cc406Sopenharmony_cirt_is_rewound (void) 1563141cc406Sopenharmony_ci{ 1564141cc406Sopenharmony_ci char r; 1565141cc406Sopenharmony_ci 1566141cc406Sopenharmony_ci if (rt_read_register_immediate (0x1d, 1, &r) < 0) 1567141cc406Sopenharmony_ci return -1; 1568141cc406Sopenharmony_ci if (r & 0x02) 1569141cc406Sopenharmony_ci return 1; 1570141cc406Sopenharmony_ci return 0; 1571141cc406Sopenharmony_ci} 1572141cc406Sopenharmony_ci 1573141cc406Sopenharmony_cistatic int 1574141cc406Sopenharmony_cirt_set_direction_forwards (unsigned char *regs) 1575141cc406Sopenharmony_ci{ 1576141cc406Sopenharmony_ci regs[0xc6] |= 0x08; 1577141cc406Sopenharmony_ci return 0; 1578141cc406Sopenharmony_ci} 1579141cc406Sopenharmony_ci 1580141cc406Sopenharmony_cistatic int 1581141cc406Sopenharmony_cirt_set_direction_rewind (unsigned char *regs) 1582141cc406Sopenharmony_ci{ 1583141cc406Sopenharmony_ci regs[0xc6] &= 0xf7; 1584141cc406Sopenharmony_ci return 0; 1585141cc406Sopenharmony_ci} 1586141cc406Sopenharmony_ci 1587141cc406Sopenharmony_cistatic int 1588141cc406Sopenharmony_cirt_set_stop_when_rewound (unsigned char *regs, int stop) 1589141cc406Sopenharmony_ci{ 1590141cc406Sopenharmony_ci if (stop) 1591141cc406Sopenharmony_ci regs[0xb2] |= 0x10; 1592141cc406Sopenharmony_ci else 1593141cc406Sopenharmony_ci regs[0xb2] &= 0xef; 1594141cc406Sopenharmony_ci return 0; 1595141cc406Sopenharmony_ci} 1596141cc406Sopenharmony_ci 1597141cc406Sopenharmony_cistatic int 1598141cc406Sopenharmony_cirt_start_moving (void) 1599141cc406Sopenharmony_ci{ 1600141cc406Sopenharmony_ci if (rt_set_one_register (REG_MOVE_CONTROL_TEST, 2) < 0 || 1601141cc406Sopenharmony_ci rt_set_one_register (REG_MOVE_CONTROL_TEST, 2) < 0 || 1602141cc406Sopenharmony_ci rt_set_one_register (REG_MOVE_CONTROL_TEST, 0) < 0 || 1603141cc406Sopenharmony_ci rt_set_one_register (REG_MOVE_CONTROL_TEST, 0) < 0 || 1604141cc406Sopenharmony_ci rt_set_one_register (REG_MOVE_CONTROL_TEST, 8) < 0 || 1605141cc406Sopenharmony_ci rt_set_one_register (REG_MOVE_CONTROL_TEST, 8) < 0) 1606141cc406Sopenharmony_ci return -1; 1607141cc406Sopenharmony_ci return 0; 1608141cc406Sopenharmony_ci} 1609141cc406Sopenharmony_ci 1610141cc406Sopenharmony_cistatic int 1611141cc406Sopenharmony_cirt_stop_moving (void) 1612141cc406Sopenharmony_ci{ 1613141cc406Sopenharmony_ci if (rt_set_one_register (REG_MOVE_CONTROL_TEST, 2) < 0 || 1614141cc406Sopenharmony_ci rt_set_one_register (REG_MOVE_CONTROL_TEST, 2) < 0 || 1615141cc406Sopenharmony_ci rt_set_one_register (REG_MOVE_CONTROL_TEST, 0) < 0 || 1616141cc406Sopenharmony_ci rt_set_one_register (REG_MOVE_CONTROL_TEST, 0) < 0) 1617141cc406Sopenharmony_ci return -1; 1618141cc406Sopenharmony_ci return 0; 1619141cc406Sopenharmony_ci} 1620141cc406Sopenharmony_ci 1621141cc406Sopenharmony_cistatic int 1622141cc406Sopenharmony_cirt_set_powersave_mode (int enable) 1623141cc406Sopenharmony_ci{ 1624141cc406Sopenharmony_ci unsigned char r; 1625141cc406Sopenharmony_ci 1626141cc406Sopenharmony_ci if (rt_read_register_immediate (REG_MOVE_CONTROL_TEST, 1, &r) < 0) 1627141cc406Sopenharmony_ci return -1; 1628141cc406Sopenharmony_ci if (r & 0x04) 1629141cc406Sopenharmony_ci { 1630141cc406Sopenharmony_ci if (enable == 1) 1631141cc406Sopenharmony_ci return 0; 1632141cc406Sopenharmony_ci r &= ~0x04; 1633141cc406Sopenharmony_ci } 1634141cc406Sopenharmony_ci else 1635141cc406Sopenharmony_ci { 1636141cc406Sopenharmony_ci if (enable == 0) 1637141cc406Sopenharmony_ci return 0; 1638141cc406Sopenharmony_ci r |= 0x04; 1639141cc406Sopenharmony_ci } 1640141cc406Sopenharmony_ci if (rt_set_one_register (REG_MOVE_CONTROL_TEST, r) < 0 || 1641141cc406Sopenharmony_ci rt_set_one_register (REG_MOVE_CONTROL_TEST, r) < 0) 1642141cc406Sopenharmony_ci return -1; 1643141cc406Sopenharmony_ci return 0; 1644141cc406Sopenharmony_ci} 1645141cc406Sopenharmony_ci 1646141cc406Sopenharmony_cistatic int 1647141cc406Sopenharmony_cirt_turn_off_lamp (void) 1648141cc406Sopenharmony_ci{ 1649141cc406Sopenharmony_ci return rt_set_one_register (0x3a, 0); 1650141cc406Sopenharmony_ci} 1651141cc406Sopenharmony_ci 1652141cc406Sopenharmony_cistatic int 1653141cc406Sopenharmony_cirt_turn_on_lamp (void) 1654141cc406Sopenharmony_ci{ 1655141cc406Sopenharmony_ci char r3ab[2]; 1656141cc406Sopenharmony_ci char r10; 1657141cc406Sopenharmony_ci char r58; 1658141cc406Sopenharmony_ci 1659141cc406Sopenharmony_ci if (rt_read_register_immediate (0x3a, 1, r3ab) < 0 || 1660141cc406Sopenharmony_ci rt_read_register_immediate (0x10, 1, &r10) < 0 || 1661141cc406Sopenharmony_ci rt_read_register_immediate (0x58, 1, &r58) < 0) 1662141cc406Sopenharmony_ci return -1; 1663141cc406Sopenharmony_ci r3ab[0] |= 0x80; 1664141cc406Sopenharmony_ci r3ab[1] = 0x40; 1665141cc406Sopenharmony_ci r10 |= 0x01; 1666141cc406Sopenharmony_ci r58 &= 0x0f; 1667141cc406Sopenharmony_ci if (rt_set_register_immediate (0x3a, 2, r3ab) < 0 || 1668141cc406Sopenharmony_ci rt_set_one_register (0x10, r10) < 0 || 1669141cc406Sopenharmony_ci rt_set_one_register (0x58, r58) < 0) 1670141cc406Sopenharmony_ci return -1; 1671141cc406Sopenharmony_ci return 0; 1672141cc406Sopenharmony_ci} 1673141cc406Sopenharmony_ci 1674141cc406Sopenharmony_cistatic int 1675141cc406Sopenharmony_cirt_set_value_lsbfirst (unsigned char *regs, 1676141cc406Sopenharmony_ci int firstreg, int totalregs, unsigned value) 1677141cc406Sopenharmony_ci{ 1678141cc406Sopenharmony_ci while (totalregs--) 1679141cc406Sopenharmony_ci { 1680141cc406Sopenharmony_ci regs[firstreg++] = value & 0xff; 1681141cc406Sopenharmony_ci value >>= 8; 1682141cc406Sopenharmony_ci } 1683141cc406Sopenharmony_ci return 0; 1684141cc406Sopenharmony_ci} 1685141cc406Sopenharmony_ci 1686141cc406Sopenharmony_ci#if 0 1687141cc406Sopenharmony_cistatic int 1688141cc406Sopenharmony_cirt_set_value_msbfirst (unsigned char *regs, 1689141cc406Sopenharmony_ci int firstreg, int totalregs, unsigned value) 1690141cc406Sopenharmony_ci{ 1691141cc406Sopenharmony_ci while (totalregs--) 1692141cc406Sopenharmony_ci { 1693141cc406Sopenharmony_ci regs[firstreg + totalregs] = value & 0xff; 1694141cc406Sopenharmony_ci value >>= 8; 1695141cc406Sopenharmony_ci } 1696141cc406Sopenharmony_ci return 0; 1697141cc406Sopenharmony_ci} 1698141cc406Sopenharmony_ci#endif 1699141cc406Sopenharmony_ci 1700141cc406Sopenharmony_cistatic int 1701141cc406Sopenharmony_cirt_set_ccd_shift_clock_multiplier (unsigned char *regs, unsigned value) 1702141cc406Sopenharmony_ci{ 1703141cc406Sopenharmony_ci return rt_set_value_lsbfirst (regs, 0xf0, 3, value); 1704141cc406Sopenharmony_ci} 1705141cc406Sopenharmony_ci 1706141cc406Sopenharmony_cistatic int 1707141cc406Sopenharmony_cirt_set_ccd_clock_reset_interval (unsigned char *regs, unsigned value) 1708141cc406Sopenharmony_ci{ 1709141cc406Sopenharmony_ci return rt_set_value_lsbfirst (regs, 0xf9, 3, value); 1710141cc406Sopenharmony_ci} 1711141cc406Sopenharmony_ci 1712141cc406Sopenharmony_cistatic int 1713141cc406Sopenharmony_cirt_set_ccd_clamp_clock_multiplier (unsigned char *regs, unsigned value) 1714141cc406Sopenharmony_ci{ 1715141cc406Sopenharmony_ci return rt_set_value_lsbfirst (regs, 0xfc, 3, value); 1716141cc406Sopenharmony_ci} 1717141cc406Sopenharmony_ci 1718141cc406Sopenharmony_cistatic int 1719141cc406Sopenharmony_cirt_set_movement_pattern (unsigned char *regs, unsigned value) 1720141cc406Sopenharmony_ci{ 1721141cc406Sopenharmony_ci return rt_set_value_lsbfirst (regs, 0xc0, 3, value); 1722141cc406Sopenharmony_ci} 1723141cc406Sopenharmony_ci 1724141cc406Sopenharmony_cistatic int 1725141cc406Sopenharmony_cirt_set_motor_movement_clock_multiplier (unsigned char *regs, unsigned value) 1726141cc406Sopenharmony_ci{ 1727141cc406Sopenharmony_ci regs[0x40] = (regs[0x40] & ~0xc0) | (value << 6); 1728141cc406Sopenharmony_ci return 0; 1729141cc406Sopenharmony_ci} 1730141cc406Sopenharmony_ci 1731141cc406Sopenharmony_cistatic int 1732141cc406Sopenharmony_cirt_set_motor_type (unsigned char *regs, unsigned value) 1733141cc406Sopenharmony_ci{ 1734141cc406Sopenharmony_ci regs[0xc9] = (regs[0xc9] & 0xf8) | (value & 0x7); 1735141cc406Sopenharmony_ci return 0; 1736141cc406Sopenharmony_ci} 1737141cc406Sopenharmony_ci 1738141cc406Sopenharmony_cistatic int 1739141cc406Sopenharmony_cirt_set_noscan_distance (unsigned char *regs, unsigned value) 1740141cc406Sopenharmony_ci{ 1741141cc406Sopenharmony_ci DBG (10, "Setting distance without scanning to %d\n", value); 1742141cc406Sopenharmony_ci return rt_set_value_lsbfirst (regs, 0x60, 2, value); 1743141cc406Sopenharmony_ci} 1744141cc406Sopenharmony_ci 1745141cc406Sopenharmony_cistatic int 1746141cc406Sopenharmony_cirt_set_total_distance (unsigned char *regs, unsigned value) 1747141cc406Sopenharmony_ci{ 1748141cc406Sopenharmony_ci DBG (10, "Setting total distance to %d\n", value); 1749141cc406Sopenharmony_ci return rt_set_value_lsbfirst (regs, 0x62, 2, value); 1750141cc406Sopenharmony_ci} 1751141cc406Sopenharmony_ci 1752141cc406Sopenharmony_cistatic int 1753141cc406Sopenharmony_cirt_set_scanline_start (unsigned char *regs, unsigned value) 1754141cc406Sopenharmony_ci{ 1755141cc406Sopenharmony_ci return rt_set_value_lsbfirst (regs, 0x66, 2, value); 1756141cc406Sopenharmony_ci} 1757141cc406Sopenharmony_ci 1758141cc406Sopenharmony_cistatic int 1759141cc406Sopenharmony_cirt_set_scanline_end (unsigned char *regs, unsigned value) 1760141cc406Sopenharmony_ci{ 1761141cc406Sopenharmony_ci return rt_set_value_lsbfirst (regs, 0x6c, 2, value); 1762141cc406Sopenharmony_ci} 1763141cc406Sopenharmony_ci 1764141cc406Sopenharmony_cistatic int 1765141cc406Sopenharmony_cirt_set_basic_calibration (unsigned char *regs, 1766141cc406Sopenharmony_ci int redoffset1, 1767141cc406Sopenharmony_ci int redoffset2, 1768141cc406Sopenharmony_ci int redgain, 1769141cc406Sopenharmony_ci int greenoffset1, 1770141cc406Sopenharmony_ci int greenoffset2, 1771141cc406Sopenharmony_ci int greengain, 1772141cc406Sopenharmony_ci int blueoffset1, int blueoffset2, int bluegain) 1773141cc406Sopenharmony_ci{ 1774141cc406Sopenharmony_ci regs[0x02] = redoffset1; 1775141cc406Sopenharmony_ci regs[0x05] = redoffset2; 1776141cc406Sopenharmony_ci regs[0x08] = redgain; 1777141cc406Sopenharmony_ci regs[0x03] = greenoffset1; 1778141cc406Sopenharmony_ci regs[0x06] = greenoffset2; 1779141cc406Sopenharmony_ci regs[0x09] = greengain; 1780141cc406Sopenharmony_ci regs[0x04] = blueoffset1; 1781141cc406Sopenharmony_ci regs[0x07] = blueoffset2; 1782141cc406Sopenharmony_ci regs[0x0a] = bluegain; 1783141cc406Sopenharmony_ci return 0; 1784141cc406Sopenharmony_ci} 1785141cc406Sopenharmony_ci 1786141cc406Sopenharmony_cistatic int 1787141cc406Sopenharmony_cirt_set_calibration_addresses (unsigned char *regs, 1788141cc406Sopenharmony_ci unsigned redaddr, 1789141cc406Sopenharmony_ci unsigned greenaddr, 1790141cc406Sopenharmony_ci unsigned blueaddr, 1791141cc406Sopenharmony_ci unsigned endaddr, 1792141cc406Sopenharmony_ci unsigned width) 1793141cc406Sopenharmony_ci{ 1794141cc406Sopenharmony_ci unsigned endpage = (endaddr + 31) / 32; 1795141cc406Sopenharmony_ci unsigned scanline_pages = ((width + 1) * 3 + 31) / 32; 1796141cc406Sopenharmony_ci 1797141cc406Sopenharmony_ci /* Red, green and blue detailed calibration addresses */ 1798141cc406Sopenharmony_ci 1799141cc406Sopenharmony_ci regs[0x84] = redaddr; 1800141cc406Sopenharmony_ci regs[0x8e] = (regs[0x8e] & 0x0f) | ((redaddr >> 4) & 0xf0); 1801141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0x85, 2, greenaddr); 1802141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0x87, 2, blueaddr); 1803141cc406Sopenharmony_ci 1804141cc406Sopenharmony_ci /* I don't know what the next three are used for, but each buffer commencing 1805141cc406Sopenharmony_ci * at 0x80 and 0x82 needs to hold a full scan line. 1806141cc406Sopenharmony_ci */ 1807141cc406Sopenharmony_ci 1808141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0x80, 2, endpage); 1809141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0x82, 2, endpage + scanline_pages); 1810141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0x89, 2, endpage + scanline_pages * 2); 1811141cc406Sopenharmony_ci 1812141cc406Sopenharmony_ci /* I don't know what this is, but it seems to be a number of pages that can hold 1813141cc406Sopenharmony_ci * 16 complete scan lines, but not calculated as an offset from any other page 1814141cc406Sopenharmony_ci */ 1815141cc406Sopenharmony_ci 1816141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0x51, 2, (48 * (width + 1) + 31) / 32); 1817141cc406Sopenharmony_ci 1818141cc406Sopenharmony_ci /* I don't know what this is either, but this is what the Windows driver does */ 1819141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0x8f, 2, 0x1c00); 1820141cc406Sopenharmony_ci return 0; 1821141cc406Sopenharmony_ci} 1822141cc406Sopenharmony_ci 1823141cc406Sopenharmony_cistatic int 1824141cc406Sopenharmony_cirt_set_lamp_duty_cycle (unsigned char *regs, 1825141cc406Sopenharmony_ci int enable, int frequency, int offduty) 1826141cc406Sopenharmony_ci{ 1827141cc406Sopenharmony_ci if (enable) 1828141cc406Sopenharmony_ci regs[0x3b] |= 0x80; 1829141cc406Sopenharmony_ci else 1830141cc406Sopenharmony_ci regs[0x3b] &= 0x7f; 1831141cc406Sopenharmony_ci 1832141cc406Sopenharmony_ci regs[0x3b] = 1833141cc406Sopenharmony_ci (regs[0x3b] & 0x80) | ((frequency & 0x7) << 4) | (offduty & 0x0f); 1834141cc406Sopenharmony_ci regs[0x3d] = (regs[0x3d] & 0x7f) | ((frequency & 0x8) << 4); 1835141cc406Sopenharmony_ci return 0; 1836141cc406Sopenharmony_ci} 1837141cc406Sopenharmony_ci 1838141cc406Sopenharmony_cistatic int 1839141cc406Sopenharmony_cirt_set_data_feed_on (unsigned char *regs) 1840141cc406Sopenharmony_ci{ 1841141cc406Sopenharmony_ci regs[0xb2] &= ~0x04; 1842141cc406Sopenharmony_ci return 0; 1843141cc406Sopenharmony_ci} 1844141cc406Sopenharmony_ci 1845141cc406Sopenharmony_cistatic int 1846141cc406Sopenharmony_cirt_set_data_feed_off (unsigned char *regs) 1847141cc406Sopenharmony_ci{ 1848141cc406Sopenharmony_ci regs[0xb2] |= 0x04; 1849141cc406Sopenharmony_ci return 0; 1850141cc406Sopenharmony_ci} 1851141cc406Sopenharmony_ci 1852141cc406Sopenharmony_cistatic int 1853141cc406Sopenharmony_cirt_enable_ccd (unsigned char *regs, int enable) 1854141cc406Sopenharmony_ci{ 1855141cc406Sopenharmony_ci if (enable) 1856141cc406Sopenharmony_ci regs[0x00] &= ~0x10; 1857141cc406Sopenharmony_ci else 1858141cc406Sopenharmony_ci regs[0x00] |= 0x10; 1859141cc406Sopenharmony_ci return 0; 1860141cc406Sopenharmony_ci} 1861141cc406Sopenharmony_ci 1862141cc406Sopenharmony_cistatic int 1863141cc406Sopenharmony_cirt_set_cdss (unsigned char *regs, int val1, int val2) 1864141cc406Sopenharmony_ci{ 1865141cc406Sopenharmony_ci regs[0x28] = (regs[0x28] & 0xe0) | (val1 & 0x1f); 1866141cc406Sopenharmony_ci regs[0x2a] = (regs[0x2a] & 0xe0) | (val2 & 0x1f); 1867141cc406Sopenharmony_ci return 0; 1868141cc406Sopenharmony_ci} 1869141cc406Sopenharmony_ci 1870141cc406Sopenharmony_cistatic int 1871141cc406Sopenharmony_cirt_set_cdsc (unsigned char *regs, int val1, int val2) 1872141cc406Sopenharmony_ci{ 1873141cc406Sopenharmony_ci regs[0x29] = (regs[0x29] & 0xe0) | (val1 & 0x1f); 1874141cc406Sopenharmony_ci regs[0x2b] = (regs[0x2b] & 0xe0) | (val2 & 0x1f); 1875141cc406Sopenharmony_ci return 0; 1876141cc406Sopenharmony_ci} 1877141cc406Sopenharmony_ci 1878141cc406Sopenharmony_cistatic int 1879141cc406Sopenharmony_cirt_update_after_setting_cdss2 (unsigned char *regs) 1880141cc406Sopenharmony_ci{ 1881141cc406Sopenharmony_ci int fullcolour = (!(regs[0x2f] & 0xc0) && (regs[0x2f] & 0x04)); 1882141cc406Sopenharmony_ci int value = regs[0x2a] & 0x1f; 1883141cc406Sopenharmony_ci 1884141cc406Sopenharmony_ci regs[0x2a] = (regs[0x2a] & 0xe0) | (value & 0x1f); 1885141cc406Sopenharmony_ci 1886141cc406Sopenharmony_ci if (fullcolour) 1887141cc406Sopenharmony_ci value *= 3; 1888141cc406Sopenharmony_ci if ((regs[0x40] & 0xc0) == 0x40) 1889141cc406Sopenharmony_ci value += 17; 1890141cc406Sopenharmony_ci else 1891141cc406Sopenharmony_ci value += 16; 1892141cc406Sopenharmony_ci 1893141cc406Sopenharmony_ci regs[0x2c] = (regs[0x2c] & 0xe0) | (value % 24); 1894141cc406Sopenharmony_ci regs[0x2d] = (regs[0x2d] & 0xe0) | ((value + 2) % 24); 1895141cc406Sopenharmony_ci return 0; 1896141cc406Sopenharmony_ci} 1897141cc406Sopenharmony_ci 1898141cc406Sopenharmony_cistatic int 1899141cc406Sopenharmony_cirt_set_cph0s (unsigned char *regs, int on) 1900141cc406Sopenharmony_ci{ 1901141cc406Sopenharmony_ci if (on) 1902141cc406Sopenharmony_ci regs[0x2d] |= 0x20; /* 1200dpi horizontal coordinate space */ 1903141cc406Sopenharmony_ci else 1904141cc406Sopenharmony_ci regs[0x2d] &= ~0x20; /* 600dpi horizontal coordinate space */ 1905141cc406Sopenharmony_ci return 0; 1906141cc406Sopenharmony_ci} 1907141cc406Sopenharmony_ci 1908141cc406Sopenharmony_cistatic int 1909141cc406Sopenharmony_cirt_set_cvtr_lm (unsigned char *regs, int val1, int val2, int val3) 1910141cc406Sopenharmony_ci{ 1911141cc406Sopenharmony_ci regs[0x28] = (regs[0x28] & ~0xe0) | (val1 << 5); 1912141cc406Sopenharmony_ci regs[0x29] = (regs[0x29] & ~0xe0) | (val2 << 5); 1913141cc406Sopenharmony_ci regs[0x2a] = (regs[0x2a] & ~0xe0) | (val3 << 5); 1914141cc406Sopenharmony_ci return 0; 1915141cc406Sopenharmony_ci} 1916141cc406Sopenharmony_ci 1917141cc406Sopenharmony_cistatic int 1918141cc406Sopenharmony_cirt_set_cvtr_mpt (unsigned char *regs, int val1, int val2, int val3) 1919141cc406Sopenharmony_ci{ 1920141cc406Sopenharmony_ci regs[0x3c] = (val1 & 0x0f) | (val2 << 4); 1921141cc406Sopenharmony_ci regs[0x3d] = (regs[0x3d] & 0xf0) | (val3 & 0x0f); 1922141cc406Sopenharmony_ci return 0; 1923141cc406Sopenharmony_ci} 1924141cc406Sopenharmony_ci 1925141cc406Sopenharmony_cistatic int 1926141cc406Sopenharmony_cirt_set_cvtr_wparams (unsigned char *regs, 1927141cc406Sopenharmony_ci unsigned fpw, unsigned bpw, unsigned w) 1928141cc406Sopenharmony_ci{ 1929141cc406Sopenharmony_ci regs[0x31] = (w & 0x0f) | ((bpw << 4) & 0x30) | (fpw << 6); 1930141cc406Sopenharmony_ci return 0; 1931141cc406Sopenharmony_ci} 1932141cc406Sopenharmony_ci 1933141cc406Sopenharmony_cistatic int 1934141cc406Sopenharmony_cirt_enable_movement (unsigned char *regs, int enable) 1935141cc406Sopenharmony_ci{ 1936141cc406Sopenharmony_ci if (enable) 1937141cc406Sopenharmony_ci regs[0xc3] |= 0x80; 1938141cc406Sopenharmony_ci else 1939141cc406Sopenharmony_ci regs[0xc3] &= ~0x80; 1940141cc406Sopenharmony_ci return 0; 1941141cc406Sopenharmony_ci} 1942141cc406Sopenharmony_ci 1943141cc406Sopenharmony_cistatic int 1944141cc406Sopenharmony_cirt_set_scan_frequency (unsigned char *regs, int frequency) 1945141cc406Sopenharmony_ci{ 1946141cc406Sopenharmony_ci regs[0x64] = (regs[0x64] & 0xf0) | (frequency & 0x0f); 1947141cc406Sopenharmony_ci return 0; 1948141cc406Sopenharmony_ci} 1949141cc406Sopenharmony_ci 1950141cc406Sopenharmony_cistatic int 1951141cc406Sopenharmony_cirt_set_merge_channels (unsigned char *regs, int on) 1952141cc406Sopenharmony_ci{ 1953141cc406Sopenharmony_ci /* RGBRGB instead of RRRRR...GGGGG...BBBB */ 1954141cc406Sopenharmony_ci regs[0x2f] &= ~0x14; 1955141cc406Sopenharmony_ci regs[0x2f] |= on ? 0x04 : 0x10; 1956141cc406Sopenharmony_ci return 0; 1957141cc406Sopenharmony_ci} 1958141cc406Sopenharmony_ci 1959141cc406Sopenharmony_cistatic int 1960141cc406Sopenharmony_cirt_set_channel (unsigned char *regs, int channel) 1961141cc406Sopenharmony_ci{ 1962141cc406Sopenharmony_ci regs[0x2f] = (regs[0x2f] & ~0xc0) | (channel << 6); 1963141cc406Sopenharmony_ci return 0; 1964141cc406Sopenharmony_ci} 1965141cc406Sopenharmony_ci 1966141cc406Sopenharmony_cistatic int 1967141cc406Sopenharmony_cirt_set_single_channel_scanning (unsigned char *regs, int on) 1968141cc406Sopenharmony_ci{ 1969141cc406Sopenharmony_ci if (on) 1970141cc406Sopenharmony_ci regs[0x2f] |= 0x20; 1971141cc406Sopenharmony_ci else 1972141cc406Sopenharmony_ci regs[0x2f] &= ~0x20; 1973141cc406Sopenharmony_ci return 0; 1974141cc406Sopenharmony_ci} 1975141cc406Sopenharmony_ci 1976141cc406Sopenharmony_cistatic int 1977141cc406Sopenharmony_cirt_set_colour_mode (unsigned char *regs, int on) 1978141cc406Sopenharmony_ci{ 1979141cc406Sopenharmony_ci if (on) 1980141cc406Sopenharmony_ci regs[0x2f] |= 0x02; 1981141cc406Sopenharmony_ci else 1982141cc406Sopenharmony_ci regs[0x2f] &= ~0x02; 1983141cc406Sopenharmony_ci return 0; 1984141cc406Sopenharmony_ci} 1985141cc406Sopenharmony_ci 1986141cc406Sopenharmony_cistatic int 1987141cc406Sopenharmony_cirt_set_horizontal_resolution (unsigned char *regs, int resolution) 1988141cc406Sopenharmony_ci{ 1989141cc406Sopenharmony_ci int base_resolution = 300; 1990141cc406Sopenharmony_ci 1991141cc406Sopenharmony_ci if (regs[0x2d] & 0x20) 1992141cc406Sopenharmony_ci base_resolution *= 2; 1993141cc406Sopenharmony_ci if (regs[0xd3] & 0x08) 1994141cc406Sopenharmony_ci base_resolution *= 2; 1995141cc406Sopenharmony_ci regs[0x7a] = base_resolution / resolution; 1996141cc406Sopenharmony_ci return 0; 1997141cc406Sopenharmony_ci} 1998141cc406Sopenharmony_ci 1999141cc406Sopenharmony_cistatic int 2000141cc406Sopenharmony_cirt_set_last_sram_page (unsigned char *regs, int pagenum) 2001141cc406Sopenharmony_ci{ 2002141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0x8b, 2, pagenum); 2003141cc406Sopenharmony_ci return 0; 2004141cc406Sopenharmony_ci} 2005141cc406Sopenharmony_ci 2006141cc406Sopenharmony_cistatic int 2007141cc406Sopenharmony_cirt_set_step_size (unsigned char *regs, int stepsize) 2008141cc406Sopenharmony_ci{ 2009141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0xe2, 2, stepsize); 2010141cc406Sopenharmony_ci rt_set_value_lsbfirst (regs, 0xe0, 2, 0); 2011141cc406Sopenharmony_ci return 0; 2012141cc406Sopenharmony_ci} 2013141cc406Sopenharmony_ci 2014141cc406Sopenharmony_cistatic int 2015141cc406Sopenharmony_cirt_set_all_registers (void const *regs_) 2016141cc406Sopenharmony_ci{ 2017141cc406Sopenharmony_ci char regs[255]; 2018141cc406Sopenharmony_ci 2019141cc406Sopenharmony_ci memcpy (regs, regs_, 255); 2020141cc406Sopenharmony_ci regs[0x32] &= ~0x40; 2021141cc406Sopenharmony_ci 2022141cc406Sopenharmony_ci if (rt_set_one_register (0x32, regs[0x32]) < 0 || 2023141cc406Sopenharmony_ci rt_set_register_immediate (0, 255, regs) < 0 || 2024141cc406Sopenharmony_ci rt_set_one_register (0x32, regs[0x32] | 0x40) < 0) 2025141cc406Sopenharmony_ci return -1; 2026141cc406Sopenharmony_ci return 0; 2027141cc406Sopenharmony_ci} 2028141cc406Sopenharmony_ci 2029141cc406Sopenharmony_cistatic int 2030141cc406Sopenharmony_cirt_adjust_misc_registers (unsigned char *regs) 2031141cc406Sopenharmony_ci{ 2032141cc406Sopenharmony_ci /* Mostly unknown purposes - probably no need to adjust */ 2033141cc406Sopenharmony_ci regs[0xc6] = (regs[0xc6] & 0x0f) | 0x20; /* Purpose unknown - appears to do nothing */ 2034141cc406Sopenharmony_ci regs[0x2e] = 0x86; /* ???? - Always has this value */ 2035141cc406Sopenharmony_ci regs[0x30] = 2; /* CCPL = 1 */ 2036141cc406Sopenharmony_ci regs[0xc9] |= 0x38; /* Doesn't have any obvious effect, but the Windows driver does this */ 2037141cc406Sopenharmony_ci return 0; 2038141cc406Sopenharmony_ci} 2039141cc406Sopenharmony_ci 2040141cc406Sopenharmony_ci 2041141cc406Sopenharmony_ci#define NVR_MAX_ADDRESS_SIZE 11 2042141cc406Sopenharmony_ci#define NVR_MAX_OPCODE_SIZE 3 2043141cc406Sopenharmony_ci#define NVR_DATA_SIZE 8 2044141cc406Sopenharmony_ci#define NVR_MAX_COMMAND_SIZE ((NVR_MAX_ADDRESS_SIZE + \ 2045141cc406Sopenharmony_ci NVR_MAX_OPCODE_SIZE + \ 2046141cc406Sopenharmony_ci NVR_DATA_SIZE) * 2 + 1) 2047141cc406Sopenharmony_ci 2048141cc406Sopenharmony_cistatic int 2049141cc406Sopenharmony_cirt_nvram_enable_controller (int enable) 2050141cc406Sopenharmony_ci{ 2051141cc406Sopenharmony_ci unsigned char r; 2052141cc406Sopenharmony_ci 2053141cc406Sopenharmony_ci if (rt_read_register_immediate (0x1d, 1, &r) < 0) 2054141cc406Sopenharmony_ci return -1; 2055141cc406Sopenharmony_ci if (enable) 2056141cc406Sopenharmony_ci r |= 1; 2057141cc406Sopenharmony_ci else 2058141cc406Sopenharmony_ci r &= ~1; 2059141cc406Sopenharmony_ci return rt_set_one_register (0x1d, r); 2060141cc406Sopenharmony_ci 2061141cc406Sopenharmony_ci} 2062141cc406Sopenharmony_ci 2063141cc406Sopenharmony_cistatic int 2064141cc406Sopenharmony_cirt_nvram_init_command (void) 2065141cc406Sopenharmony_ci{ 2066141cc406Sopenharmony_ci unsigned char regs[13]; 2067141cc406Sopenharmony_ci 2068141cc406Sopenharmony_ci if (rt_read_register_immediate (0x10, 13, regs) < 0) 2069141cc406Sopenharmony_ci return -1; 2070141cc406Sopenharmony_ci regs[2] |= 0xf0; 2071141cc406Sopenharmony_ci regs[4] = (regs[4] & 0x1f) | 0x60; 2072141cc406Sopenharmony_ci return rt_set_register_immediate (0x10, 13, regs); 2073141cc406Sopenharmony_ci} 2074141cc406Sopenharmony_ci 2075141cc406Sopenharmony_cistatic int 2076141cc406Sopenharmony_cirt_nvram_init_stdvars (int block, int *addrbits, unsigned char *basereg) 2077141cc406Sopenharmony_ci{ 2078141cc406Sopenharmony_ci int bitsneeded; 2079141cc406Sopenharmony_ci int capacity; 2080141cc406Sopenharmony_ci 2081141cc406Sopenharmony_ci switch (block) 2082141cc406Sopenharmony_ci { 2083141cc406Sopenharmony_ci case 0: 2084141cc406Sopenharmony_ci bitsneeded = 7; 2085141cc406Sopenharmony_ci break; 2086141cc406Sopenharmony_ci 2087141cc406Sopenharmony_ci case 1: 2088141cc406Sopenharmony_ci bitsneeded = 9; 2089141cc406Sopenharmony_ci break; 2090141cc406Sopenharmony_ci 2091141cc406Sopenharmony_ci case 2: 2092141cc406Sopenharmony_ci bitsneeded = 11; 2093141cc406Sopenharmony_ci break; 2094141cc406Sopenharmony_ci 2095141cc406Sopenharmony_ci default: 2096141cc406Sopenharmony_ci bitsneeded = 0; 2097141cc406Sopenharmony_ci capacity = 1; 2098141cc406Sopenharmony_ci while (capacity < block) 2099141cc406Sopenharmony_ci capacity <<= 1, ++bitsneeded; 2100141cc406Sopenharmony_ci break; 2101141cc406Sopenharmony_ci } 2102141cc406Sopenharmony_ci 2103141cc406Sopenharmony_ci *addrbits = bitsneeded; 2104141cc406Sopenharmony_ci 2105141cc406Sopenharmony_ci if (rt_read_register_immediate (0x10, 1, basereg) < 0) 2106141cc406Sopenharmony_ci return -1; 2107141cc406Sopenharmony_ci 2108141cc406Sopenharmony_ci *basereg &= ~0x60; 2109141cc406Sopenharmony_ci return 0; 2110141cc406Sopenharmony_ci} 2111141cc406Sopenharmony_ci 2112141cc406Sopenharmony_cistatic void 2113141cc406Sopenharmony_cirt_nvram_set_half_bit (unsigned char *buffer, 2114141cc406Sopenharmony_ci int value, unsigned char stdbits, int whichhalf) 2115141cc406Sopenharmony_ci{ 2116141cc406Sopenharmony_ci *buffer = stdbits | (value ? 0x40 : 0) | (whichhalf ? 0x20 : 0); 2117141cc406Sopenharmony_ci} 2118141cc406Sopenharmony_ci 2119141cc406Sopenharmony_cistatic void 2120141cc406Sopenharmony_cirt_nvram_set_command_bit (unsigned char *buffer, 2121141cc406Sopenharmony_ci int value, unsigned char stdbits) 2122141cc406Sopenharmony_ci{ 2123141cc406Sopenharmony_ci rt_nvram_set_half_bit (buffer, value, stdbits, 0); 2124141cc406Sopenharmony_ci rt_nvram_set_half_bit (buffer + 1, value, stdbits, 1); 2125141cc406Sopenharmony_ci} 2126141cc406Sopenharmony_ci 2127141cc406Sopenharmony_cistatic void 2128141cc406Sopenharmony_cirt_nvram_set_addressing_bits (unsigned char *buffer, 2129141cc406Sopenharmony_ci int location, 2130141cc406Sopenharmony_ci int addressingbits, unsigned char stdbits) 2131141cc406Sopenharmony_ci{ 2132141cc406Sopenharmony_ci int currentbit = 1 << (addressingbits - 1); 2133141cc406Sopenharmony_ci 2134141cc406Sopenharmony_ci while (addressingbits--) 2135141cc406Sopenharmony_ci { 2136141cc406Sopenharmony_ci rt_nvram_set_command_bit (buffer, 2137141cc406Sopenharmony_ci (location & currentbit) ? 1 : 0, stdbits); 2138141cc406Sopenharmony_ci buffer += 2; 2139141cc406Sopenharmony_ci currentbit >>= 1; 2140141cc406Sopenharmony_ci } 2141141cc406Sopenharmony_ci} 2142141cc406Sopenharmony_ci 2143141cc406Sopenharmony_ci#if 0 2144141cc406Sopenharmony_cistatic int 2145141cc406Sopenharmony_cirt_nvram_enable_write (int addressingbits, int enable, unsigned char stdbits) 2146141cc406Sopenharmony_ci{ 2147141cc406Sopenharmony_ci unsigned char cmdbuffer[NVR_MAX_COMMAND_SIZE]; 2148141cc406Sopenharmony_ci int cmdsize = 6 + addressingbits * 2; 2149141cc406Sopenharmony_ci 2150141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer, 1, stdbits); 2151141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer + 2, 0, stdbits); 2152141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer + 4, 0, stdbits); 2153141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer + 6, enable, stdbits); 2154141cc406Sopenharmony_ci if (addressingbits > 1) 2155141cc406Sopenharmony_ci rt_nvram_set_addressing_bits (cmdbuffer + 8, 0, addressingbits - 1, 2156141cc406Sopenharmony_ci stdbits); 2157141cc406Sopenharmony_ci 2158141cc406Sopenharmony_ci if (rt_nvram_enable_controller (1) < 0 || 2159141cc406Sopenharmony_ci rt_send_command_immediate (RTCMD_NVRAMCONTROL, 0, cmdsize, cmdsize, 2160141cc406Sopenharmony_ci cmdbuffer, 0, 0) < 0 2161141cc406Sopenharmony_ci || rt_nvram_enable_controller (0) < 0) 2162141cc406Sopenharmony_ci { 2163141cc406Sopenharmony_ci return -1; 2164141cc406Sopenharmony_ci } 2165141cc406Sopenharmony_ci return 0; 2166141cc406Sopenharmony_ci} 2167141cc406Sopenharmony_ci 2168141cc406Sopenharmony_cistatic int 2169141cc406Sopenharmony_cirt_nvram_write (int block, int location, char const *data, int bytes) 2170141cc406Sopenharmony_ci{ 2171141cc406Sopenharmony_ci int addressingbits; 2172141cc406Sopenharmony_ci unsigned char stdbits; 2173141cc406Sopenharmony_ci unsigned char cmdbuffer[NVR_MAX_COMMAND_SIZE]; 2174141cc406Sopenharmony_ci unsigned char *address_bits; 2175141cc406Sopenharmony_ci unsigned char *data_bits; 2176141cc406Sopenharmony_ci int cmdsize; 2177141cc406Sopenharmony_ci 2178141cc406Sopenharmony_ci /* This routine doesn't appear to work, but I can't see anything wrong with it */ 2179141cc406Sopenharmony_ci if (rt_nvram_init_stdvars (block, &addressingbits, &stdbits) < 0) 2180141cc406Sopenharmony_ci return -1; 2181141cc406Sopenharmony_ci 2182141cc406Sopenharmony_ci cmdsize = (addressingbits + 8) * 2 + 6; 2183141cc406Sopenharmony_ci address_bits = cmdbuffer + 6; 2184141cc406Sopenharmony_ci data_bits = address_bits + (addressingbits * 2); 2185141cc406Sopenharmony_ci 2186141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer, 1, stdbits); 2187141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer + 2, 0, stdbits); 2188141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer + 4, 1, stdbits); 2189141cc406Sopenharmony_ci 2190141cc406Sopenharmony_ci if (rt_nvram_init_command () < 0 || 2191141cc406Sopenharmony_ci rt_nvram_enable_write (addressingbits, 1, stdbits) < 0) 2192141cc406Sopenharmony_ci return -1; 2193141cc406Sopenharmony_ci 2194141cc406Sopenharmony_ci while (bytes--) 2195141cc406Sopenharmony_ci { 2196141cc406Sopenharmony_ci int i; 2197141cc406Sopenharmony_ci 2198141cc406Sopenharmony_ci rt_nvram_set_addressing_bits (address_bits, location, addressingbits, 2199141cc406Sopenharmony_ci stdbits); 2200141cc406Sopenharmony_ci rt_nvram_set_addressing_bits (data_bits, *data++, 8, stdbits); 2201141cc406Sopenharmony_ci 2202141cc406Sopenharmony_ci if (rt_nvram_enable_controller (1) < 0 || 2203141cc406Sopenharmony_ci rt_send_command_immediate (RTCMD_NVRAMCONTROL, 0, cmdsize, cmdsize, 2204141cc406Sopenharmony_ci cmdbuffer, 0, 0) < 0 2205141cc406Sopenharmony_ci || rt_nvram_enable_controller (0) < 0) 2206141cc406Sopenharmony_ci return -1; 2207141cc406Sopenharmony_ci 2208141cc406Sopenharmony_ci if (rt_nvram_enable_controller (1) < 0) 2209141cc406Sopenharmony_ci return -1; 2210141cc406Sopenharmony_ci for (i = 0; i < cmdsize; ++i) 2211141cc406Sopenharmony_ci { 2212141cc406Sopenharmony_ci unsigned char r; 2213141cc406Sopenharmony_ci unsigned char cmd; 2214141cc406Sopenharmony_ci 2215141cc406Sopenharmony_ci rt_nvram_set_half_bit (&cmd, 0, stdbits, i & 1); 2216141cc406Sopenharmony_ci if (rt_send_command_immediate 2217141cc406Sopenharmony_ci (RTCMD_NVRAMCONTROL, 0, 1, 1, &cmd, 0, 0) < 0 2218141cc406Sopenharmony_ci || rt_read_register_immediate (0x10, 1, &r) < 0) 2219141cc406Sopenharmony_ci { 2220141cc406Sopenharmony_ci return -1; 2221141cc406Sopenharmony_ci } 2222141cc406Sopenharmony_ci else if (r & 0x80) 2223141cc406Sopenharmony_ci { 2224141cc406Sopenharmony_ci break; 2225141cc406Sopenharmony_ci } 2226141cc406Sopenharmony_ci } 2227141cc406Sopenharmony_ci if (rt_nvram_enable_controller (0) < 0) 2228141cc406Sopenharmony_ci return -1; 2229141cc406Sopenharmony_ci 2230141cc406Sopenharmony_ci ++location; 2231141cc406Sopenharmony_ci } 2232141cc406Sopenharmony_ci 2233141cc406Sopenharmony_ci if (rt_nvram_enable_write (addressingbits, 0, stdbits) < 0) 2234141cc406Sopenharmony_ci return -1; 2235141cc406Sopenharmony_ci return 0; 2236141cc406Sopenharmony_ci} 2237141cc406Sopenharmony_ci#endif 2238141cc406Sopenharmony_ci 2239141cc406Sopenharmony_cistatic int 2240141cc406Sopenharmony_cirt_nvram_read (int block, int location, unsigned char *data, int bytes) 2241141cc406Sopenharmony_ci{ 2242141cc406Sopenharmony_ci int addressingbits; 2243141cc406Sopenharmony_ci unsigned char stdbits; 2244141cc406Sopenharmony_ci unsigned char cmdbuffer[NVR_MAX_COMMAND_SIZE]; 2245141cc406Sopenharmony_ci unsigned char *address_bits; 2246141cc406Sopenharmony_ci unsigned char readbit_command[2]; 2247141cc406Sopenharmony_ci int cmdsize; 2248141cc406Sopenharmony_ci 2249141cc406Sopenharmony_ci if (rt_nvram_init_stdvars (block, &addressingbits, &stdbits) < 0) 2250141cc406Sopenharmony_ci return -1; 2251141cc406Sopenharmony_ci 2252141cc406Sopenharmony_ci cmdsize = addressingbits * 2 + 7; 2253141cc406Sopenharmony_ci address_bits = cmdbuffer + 6; 2254141cc406Sopenharmony_ci 2255141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer, 1, stdbits); 2256141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer + 2, 1, stdbits); 2257141cc406Sopenharmony_ci rt_nvram_set_command_bit (cmdbuffer + 4, 0, stdbits); 2258141cc406Sopenharmony_ci rt_nvram_set_half_bit (cmdbuffer + cmdsize - 1, 0, stdbits, 0); 2259141cc406Sopenharmony_ci 2260141cc406Sopenharmony_ci rt_nvram_set_half_bit (readbit_command, 0, stdbits, 1); 2261141cc406Sopenharmony_ci rt_nvram_set_half_bit (readbit_command + 1, 0, stdbits, 0); 2262141cc406Sopenharmony_ci 2263141cc406Sopenharmony_ci if (rt_nvram_init_command () < 0) 2264141cc406Sopenharmony_ci return -1; 2265141cc406Sopenharmony_ci 2266141cc406Sopenharmony_ci while (bytes--) 2267141cc406Sopenharmony_ci { 2268141cc406Sopenharmony_ci char c = 0; 2269141cc406Sopenharmony_ci unsigned char r; 2270141cc406Sopenharmony_ci int i; 2271141cc406Sopenharmony_ci 2272141cc406Sopenharmony_ci rt_nvram_set_addressing_bits (address_bits, location, addressingbits, 2273141cc406Sopenharmony_ci stdbits); 2274141cc406Sopenharmony_ci 2275141cc406Sopenharmony_ci if (rt_nvram_enable_controller (1) < 0 || 2276141cc406Sopenharmony_ci rt_send_command_immediate (RTCMD_NVRAMCONTROL, 0x1d, cmdsize, 2277141cc406Sopenharmony_ci cmdsize, cmdbuffer, 0, 0) < 0) 2278141cc406Sopenharmony_ci return -1; 2279141cc406Sopenharmony_ci 2280141cc406Sopenharmony_ci for (i = 0; i < 8; ++i) 2281141cc406Sopenharmony_ci { 2282141cc406Sopenharmony_ci c <<= 1; 2283141cc406Sopenharmony_ci 2284141cc406Sopenharmony_ci if (rt_send_command_immediate 2285141cc406Sopenharmony_ci (RTCMD_NVRAMCONTROL, 0x1d, 2, 2, readbit_command, 0, 0) < 0 2286141cc406Sopenharmony_ci || rt_read_register_immediate (0x10, 1, &r) < 0) 2287141cc406Sopenharmony_ci return -1; 2288141cc406Sopenharmony_ci if (r & 0x80) 2289141cc406Sopenharmony_ci c |= 1; 2290141cc406Sopenharmony_ci } 2291141cc406Sopenharmony_ci if (rt_nvram_enable_controller (0) < 0) 2292141cc406Sopenharmony_ci return -1; 2293141cc406Sopenharmony_ci 2294141cc406Sopenharmony_ci *data++ = c; 2295141cc406Sopenharmony_ci ++location; 2296141cc406Sopenharmony_ci } 2297141cc406Sopenharmony_ci return 0; 2298141cc406Sopenharmony_ci} 2299141cc406Sopenharmony_ci 2300141cc406Sopenharmony_ci/* This is what we want as the initial registers, not what they 2301141cc406Sopenharmony_ci * are at power on time. In particular 13 bytes at 0x10 are 2302141cc406Sopenharmony_ci * different, and the byte at 0x94 is different. 2303141cc406Sopenharmony_ci */ 2304141cc406Sopenharmony_cistatic unsigned char initial_regs[] = { 2305141cc406Sopenharmony_ci /* 0x00 */ 0xf5, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2306141cc406Sopenharmony_ci /* 0x08 */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 2307141cc406Sopenharmony_ci /* 0x10 */ 0x81, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 2308141cc406Sopenharmony_ci /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 2309141cc406Sopenharmony_ci /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2310141cc406Sopenharmony_ci /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x19, 2311141cc406Sopenharmony_ci /* 0x30 */ 0xd0, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2312141cc406Sopenharmony_ci /* 0x38 */ 0x00, 0x00, 0xa0, 0x37, 0xff, 0x0f, 0x00, 0x00, 2313141cc406Sopenharmony_ci /* 0x40 */ 0x80, 0x00, 0x00, 0x00, 0x8c, 0x76, 0x00, 0x00, 2314141cc406Sopenharmony_ci /* 0x48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2315141cc406Sopenharmony_ci /* 0x50 */ 0x20, 0xbc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 2316141cc406Sopenharmony_ci /* 0x58 */ 0x1d, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 2317141cc406Sopenharmony_ci /* 0x60 */ 0x5e, 0xea, 0x5f, 0xea, 0x00, 0x80, 0x64, 0x00, 2318141cc406Sopenharmony_ci /* 0x68 */ 0x00, 0x00, 0x00, 0x00, 0x84, 0x04, 0x00, 0x00, 2319141cc406Sopenharmony_ci /* 0x70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2320141cc406Sopenharmony_ci /* 0x78 */ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2321141cc406Sopenharmony_ci /* 0x80 */ 0x0f, 0x02, 0x4b, 0x02, 0x00, 0xec, 0x19, 0xd8, 2322141cc406Sopenharmony_ci /* 0x88 */ 0x2d, 0x87, 0x02, 0xff, 0x3f, 0x78, 0x60, 0x00, 2323141cc406Sopenharmony_ci /* 0x90 */ 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 2324141cc406Sopenharmony_ci /* 0x98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2325141cc406Sopenharmony_ci /* 0xa0 */ 0x00, 0x00, 0x00, 0x0c, 0x27, 0x64, 0x00, 0x00, 2326141cc406Sopenharmony_ci /* 0xa8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2327141cc406Sopenharmony_ci /* 0xb0 */ 0x12, 0x08, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 2328141cc406Sopenharmony_ci /* 0xb8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2329141cc406Sopenharmony_ci /* 0xc0 */ 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 2330141cc406Sopenharmony_ci /* 0xc8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2331141cc406Sopenharmony_ci /* 0xd0 */ 0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 2332141cc406Sopenharmony_ci /* 0xd8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2333141cc406Sopenharmony_ci /* 0xe0 */ 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 2334141cc406Sopenharmony_ci /* 0xe8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2335141cc406Sopenharmony_ci /* 0xf0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2336141cc406Sopenharmony_ci /* 0xf8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 2337141cc406Sopenharmony_ci}; 2338141cc406Sopenharmony_ci 2339141cc406Sopenharmony_ci#define RT_NORMAL_TG 0 2340141cc406Sopenharmony_ci#define RT_DOUBLE_TG 1 2341141cc406Sopenharmony_ci#define RT_TRIPLE_TG 2 2342141cc406Sopenharmony_ci#define RT_DDOUBLE_TG 3 2343141cc406Sopenharmony_ci#define RT_300_TG 4 2344141cc406Sopenharmony_ci#define RT_150_TG 5 2345141cc406Sopenharmony_ci#define RT_TEST_TG 6 2346141cc406Sopenharmony_cistatic struct tg_info__ 2347141cc406Sopenharmony_ci{ 2348141cc406Sopenharmony_ci int tg_cph0p; 2349141cc406Sopenharmony_ci int tg_crsp; 2350141cc406Sopenharmony_ci int tg_cclpp; 2351141cc406Sopenharmony_ci int tg_cph0s; 2352141cc406Sopenharmony_ci int tg_cdss1; 2353141cc406Sopenharmony_ci int tg_cdsc1; 2354141cc406Sopenharmony_ci int tg_cdss2; 2355141cc406Sopenharmony_ci int tg_cdsc2; 2356141cc406Sopenharmony_ci} tg_info[] = 2357141cc406Sopenharmony_ci{ 2358141cc406Sopenharmony_ci /* CPH CCD Shifting Clock 2359141cc406Sopenharmony_ci * 0P ??? Perhaps CCD rising edge position 2360141cc406Sopenharmony_ci * 0S ??? 2361141cc406Sopenharmony_ci * CRS Reset CCD Clock 2362141cc406Sopenharmony_ci * P ??? Perhaps CCD falling edge position 2363141cc406Sopenharmony_ci * CCLP CCD Clamp Clock 2364141cc406Sopenharmony_ci * P ??? 2365141cc406Sopenharmony_ci * CDS ??? 2366141cc406Sopenharmony_ci * S1 ??? 2367141cc406Sopenharmony_ci * S2 ??? 2368141cc406Sopenharmony_ci * C1 ??? 2369141cc406Sopenharmony_ci * C2 ??? 2370141cc406Sopenharmony_ci */ 2371141cc406Sopenharmony_ci /*CPH0P CRSP CCLPP CPH0S CDSS1 CDSC1 CDSS2 CDSC2 */ 2372141cc406Sopenharmony_ci { 2373141cc406Sopenharmony_ci 0x01FFE0, 0x3c0000, 0x003000, 1, 0xb, 0xd, 0x00, 0x01}, /* NORMAL */ 2374141cc406Sopenharmony_ci { 2375141cc406Sopenharmony_ci 0x7ff800, 0xf00000, 0x01c000, 0, 0xb, 0xc, 0x14, 0x15}, /* DOUBLE */ 2376141cc406Sopenharmony_ci { 2377141cc406Sopenharmony_ci 0x033fcc, 0x300000, 0x060000, 1, 0x8, 0xa, 0x00, 0x01}, /* TRIPLE */ 2378141cc406Sopenharmony_ci { 2379141cc406Sopenharmony_ci 0x028028, 0x300000, 0x060000, 1, 0x8, 0xa, 0x00, 0x01}, /* DDOUBLE */ 2380141cc406Sopenharmony_ci { 2381141cc406Sopenharmony_ci 0x7ff800, 0x030000, 0x060000, 0, 0xa, 0xc, 0x17, 0x01}, /* 300 */ 2382141cc406Sopenharmony_ci { 2383141cc406Sopenharmony_ci 0x7fc700, 0x030000, 0x060000, 0, 0x7, 0x9, 0x17, 0x01}, /* 150 */ 2384141cc406Sopenharmony_ci { 2385141cc406Sopenharmony_ci 0x7ff800, 0x300000, 0x060000, 0, 0xa, 0xc, 0x17, 0x01}, /* TEST */ 2386141cc406Sopenharmony_ci}; 2387141cc406Sopenharmony_ci 2388141cc406Sopenharmony_cistruct resolution_parameters 2389141cc406Sopenharmony_ci{ 2390141cc406Sopenharmony_ci unsigned resolution; 2391141cc406Sopenharmony_ci int reg_39_value; 2392141cc406Sopenharmony_ci int reg_c3_value; 2393141cc406Sopenharmony_ci int reg_c6_value; 2394141cc406Sopenharmony_ci int scan_frequency; 2395141cc406Sopenharmony_ci int cph0s; 2396141cc406Sopenharmony_ci int red_green_offset; 2397141cc406Sopenharmony_ci int green_blue_offset; 2398141cc406Sopenharmony_ci int intra_channel_offset; 2399141cc406Sopenharmony_ci int motor_movement_clock_multiplier; 2400141cc406Sopenharmony_ci int d3_bit_3_value; 2401141cc406Sopenharmony_ci int tg; 2402141cc406Sopenharmony_ci int step_size; 2403141cc406Sopenharmony_ci}; 2404141cc406Sopenharmony_ci 2405141cc406Sopenharmony_ci/* The TG value sets seem to affect the exposure time: 2406141cc406Sopenharmony_ci * At 200dpi: 2407141cc406Sopenharmony_ci * NORMAL gets higher values than DOUBLE 2408141cc406Sopenharmony_ci * DDOUBLE gives a crazy spike in the data 2409141cc406Sopenharmony_ci * TRIPLE gives a black result 2410141cc406Sopenharmony_ci * TEST gives a black result 2411141cc406Sopenharmony_ci * 300 gives a black result 2412141cc406Sopenharmony_ci * 150 gives a black result 2413141cc406Sopenharmony_ci */ 2414141cc406Sopenharmony_ci 2415141cc406Sopenharmony_cistatic struct resolution_parameters resparms[] = { 2416141cc406Sopenharmony_ci /* Acceptable values for stepsz are: 2417141cc406Sopenharmony_ci * 0x157b 0xabd, 0x55e, 0x2af, 0x157, 0xab, 0x55 2418141cc406Sopenharmony_ci */ 2419141cc406Sopenharmony_ci /* My values - all work */ 2420141cc406Sopenharmony_ci /*res r39 rC3 rC6 freq cph0s rgo gbo intra mmcm d3 tg stepsz */ 2421141cc406Sopenharmony_ci {1200, 3, 6, 4, 2, 1, 22, 22, 4, 2, 1, RT_NORMAL_TG, 0x157b}, 2422141cc406Sopenharmony_ci {600, 15, 6, 4, 1, 1, 9, 10, 0, 2, 1, RT_NORMAL_TG, 0x055e}, 2423141cc406Sopenharmony_ci {400, 3, 1, 4, 1, 1, 6, 6, 1, 2, 1, RT_NORMAL_TG, 0x157b}, 2424141cc406Sopenharmony_ci {300, 15, 3, 4, 1, 1, 5, 4, 0, 2, 1, RT_NORMAL_TG, 0x02af}, 2425141cc406Sopenharmony_ci {200, 7, 1, 4, 1, 1, 3, 3, 0, 2, 1, RT_NORMAL_TG, 0x055e}, 2426141cc406Sopenharmony_ci {150, 15, 3, 1, 1, 1, 2, 2, 0, 2, 1, RT_NORMAL_TG, 0x02af}, 2427141cc406Sopenharmony_ci {100, 3, 1, 3, 1, 1, 1, 1, 0, 2, 1, RT_NORMAL_TG, 0x0abd}, 2428141cc406Sopenharmony_ci {75, 15, 3, 3, 1, 1, 1, 1, 0, 2, 1, RT_NORMAL_TG, 0x02af}, 2429141cc406Sopenharmony_ci {50, 15, 1, 1, 1, 1, 0, 0, 0, 2, 1, RT_NORMAL_TG, 0x055e}, 2430141cc406Sopenharmony_ci {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 2431141cc406Sopenharmony_ci}; 2432141cc406Sopenharmony_ci 2433141cc406Sopenharmony_cistruct dcalibdata 2434141cc406Sopenharmony_ci{ 2435141cc406Sopenharmony_ci unsigned char *buffers[3]; 2436141cc406Sopenharmony_ci int pixelsperrow; 2437141cc406Sopenharmony_ci int pixelnow; 2438141cc406Sopenharmony_ci int channelnow; 2439141cc406Sopenharmony_ci int firstrowdone; 2440141cc406Sopenharmony_ci}; 2441141cc406Sopenharmony_ci 2442141cc406Sopenharmony_cistatic void dump_registers (unsigned char const *); 2443141cc406Sopenharmony_cistatic int 2444141cc406Sopenharmony_cirts8801_rewind (void) 2445141cc406Sopenharmony_ci{ 2446141cc406Sopenharmony_ci unsigned char regs[255]; 2447141cc406Sopenharmony_ci int n; 2448141cc406Sopenharmony_ci int tg_setting = RT_DOUBLE_TG; 2449141cc406Sopenharmony_ci 2450141cc406Sopenharmony_ci rt_read_register_immediate (0, 255, regs); 2451141cc406Sopenharmony_ci 2452141cc406Sopenharmony_ci rt_set_noscan_distance (regs, 59998); 2453141cc406Sopenharmony_ci rt_set_total_distance (regs, 59999); 2454141cc406Sopenharmony_ci 2455141cc406Sopenharmony_ci rt_set_stop_when_rewound (regs, 0); 2456141cc406Sopenharmony_ci 2457141cc406Sopenharmony_ci rt_set_one_register (0xc6, 0); 2458141cc406Sopenharmony_ci rt_set_one_register (0xc6, 0); 2459141cc406Sopenharmony_ci 2460141cc406Sopenharmony_ci 2461141cc406Sopenharmony_ci rt_set_direction_rewind (regs); 2462141cc406Sopenharmony_ci 2463141cc406Sopenharmony_ci rt_set_step_size (regs, 0x55); 2464141cc406Sopenharmony_ci regs[0x39] = 3; 2465141cc406Sopenharmony_ci regs[0xc3] = (regs[0xc3] & 0xf8) | 0x86; 2466141cc406Sopenharmony_ci regs[0xc6] = (regs[0xc6] & 0xf8) | 4; 2467141cc406Sopenharmony_ci 2468141cc406Sopenharmony_ci rt_set_horizontal_resolution (regs, 25); 2469141cc406Sopenharmony_ci rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p); 2470141cc406Sopenharmony_ci rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp); 2471141cc406Sopenharmony_ci rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp); 2472141cc406Sopenharmony_ci rt_set_cdss (regs, tg_info[tg_setting].tg_cdss1, 2473141cc406Sopenharmony_ci tg_info[tg_setting].tg_cdss2); 2474141cc406Sopenharmony_ci rt_set_cdsc (regs, tg_info[tg_setting].tg_cdsc1, 2475141cc406Sopenharmony_ci tg_info[tg_setting].tg_cdsc2); 2476141cc406Sopenharmony_ci rt_update_after_setting_cdss2 (regs); 2477141cc406Sopenharmony_ci rt_set_cvtr_wparams (regs, 3, 0, 6); 2478141cc406Sopenharmony_ci rt_set_cvtr_mpt (regs, 15, 15, 15); 2479141cc406Sopenharmony_ci rt_set_cvtr_lm (regs, 7, 7, 7); 2480141cc406Sopenharmony_ci rt_set_motor_type (regs, 2); 2481141cc406Sopenharmony_ci 2482141cc406Sopenharmony_ci if (DBG_LEVEL >= 5) 2483141cc406Sopenharmony_ci dump_registers (regs); 2484141cc406Sopenharmony_ci 2485141cc406Sopenharmony_ci rt_set_all_registers (regs); 2486141cc406Sopenharmony_ci rt_set_one_register (0x2c, regs[0x2c]); 2487141cc406Sopenharmony_ci 2488141cc406Sopenharmony_ci rt_start_moving (); 2489141cc406Sopenharmony_ci 2490141cc406Sopenharmony_ci while (!rt_is_rewound () && 2491141cc406Sopenharmony_ci ((n = rt_get_available_bytes ()) > 0 || rt_is_moving () > 0)) 2492141cc406Sopenharmony_ci { 2493141cc406Sopenharmony_ci if (n) 2494141cc406Sopenharmony_ci { 2495141cc406Sopenharmony_ci char buffer[0xffc0]; 2496141cc406Sopenharmony_ci 2497141cc406Sopenharmony_ci if (n > (int) sizeof (buffer)) 2498141cc406Sopenharmony_ci n = sizeof (buffer); 2499141cc406Sopenharmony_ci rt_get_data (n, buffer); 2500141cc406Sopenharmony_ci } 2501141cc406Sopenharmony_ci else 2502141cc406Sopenharmony_ci { 2503141cc406Sopenharmony_ci usleep (10000); 2504141cc406Sopenharmony_ci } 2505141cc406Sopenharmony_ci } 2506141cc406Sopenharmony_ci 2507141cc406Sopenharmony_ci rt_stop_moving (); 2508141cc406Sopenharmony_ci return 0; 2509141cc406Sopenharmony_ci} 2510141cc406Sopenharmony_ci 2511141cc406Sopenharmony_cistatic int cancelled_scan = 0; 2512141cc406Sopenharmony_ci 2513141cc406Sopenharmony_cistatic unsigned 2514141cc406Sopenharmony_ciget_lsbfirst_int (unsigned char const *p, int n) 2515141cc406Sopenharmony_ci{ 2516141cc406Sopenharmony_ci unsigned value = *p++; 2517141cc406Sopenharmony_ci int shift = 8; 2518141cc406Sopenharmony_ci 2519141cc406Sopenharmony_ci while (--n) 2520141cc406Sopenharmony_ci { 2521141cc406Sopenharmony_ci unsigned now = *p++; 2522141cc406Sopenharmony_ci value |= now << shift; 2523141cc406Sopenharmony_ci shift += 8; 2524141cc406Sopenharmony_ci } 2525141cc406Sopenharmony_ci return value; 2526141cc406Sopenharmony_ci} 2527141cc406Sopenharmony_ci 2528141cc406Sopenharmony_cistatic int 2529141cc406Sopenharmony_ciconvert_c6 (int i) 2530141cc406Sopenharmony_ci{ 2531141cc406Sopenharmony_ci switch (i) 2532141cc406Sopenharmony_ci { 2533141cc406Sopenharmony_ci case 3: 2534141cc406Sopenharmony_ci return 1; 2535141cc406Sopenharmony_ci 2536141cc406Sopenharmony_ci case 1: 2537141cc406Sopenharmony_ci return 2; 2538141cc406Sopenharmony_ci 2539141cc406Sopenharmony_ci case 4: 2540141cc406Sopenharmony_ci return 4; 2541141cc406Sopenharmony_ci } 2542141cc406Sopenharmony_ci return -1; 2543141cc406Sopenharmony_ci} 2544141cc406Sopenharmony_ci 2545141cc406Sopenharmony_cistatic void 2546141cc406Sopenharmony_cidump_registers (unsigned char const *regs) 2547141cc406Sopenharmony_ci{ 2548141cc406Sopenharmony_ci int i = 0; 2549141cc406Sopenharmony_ci long pixels; 2550141cc406Sopenharmony_ci 2551141cc406Sopenharmony_ci DBG (5, "Scan commencing with registers:\n"); 2552141cc406Sopenharmony_ci while (i < 255) 2553141cc406Sopenharmony_ci { 2554141cc406Sopenharmony_ci int j = 0; 2555141cc406Sopenharmony_ci char buffer[80]; 2556141cc406Sopenharmony_ci 2557141cc406Sopenharmony_ci buffer[0] = 0; 2558141cc406Sopenharmony_ci 2559141cc406Sopenharmony_ci sprintf (buffer + strlen (buffer), "%02x:", i); 2560141cc406Sopenharmony_ci while (j < 8) 2561141cc406Sopenharmony_ci { 2562141cc406Sopenharmony_ci sprintf (buffer + strlen (buffer), " %02x", regs[i++]); 2563141cc406Sopenharmony_ci j++; 2564141cc406Sopenharmony_ci } 2565141cc406Sopenharmony_ci sprintf (buffer + strlen (buffer), " -"); 2566141cc406Sopenharmony_ci while (j++ < 16 && i < 255) 2567141cc406Sopenharmony_ci sprintf (buffer + strlen (buffer), " %02x", regs[i++]); 2568141cc406Sopenharmony_ci DBG (5, " %s\n", buffer); 2569141cc406Sopenharmony_ci } 2570141cc406Sopenharmony_ci 2571141cc406Sopenharmony_ci DBG (5, " Position:\n"); 2572141cc406Sopenharmony_ci DBG (5, " Distance without scanning: %u\n", 2573141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0x60, 2)); 2574141cc406Sopenharmony_ci DBG (5, " Total distance: %u\n", 2575141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0x62, 2)); 2576141cc406Sopenharmony_ci DBG (5, " Scanning distance: %u\n", 2577141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0x62, 2) - get_lsbfirst_int (regs + 0x60, 2)); 2578141cc406Sopenharmony_ci DBG (5, " Direction: %s\n", 2579141cc406Sopenharmony_ci (regs[0xc6] & 0x08) ? "forward" : "rewind"); 2580141cc406Sopenharmony_ci DBG (5, " Motor: %s\n", 2581141cc406Sopenharmony_ci (regs[0xc3] & 0x80) ? "enabled" : "disabled"); 2582141cc406Sopenharmony_ci if (regs[0x7a]) 2583141cc406Sopenharmony_ci DBG (5, " X range: %u-%u\n", 2584141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0x66, 2) / regs[0x7a], 2585141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0x6c, 2) / regs[0x7a]); 2586141cc406Sopenharmony_ci DBG (5, " TG Info:\n"); 2587141cc406Sopenharmony_ci DBG (5, " CPH0P: %06x\n", 2588141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0xf0, 3)); 2589141cc406Sopenharmony_ci DBG (5, " CRSP: %06x\n", 2590141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0xf9, 3)); 2591141cc406Sopenharmony_ci DBG (5, " CCLPP: %06x\n", 2592141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0xfc, 3)); 2593141cc406Sopenharmony_ci DBG (5, " CPH0S: %d\n", 2594141cc406Sopenharmony_ci (regs[0x2d] & 0x20) ? 1 : 0); 2595141cc406Sopenharmony_ci DBG (5, " CDSS1: %02x\n", regs[0x28] & 0x1f); 2596141cc406Sopenharmony_ci DBG (5, " CDSC1: %02x\n", regs[0x29] & 0x1f); 2597141cc406Sopenharmony_ci DBG (5, " CDSS2: %02x\n", regs[0x2a] & 0x1f); 2598141cc406Sopenharmony_ci DBG (5, " CDSC2: %02x\n", regs[0x2b] & 0x1f); 2599141cc406Sopenharmony_ci 2600141cc406Sopenharmony_ci DBG (5, " Resolution specific:\n"); 2601141cc406Sopenharmony_ci if (!regs[0x7a]) 2602141cc406Sopenharmony_ci DBG (5, " Horizontal resolution: Denominator is zero!\n"); 2603141cc406Sopenharmony_ci else 2604141cc406Sopenharmony_ci DBG (5, " Horizontal resolution: %u\n", 300 2605141cc406Sopenharmony_ci * ((regs[0x2d] & 0x20) ? 2 : 1) 2606141cc406Sopenharmony_ci * ((regs[0xd3] & 0x08) ? 2 : 1) / regs[0x7a]); 2607141cc406Sopenharmony_ci DBG (5, " Derived vertical resolution: %u\n", 2608141cc406Sopenharmony_ci 400 * (regs[0xc3] & 0x1f) * convert_c6 (regs[0xc6] & 0x7) / 2609141cc406Sopenharmony_ci (regs[0x39] + 1)); 2610141cc406Sopenharmony_ci DBG (5, " Register D3:3 %u\n", 2611141cc406Sopenharmony_ci (regs[0xd3] & 0x08) ? 1 : 0); 2612141cc406Sopenharmony_ci DBG (5, " Register 39: %u\n", regs[0x39]); 2613141cc406Sopenharmony_ci DBG (5, " Register C3:0-5: %u\n", regs[0xc3] & 0x1f); 2614141cc406Sopenharmony_ci DBG (5, " Register C6:0-2: %u\n", regs[0xc6] & 0x7); 2615141cc406Sopenharmony_ci DBG (5, " Motor movement clock multiplier: %u\n", regs[0x40] >> 6); 2616141cc406Sopenharmony_ci DBG (5, " Step Size: %04x\n", 2617141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0xe2, 2)); 2618141cc406Sopenharmony_ci DBG (5, " Frequency: %u\n", regs[0x64] & 0xf); 2619141cc406Sopenharmony_ci DBG (5, " Colour registers\n"); 2620141cc406Sopenharmony_ci DBG (5, " Register 2F: %02x\n", regs[0x2f]); 2621141cc406Sopenharmony_ci DBG (5, " Register 2C: %02x\n", regs[0x2c]); 2622141cc406Sopenharmony_ci if (regs[0x7a]) 2623141cc406Sopenharmony_ci { 2624141cc406Sopenharmony_ci DBG (5, " Scan data estimates:\n"); 2625141cc406Sopenharmony_ci pixels = 2626141cc406Sopenharmony_ci (long) (get_lsbfirst_int (regs + 0x62, 2) - 2627141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0x60, 2628141cc406Sopenharmony_ci 2)) * (long) (get_lsbfirst_int (regs + 0x6c, 2629141cc406Sopenharmony_ci 2) - 2630141cc406Sopenharmony_ci get_lsbfirst_int (regs + 0x66, 2631141cc406Sopenharmony_ci 2)) / 2632141cc406Sopenharmony_ci regs[0x7a]; 2633141cc406Sopenharmony_ci DBG (5, " Pixels: %ld\n", pixels); 2634141cc406Sopenharmony_ci DBG (5, " Bytes at 24BPP: %ld\n", pixels * 3); 2635141cc406Sopenharmony_ci DBG (5, " Bytes at 1BPP: %ld\n", pixels / 8); 2636141cc406Sopenharmony_ci } 2637141cc406Sopenharmony_ci DBG (5, "\n"); 2638141cc406Sopenharmony_ci} 2639141cc406Sopenharmony_ci 2640141cc406Sopenharmony_cistatic int 2641141cc406Sopenharmony_ciconstrain (int val, int min, int max) 2642141cc406Sopenharmony_ci{ 2643141cc406Sopenharmony_ci if (val < min) 2644141cc406Sopenharmony_ci { 2645141cc406Sopenharmony_ci DBG (10, "Clipped %d to %d\n", val, min); 2646141cc406Sopenharmony_ci val = min; 2647141cc406Sopenharmony_ci } 2648141cc406Sopenharmony_ci else if (val > max) 2649141cc406Sopenharmony_ci { 2650141cc406Sopenharmony_ci DBG (10, "Clipped %d to %d\n", val, max); 2651141cc406Sopenharmony_ci val = max; 2652141cc406Sopenharmony_ci } 2653141cc406Sopenharmony_ci return val; 2654141cc406Sopenharmony_ci} 2655141cc406Sopenharmony_ci 2656141cc406Sopenharmony_ci#if 0 2657141cc406Sopenharmony_cistatic void 2658141cc406Sopenharmony_cisram_dump_byte(FILE *fp, 2659141cc406Sopenharmony_ci unsigned char const *left, 2660141cc406Sopenharmony_ci unsigned leftstart, 2661141cc406Sopenharmony_ci unsigned leftlimit, 2662141cc406Sopenharmony_ci unsigned char const *right, 2663141cc406Sopenharmony_ci unsigned rightstart, 2664141cc406Sopenharmony_ci unsigned rightlimit, 2665141cc406Sopenharmony_ci unsigned idx) 2666141cc406Sopenharmony_ci{ 2667141cc406Sopenharmony_ci unsigned ridx = rightstart + idx; 2668141cc406Sopenharmony_ci unsigned lidx = leftstart + idx; 2669141cc406Sopenharmony_ci 2670141cc406Sopenharmony_ci putc(' ', fp); 2671141cc406Sopenharmony_ci if (rightstart < rightlimit && leftstart < leftlimit && left[lidx] != right[ridx]) 2672141cc406Sopenharmony_ci fputs("<b>", fp); 2673141cc406Sopenharmony_ci if (leftstart < leftlimit) 2674141cc406Sopenharmony_ci fprintf(fp, "%02x", left[lidx]); 2675141cc406Sopenharmony_ci else 2676141cc406Sopenharmony_ci fputs(" ", fp); 2677141cc406Sopenharmony_ci if (rightstart < rightlimit && leftstart < leftlimit && left[lidx] != right[ridx]) 2678141cc406Sopenharmony_ci fputs("</b>", fp); 2679141cc406Sopenharmony_ci} 2680141cc406Sopenharmony_ci 2681141cc406Sopenharmony_cistatic void 2682141cc406Sopenharmony_cidump_sram_to_file(char const *fname, 2683141cc406Sopenharmony_ci unsigned char const *expected, 2684141cc406Sopenharmony_ci unsigned end_calibration_offset) 2685141cc406Sopenharmony_ci{ 2686141cc406Sopenharmony_ci FILE *fp = fopen(fname, "w"); 2687141cc406Sopenharmony_ci rt_set_sram_page(0); 2688141cc406Sopenharmony_ci 2689141cc406Sopenharmony_ci if (fp) 2690141cc406Sopenharmony_ci { 2691141cc406Sopenharmony_ci unsigned char buf[1024]; 2692141cc406Sopenharmony_ci unsigned loc = 0; 2693141cc406Sopenharmony_ci 2694141cc406Sopenharmony_ci fprintf(fp, "<html><head></head><body><pre>\n"); 2695141cc406Sopenharmony_ci while (loc < end_calibration_offset) 2696141cc406Sopenharmony_ci { 2697141cc406Sopenharmony_ci unsigned byte = 0; 2698141cc406Sopenharmony_ci 2699141cc406Sopenharmony_ci rt_read_sram(1024, buf); 2700141cc406Sopenharmony_ci 2701141cc406Sopenharmony_ci while (byte < 1024) 2702141cc406Sopenharmony_ci { 2703141cc406Sopenharmony_ci unsigned idx = 0; 2704141cc406Sopenharmony_ci 2705141cc406Sopenharmony_ci fprintf(fp, "%06x:", loc); 2706141cc406Sopenharmony_ci do 2707141cc406Sopenharmony_ci { 2708141cc406Sopenharmony_ci sram_dump_byte(fp, buf, byte, 1024, expected, loc, end_calibration_offset, idx); 2709141cc406Sopenharmony_ci } while (++idx & 0x7); 2710141cc406Sopenharmony_ci fprintf(fp, " -"); 2711141cc406Sopenharmony_ci do 2712141cc406Sopenharmony_ci { 2713141cc406Sopenharmony_ci sram_dump_byte(fp, buf, byte, 1024, expected, loc, end_calibration_offset, idx); 2714141cc406Sopenharmony_ci } while (++idx & 0x7); 2715141cc406Sopenharmony_ci 2716141cc406Sopenharmony_ci idx = 0; 2717141cc406Sopenharmony_ci fputs(" ", fp); 2718141cc406Sopenharmony_ci 2719141cc406Sopenharmony_ci do 2720141cc406Sopenharmony_ci { 2721141cc406Sopenharmony_ci sram_dump_byte(fp, expected, loc, end_calibration_offset, buf, byte, 1024, idx); 2722141cc406Sopenharmony_ci } while (++idx & 0x7); 2723141cc406Sopenharmony_ci fprintf(fp, " -"); 2724141cc406Sopenharmony_ci do 2725141cc406Sopenharmony_ci { 2726141cc406Sopenharmony_ci sram_dump_byte(fp, expected, loc, end_calibration_offset, buf, byte, 1024, idx); 2727141cc406Sopenharmony_ci } while (++idx & 0x7); 2728141cc406Sopenharmony_ci 2729141cc406Sopenharmony_ci 2730141cc406Sopenharmony_ci fputs("\n", fp); 2731141cc406Sopenharmony_ci byte += 16; 2732141cc406Sopenharmony_ci loc += 16; 2733141cc406Sopenharmony_ci } 2734141cc406Sopenharmony_ci } 2735141cc406Sopenharmony_ci fprintf(fp, "</pre></body></html>"); 2736141cc406Sopenharmony_ci fclose(fp); 2737141cc406Sopenharmony_ci } 2738141cc406Sopenharmony_ci} 2739141cc406Sopenharmony_ci#endif 2740141cc406Sopenharmony_ci 2741141cc406Sopenharmony_cistatic int 2742141cc406Sopenharmony_cirts8801_doscan (unsigned width, 2743141cc406Sopenharmony_ci unsigned height, 2744141cc406Sopenharmony_ci unsigned colour, 2745141cc406Sopenharmony_ci unsigned red_green_offset, 2746141cc406Sopenharmony_ci unsigned green_blue_offset, 2747141cc406Sopenharmony_ci unsigned intra_channel_offset, 2748141cc406Sopenharmony_ci rts8801_callback cbfunc, 2749141cc406Sopenharmony_ci void *params, 2750141cc406Sopenharmony_ci int oddfirst, 2751141cc406Sopenharmony_ci unsigned char const *calib_info, 2752141cc406Sopenharmony_ci int merged_channels, 2753141cc406Sopenharmony_ci double *postprocess_offsets, 2754141cc406Sopenharmony_ci double *postprocess_gains) 2755141cc406Sopenharmony_ci{ 2756141cc406Sopenharmony_ci unsigned rowbytes = 0; 2757141cc406Sopenharmony_ci unsigned output_rowbytes = 0; 2758141cc406Sopenharmony_ci unsigned channels = 0; 2759141cc406Sopenharmony_ci unsigned total_rows = 0; 2760141cc406Sopenharmony_ci unsigned char *row_buffer; 2761141cc406Sopenharmony_ci unsigned char *output_buffer; 2762141cc406Sopenharmony_ci unsigned buffered_rows; 2763141cc406Sopenharmony_ci int rows_to_begin; 2764141cc406Sopenharmony_ci int rowbuffer_bytes; 2765141cc406Sopenharmony_ci int n; 2766141cc406Sopenharmony_ci unsigned rownow = 0; 2767141cc406Sopenharmony_ci unsigned bytenow = 0; 2768141cc406Sopenharmony_ci unsigned char *channel_data[3][2]; 2769141cc406Sopenharmony_ci unsigned i; 2770141cc406Sopenharmony_ci unsigned j; 2771141cc406Sopenharmony_ci int result = 0; 2772141cc406Sopenharmony_ci unsigned rows_supplied = 0; 2773141cc406Sopenharmony_ci 2774141cc406Sopenharmony_ci (void) calib_info; /* Kill warning */ 2775141cc406Sopenharmony_ci if (cancelled_scan) 2776141cc406Sopenharmony_ci return -1; 2777141cc406Sopenharmony_ci rt_start_moving (); 2778141cc406Sopenharmony_ci 2779141cc406Sopenharmony_ci channels = 3; 2780141cc406Sopenharmony_ci rowbytes = width * 3; 2781141cc406Sopenharmony_ci 2782141cc406Sopenharmony_ci switch (colour) 2783141cc406Sopenharmony_ci { 2784141cc406Sopenharmony_ci case HP3500_GRAY_SCAN: 2785141cc406Sopenharmony_ci output_rowbytes = width; 2786141cc406Sopenharmony_ci break; 2787141cc406Sopenharmony_ci 2788141cc406Sopenharmony_ci case HP3500_COLOR_SCAN: 2789141cc406Sopenharmony_ci output_rowbytes = rowbytes; 2790141cc406Sopenharmony_ci break; 2791141cc406Sopenharmony_ci 2792141cc406Sopenharmony_ci case HP3500_LINEART_SCAN: 2793141cc406Sopenharmony_ci output_rowbytes = (width + 7) / 8; 2794141cc406Sopenharmony_ci break; 2795141cc406Sopenharmony_ci } 2796141cc406Sopenharmony_ci 2797141cc406Sopenharmony_ci buffered_rows = 2798141cc406Sopenharmony_ci red_green_offset + green_blue_offset + intra_channel_offset + 1; 2799141cc406Sopenharmony_ci rows_to_begin = buffered_rows; 2800141cc406Sopenharmony_ci rowbuffer_bytes = buffered_rows * rowbytes; 2801141cc406Sopenharmony_ci row_buffer = (unsigned char *) malloc (rowbuffer_bytes); 2802141cc406Sopenharmony_ci output_buffer = (unsigned char *) malloc (rowbytes); 2803141cc406Sopenharmony_ci 2804141cc406Sopenharmony_ci for (i = j = 0; i < channels; ++i) 2805141cc406Sopenharmony_ci { 2806141cc406Sopenharmony_ci if (i == 1) 2807141cc406Sopenharmony_ci j += red_green_offset; 2808141cc406Sopenharmony_ci else if (i == 2) 2809141cc406Sopenharmony_ci j += green_blue_offset; 2810141cc406Sopenharmony_ci if (merged_channels) 2811141cc406Sopenharmony_ci channel_data[i][1 - oddfirst] = row_buffer + rowbytes * j + i; 2812141cc406Sopenharmony_ci else 2813141cc406Sopenharmony_ci channel_data[i][1 - oddfirst] = row_buffer + rowbytes * j + width * i; 2814141cc406Sopenharmony_ci channel_data[i][oddfirst] = 2815141cc406Sopenharmony_ci channel_data[i][1 - oddfirst] + rowbytes * intra_channel_offset; 2816141cc406Sopenharmony_ci } 2817141cc406Sopenharmony_ci 2818141cc406Sopenharmony_ci while (((n = rt_get_available_bytes ()) > 0 || rt_is_moving () > 0) 2819141cc406Sopenharmony_ci && !cancelled_scan) 2820141cc406Sopenharmony_ci { 2821141cc406Sopenharmony_ci if (n == 1 && (rt_is_moving () || rt_get_available_bytes () != 1)) 2822141cc406Sopenharmony_ci n = 0; 2823141cc406Sopenharmony_ci if (n > 0) 2824141cc406Sopenharmony_ci { 2825141cc406Sopenharmony_ci unsigned char buffer[0xffc0]; 2826141cc406Sopenharmony_ci 2827141cc406Sopenharmony_ci if (n > 0xffc0) 2828141cc406Sopenharmony_ci n = 0xffc0; 2829141cc406Sopenharmony_ci else if ((n > 1) && (n & 1)) 2830141cc406Sopenharmony_ci --n; 2831141cc406Sopenharmony_ci if (rt_get_data (n, buffer) >= 0) 2832141cc406Sopenharmony_ci { 2833141cc406Sopenharmony_ci unsigned char *bufnow = buffer; 2834141cc406Sopenharmony_ci 2835141cc406Sopenharmony_ci while (n) 2836141cc406Sopenharmony_ci { 2837141cc406Sopenharmony_ci int numcopy = rowbytes - bytenow; 2838141cc406Sopenharmony_ci 2839141cc406Sopenharmony_ci if (numcopy > n) 2840141cc406Sopenharmony_ci numcopy = n; 2841141cc406Sopenharmony_ci 2842141cc406Sopenharmony_ci memcpy (row_buffer + rownow * rowbytes + bytenow, 2843141cc406Sopenharmony_ci bufnow, numcopy); 2844141cc406Sopenharmony_ci bytenow += numcopy; 2845141cc406Sopenharmony_ci bufnow += numcopy; 2846141cc406Sopenharmony_ci n -= numcopy; 2847141cc406Sopenharmony_ci 2848141cc406Sopenharmony_ci if (bytenow == rowbytes) 2849141cc406Sopenharmony_ci { 2850141cc406Sopenharmony_ci if (!rows_to_begin || !--rows_to_begin) 2851141cc406Sopenharmony_ci { 2852141cc406Sopenharmony_ci unsigned char *outnow = output_buffer; 2853141cc406Sopenharmony_ci unsigned x; 2854141cc406Sopenharmony_ci 2855141cc406Sopenharmony_ci for (i = x = 0; 2856141cc406Sopenharmony_ci x < width; 2857141cc406Sopenharmony_ci ++x, i += merged_channels ? channels : 1) 2858141cc406Sopenharmony_ci { 2859141cc406Sopenharmony_ci for (j = 0; j < channels; ++j) 2860141cc406Sopenharmony_ci { 2861141cc406Sopenharmony_ci unsigned pix = 2862141cc406Sopenharmony_ci (unsigned char) channel_data[j][i & 1][i]; 2863141cc406Sopenharmony_ci 2864141cc406Sopenharmony_ci if (postprocess_gains && postprocess_offsets) 2865141cc406Sopenharmony_ci { 2866141cc406Sopenharmony_ci int ppidx = j * width + x; 2867141cc406Sopenharmony_ci 2868141cc406Sopenharmony_ci pix = constrain ( pix 2869141cc406Sopenharmony_ci * postprocess_gains[ppidx] 2870141cc406Sopenharmony_ci - postprocess_offsets[ppidx], 2871141cc406Sopenharmony_ci 0, 2872141cc406Sopenharmony_ci 255); 2873141cc406Sopenharmony_ci } 2874141cc406Sopenharmony_ci *outnow++ = pix; 2875141cc406Sopenharmony_ci } 2876141cc406Sopenharmony_ci } 2877141cc406Sopenharmony_ci 2878141cc406Sopenharmony_ci if (colour == HP3500_GRAY_SCAN || colour == HP3500_LINEART_SCAN) 2879141cc406Sopenharmony_ci { 2880141cc406Sopenharmony_ci unsigned char const *in_now = output_buffer; 2881141cc406Sopenharmony_ci int bit = 7; 2882141cc406Sopenharmony_ci 2883141cc406Sopenharmony_ci outnow = output_buffer; 2884141cc406Sopenharmony_ci for (i = 0; i < width; ++i) 2885141cc406Sopenharmony_ci { 2886141cc406Sopenharmony_ci 2887141cc406Sopenharmony_ci if (colour == HP3500_GRAY_SCAN) 2888141cc406Sopenharmony_ci { 2889141cc406Sopenharmony_ci *outnow++ = ((unsigned) in_now[0] * 2989 + 2890141cc406Sopenharmony_ci (unsigned) in_now[1] * 5870 + 2891141cc406Sopenharmony_ci (unsigned) in_now[2] * 1140) / 10000; 2892141cc406Sopenharmony_ci } 2893141cc406Sopenharmony_ci else 2894141cc406Sopenharmony_ci { 2895141cc406Sopenharmony_ci if (bit == 7) 2896141cc406Sopenharmony_ci *outnow = ((in_now[1] < 0x80) ? 0x80 : 0); 2897141cc406Sopenharmony_ci else if (in_now[1] < 0x80) 2898141cc406Sopenharmony_ci *outnow |= (1 << bit); 2899141cc406Sopenharmony_ci if (bit == 0) 2900141cc406Sopenharmony_ci { 2901141cc406Sopenharmony_ci ++outnow; 2902141cc406Sopenharmony_ci bit = 7; 2903141cc406Sopenharmony_ci } 2904141cc406Sopenharmony_ci else 2905141cc406Sopenharmony_ci { 2906141cc406Sopenharmony_ci --bit; 2907141cc406Sopenharmony_ci } 2908141cc406Sopenharmony_ci } 2909141cc406Sopenharmony_ci in_now += 3; 2910141cc406Sopenharmony_ci } 2911141cc406Sopenharmony_ci } 2912141cc406Sopenharmony_ci if (rows_supplied++ < height && 2913141cc406Sopenharmony_ci !((*cbfunc) (params, output_rowbytes, output_buffer))) 2914141cc406Sopenharmony_ci break; 2915141cc406Sopenharmony_ci 2916141cc406Sopenharmony_ci for (i = 0; i < channels; ++i) 2917141cc406Sopenharmony_ci { 2918141cc406Sopenharmony_ci for (j = 0; j < 2; ++j) 2919141cc406Sopenharmony_ci { 2920141cc406Sopenharmony_ci channel_data[i][j] += rowbytes; 2921141cc406Sopenharmony_ci if (channel_data[i][j] - row_buffer >= 2922141cc406Sopenharmony_ci rowbuffer_bytes) 2923141cc406Sopenharmony_ci channel_data[i][j] -= rowbuffer_bytes; 2924141cc406Sopenharmony_ci } 2925141cc406Sopenharmony_ci } 2926141cc406Sopenharmony_ci } 2927141cc406Sopenharmony_ci ++total_rows; 2928141cc406Sopenharmony_ci if (++rownow == buffered_rows) 2929141cc406Sopenharmony_ci rownow = 0; 2930141cc406Sopenharmony_ci bytenow = 0; 2931141cc406Sopenharmony_ci } 2932141cc406Sopenharmony_ci } 2933141cc406Sopenharmony_ci } 2934141cc406Sopenharmony_ci DBG (30, "total_rows = %d\r", total_rows); 2935141cc406Sopenharmony_ci } 2936141cc406Sopenharmony_ci else 2937141cc406Sopenharmony_ci { 2938141cc406Sopenharmony_ci usleep (10000); 2939141cc406Sopenharmony_ci } 2940141cc406Sopenharmony_ci } 2941141cc406Sopenharmony_ci DBG (10, "\n"); 2942141cc406Sopenharmony_ci if (n < 0) 2943141cc406Sopenharmony_ci result = -1; 2944141cc406Sopenharmony_ci 2945141cc406Sopenharmony_ci free (output_buffer); 2946141cc406Sopenharmony_ci free (row_buffer); 2947141cc406Sopenharmony_ci 2948141cc406Sopenharmony_ci rt_stop_moving (); 2949141cc406Sopenharmony_ci return result; 2950141cc406Sopenharmony_ci} 2951141cc406Sopenharmony_ci 2952141cc406Sopenharmony_cistatic unsigned local_sram_size; 2953141cc406Sopenharmony_cistatic unsigned char r93setting; 2954141cc406Sopenharmony_ci 2955141cc406Sopenharmony_ci#define RTS8801_F_SUPPRESS_MOVEMENT 1 2956141cc406Sopenharmony_ci#define RTS8801_F_LAMP_OFF 2 2957141cc406Sopenharmony_ci#define RTS8801_F_NO_DISPLACEMENTS 4 2958141cc406Sopenharmony_ci#define RTS8801_F_ODDX 8 2959141cc406Sopenharmony_ci 2960141cc406Sopenharmony_cistatic int 2961141cc406Sopenharmony_cifind_resolution_index (unsigned resolution) 2962141cc406Sopenharmony_ci{ 2963141cc406Sopenharmony_ci int res = 0; 2964141cc406Sopenharmony_ci 2965141cc406Sopenharmony_ci for (res = 0; resparms[res].resolution != resolution; ++res) 2966141cc406Sopenharmony_ci { 2967141cc406Sopenharmony_ci if (!resparms[res].resolution) 2968141cc406Sopenharmony_ci return -1; 2969141cc406Sopenharmony_ci } 2970141cc406Sopenharmony_ci return res; 2971141cc406Sopenharmony_ci} 2972141cc406Sopenharmony_ci 2973141cc406Sopenharmony_cistatic int 2974141cc406Sopenharmony_cirts8801_fullscan (unsigned x, 2975141cc406Sopenharmony_ci unsigned y, 2976141cc406Sopenharmony_ci unsigned w, 2977141cc406Sopenharmony_ci unsigned h, 2978141cc406Sopenharmony_ci unsigned xresolution, 2979141cc406Sopenharmony_ci unsigned yresolution, 2980141cc406Sopenharmony_ci unsigned colour, 2981141cc406Sopenharmony_ci rts8801_callback cbfunc, 2982141cc406Sopenharmony_ci void *param, 2983141cc406Sopenharmony_ci unsigned char *calib_info, 2984141cc406Sopenharmony_ci int flags, 2985141cc406Sopenharmony_ci int red_calib_offset, 2986141cc406Sopenharmony_ci int green_calib_offset, 2987141cc406Sopenharmony_ci int blue_calib_offset, 2988141cc406Sopenharmony_ci int end_calib_offset, 2989141cc406Sopenharmony_ci double *postprocess_offsets, 2990141cc406Sopenharmony_ci double *postprocess_gains) 2991141cc406Sopenharmony_ci{ 2992141cc406Sopenharmony_ci int ires, jres; 2993141cc406Sopenharmony_ci int tg_setting; 2994141cc406Sopenharmony_ci unsigned char regs[256]; 2995141cc406Sopenharmony_ci unsigned char offdutytime; 2996141cc406Sopenharmony_ci int result; 2997141cc406Sopenharmony_ci int scan_frequency; 2998141cc406Sopenharmony_ci unsigned intra_channel_offset; 2999141cc406Sopenharmony_ci unsigned red_green_offset; 3000141cc406Sopenharmony_ci unsigned green_blue_offset; 3001141cc406Sopenharmony_ci unsigned total_offsets; 3002141cc406Sopenharmony_ci 3003141cc406Sopenharmony_ci ires = find_resolution_index (xresolution); 3004141cc406Sopenharmony_ci jres = find_resolution_index (yresolution); 3005141cc406Sopenharmony_ci 3006141cc406Sopenharmony_ci if (ires < 0 || jres < 0) 3007141cc406Sopenharmony_ci return -1; 3008141cc406Sopenharmony_ci 3009141cc406Sopenharmony_ci /* Set scan parameters */ 3010141cc406Sopenharmony_ci 3011141cc406Sopenharmony_ci rt_read_register_immediate (0, 255, regs); 3012141cc406Sopenharmony_ci regs[255] = 0; 3013141cc406Sopenharmony_ci 3014141cc406Sopenharmony_ci rt_enable_ccd (regs, 1); 3015141cc406Sopenharmony_ci rt_enable_movement (regs, 1); 3016141cc406Sopenharmony_ci rt_set_scan_frequency (regs, 1); 3017141cc406Sopenharmony_ci 3018141cc406Sopenharmony_ci rt_adjust_misc_registers (regs); 3019141cc406Sopenharmony_ci 3020141cc406Sopenharmony_ci rt_set_cvtr_wparams (regs, 3, 0, 6); 3021141cc406Sopenharmony_ci rt_set_cvtr_mpt (regs, 15, 15, 15); 3022141cc406Sopenharmony_ci rt_set_cvtr_lm (regs, 7, 7, 7); 3023141cc406Sopenharmony_ci rt_set_motor_type (regs, 2); 3024141cc406Sopenharmony_ci 3025141cc406Sopenharmony_ci if (rt_nvram_read (0, 0x7b, &offdutytime, 1) < 0 || offdutytime >= 15) 3026141cc406Sopenharmony_ci { 3027141cc406Sopenharmony_ci offdutytime = 6; 3028141cc406Sopenharmony_ci } 3029141cc406Sopenharmony_ci rt_set_lamp_duty_cycle (regs, 1, /* On */ 3030141cc406Sopenharmony_ci 10, /* Frequency */ 3031141cc406Sopenharmony_ci offdutytime); /* Off duty time */ 3032141cc406Sopenharmony_ci 3033141cc406Sopenharmony_ci rt_set_movement_pattern (regs, 0x800000); 3034141cc406Sopenharmony_ci 3035141cc406Sopenharmony_ci rt_set_direction_forwards (regs); 3036141cc406Sopenharmony_ci rt_set_stop_when_rewound (regs, 0); 3037141cc406Sopenharmony_ci 3038141cc406Sopenharmony_ci rt_set_calibration_addresses (regs, 0, 0, 0, 0, 0); 3039141cc406Sopenharmony_ci 3040141cc406Sopenharmony_ci rt_set_basic_calibration (regs, 3041141cc406Sopenharmony_ci calib_info[0], calib_info[1], calib_info[2], 3042141cc406Sopenharmony_ci calib_info[3], calib_info[4], calib_info[5], 3043141cc406Sopenharmony_ci calib_info[6], calib_info[7], calib_info[8]); 3044141cc406Sopenharmony_ci regs[0x0b] = 0x70; /* If set to 0x71, the alternative, all values are low */ 3045141cc406Sopenharmony_ci regs[0x40] &= 0xc0; 3046141cc406Sopenharmony_ci 3047141cc406Sopenharmony_ci if (red_calib_offset >= 0 3048141cc406Sopenharmony_ci && green_calib_offset >= 0 3049141cc406Sopenharmony_ci && blue_calib_offset >= 0) 3050141cc406Sopenharmony_ci { 3051141cc406Sopenharmony_ci rt_set_calibration_addresses (regs, red_calib_offset, 3052141cc406Sopenharmony_ci green_calib_offset, blue_calib_offset, 3053141cc406Sopenharmony_ci end_calib_offset, 3054141cc406Sopenharmony_ci w); 3055141cc406Sopenharmony_ci regs[0x40] |= 0x2f; 3056141cc406Sopenharmony_ci } 3057141cc406Sopenharmony_ci else if (end_calib_offset >= 0) 3058141cc406Sopenharmony_ci { 3059141cc406Sopenharmony_ci rt_set_calibration_addresses (regs, 0x600, 0x600, 0x600, 3060141cc406Sopenharmony_ci end_calib_offset, w); 3061141cc406Sopenharmony_ci } 3062141cc406Sopenharmony_ci 3063141cc406Sopenharmony_ci rt_set_channel (regs, RT_CHANNEL_ALL); 3064141cc406Sopenharmony_ci rt_set_single_channel_scanning (regs, 0); 3065141cc406Sopenharmony_ci rt_set_merge_channels (regs, 1); 3066141cc406Sopenharmony_ci rt_set_colour_mode (regs, 1); 3067141cc406Sopenharmony_ci 3068141cc406Sopenharmony_ci rt_set_last_sram_page (regs, (local_sram_size - 1) >> 5); 3069141cc406Sopenharmony_ci 3070141cc406Sopenharmony_ci scan_frequency = resparms[jres].scan_frequency; 3071141cc406Sopenharmony_ci rt_set_cph0s (regs, resparms[ires].cph0s); 3072141cc406Sopenharmony_ci if (resparms[ires].d3_bit_3_value) 3073141cc406Sopenharmony_ci regs[0xd3] |= 0x08; 3074141cc406Sopenharmony_ci else 3075141cc406Sopenharmony_ci regs[0xd3] &= 0xf7; 3076141cc406Sopenharmony_ci 3077141cc406Sopenharmony_ci if (flags & RTS8801_F_SUPPRESS_MOVEMENT) 3078141cc406Sopenharmony_ci regs[0xc3] &= 0x7f; 3079141cc406Sopenharmony_ci 3080141cc406Sopenharmony_ci regs[0xb2] &= 0xf7; 3081141cc406Sopenharmony_ci 3082141cc406Sopenharmony_ci rt_set_horizontal_resolution (regs, xresolution); 3083141cc406Sopenharmony_ci 3084141cc406Sopenharmony_ci rt_set_scanline_start (regs, 3085141cc406Sopenharmony_ci x * (1200 / xresolution) / 3086141cc406Sopenharmony_ci (resparms[ires].cph0s ? 1 : 2) / 3087141cc406Sopenharmony_ci (resparms[ires].d3_bit_3_value ? 1 : 2)); 3088141cc406Sopenharmony_ci rt_set_scanline_end (regs, 3089141cc406Sopenharmony_ci (x + 3090141cc406Sopenharmony_ci w) * (1200 / xresolution) / 3091141cc406Sopenharmony_ci (resparms[ires].cph0s ? 1 : 2) / 3092141cc406Sopenharmony_ci (resparms[ires].d3_bit_3_value ? 1 : 2)); 3093141cc406Sopenharmony_ci 3094141cc406Sopenharmony_ci if (flags & RTS8801_F_NO_DISPLACEMENTS) 3095141cc406Sopenharmony_ci { 3096141cc406Sopenharmony_ci red_green_offset = green_blue_offset = intra_channel_offset = 0; 3097141cc406Sopenharmony_ci } 3098141cc406Sopenharmony_ci else 3099141cc406Sopenharmony_ci { 3100141cc406Sopenharmony_ci red_green_offset = resparms[jres].red_green_offset; 3101141cc406Sopenharmony_ci green_blue_offset = resparms[jres].green_blue_offset; 3102141cc406Sopenharmony_ci intra_channel_offset = resparms[jres].intra_channel_offset; 3103141cc406Sopenharmony_ci } 3104141cc406Sopenharmony_ci total_offsets = red_green_offset + green_blue_offset + intra_channel_offset; 3105141cc406Sopenharmony_ci if (y > total_offsets + 2) 3106141cc406Sopenharmony_ci y -= total_offsets; 3107141cc406Sopenharmony_ci h += total_offsets; 3108141cc406Sopenharmony_ci 3109141cc406Sopenharmony_ci if (yresolution > 75 && !(flags & RTS8801_F_SUPPRESS_MOVEMENT)) 3110141cc406Sopenharmony_ci { 3111141cc406Sopenharmony_ci int rmres = find_resolution_index (50); 3112141cc406Sopenharmony_ci 3113141cc406Sopenharmony_ci if (rmres >= 0) 3114141cc406Sopenharmony_ci { 3115141cc406Sopenharmony_ci int factor = yresolution / 50; 3116141cc406Sopenharmony_ci int fastres = y / factor; 3117141cc406Sopenharmony_ci int remainder = y % factor; 3118141cc406Sopenharmony_ci 3119141cc406Sopenharmony_ci while (remainder < 2) 3120141cc406Sopenharmony_ci { 3121141cc406Sopenharmony_ci --fastres; 3122141cc406Sopenharmony_ci remainder += factor; 3123141cc406Sopenharmony_ci } 3124141cc406Sopenharmony_ci 3125141cc406Sopenharmony_ci if (fastres >= 3) 3126141cc406Sopenharmony_ci { 3127141cc406Sopenharmony_ci y = remainder; 3128141cc406Sopenharmony_ci 3129141cc406Sopenharmony_ci rt_set_noscan_distance(regs, fastres * resparms[rmres].scan_frequency - 2); 3130141cc406Sopenharmony_ci rt_set_total_distance(regs, fastres * resparms[rmres].scan_frequency - 1); 3131141cc406Sopenharmony_ci 3132141cc406Sopenharmony_ci rt_set_scan_frequency(regs, 1); 3133141cc406Sopenharmony_ci 3134141cc406Sopenharmony_ci tg_setting = resparms[rmres].tg; 3135141cc406Sopenharmony_ci rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p); 3136141cc406Sopenharmony_ci rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp); 3137141cc406Sopenharmony_ci rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp); 3138141cc406Sopenharmony_ci 3139141cc406Sopenharmony_ci rt_set_one_register (0xc6, 0); 3140141cc406Sopenharmony_ci rt_set_one_register (0xc6, 0); 3141141cc406Sopenharmony_ci 3142141cc406Sopenharmony_ci rt_set_step_size (regs, resparms[rmres].step_size); 3143141cc406Sopenharmony_ci 3144141cc406Sopenharmony_ci rt_set_motor_movement_clock_multiplier (regs, 3145141cc406Sopenharmony_ci resparms[rmres]. 3146141cc406Sopenharmony_ci motor_movement_clock_multiplier); 3147141cc406Sopenharmony_ci 3148141cc406Sopenharmony_ci rt_set_cdss (regs, tg_info[tg_setting].tg_cdss1, 3149141cc406Sopenharmony_ci tg_info[tg_setting].tg_cdss2); 3150141cc406Sopenharmony_ci rt_set_cdsc (regs, tg_info[tg_setting].tg_cdsc1, 3151141cc406Sopenharmony_ci tg_info[tg_setting].tg_cdsc2); 3152141cc406Sopenharmony_ci rt_update_after_setting_cdss2 (regs); 3153141cc406Sopenharmony_ci 3154141cc406Sopenharmony_ci regs[0x39] = resparms[rmres].reg_39_value; 3155141cc406Sopenharmony_ci regs[0xc3] = (regs[0xc3] & 0xf8) | resparms[rmres].reg_c3_value; 3156141cc406Sopenharmony_ci regs[0xc6] = (regs[0xc6] & 0xf8) | resparms[rmres].reg_c6_value; 3157141cc406Sopenharmony_ci 3158141cc406Sopenharmony_ci rt_set_data_feed_off (regs); 3159141cc406Sopenharmony_ci 3160141cc406Sopenharmony_ci rt_set_all_registers (regs); 3161141cc406Sopenharmony_ci 3162141cc406Sopenharmony_ci rt_set_one_register (0x2c, regs[0x2c]); 3163141cc406Sopenharmony_ci 3164141cc406Sopenharmony_ci if (DBG_LEVEL >= 5) 3165141cc406Sopenharmony_ci dump_registers (regs); 3166141cc406Sopenharmony_ci 3167141cc406Sopenharmony_ci rt_start_moving (); 3168141cc406Sopenharmony_ci while (rt_is_moving ()); 3169141cc406Sopenharmony_ci } 3170141cc406Sopenharmony_ci } 3171141cc406Sopenharmony_ci } 3172141cc406Sopenharmony_ci 3173141cc406Sopenharmony_ci 3174141cc406Sopenharmony_ci rt_set_noscan_distance (regs, y * scan_frequency - 1); 3175141cc406Sopenharmony_ci rt_set_total_distance (regs, scan_frequency * (y + h) - 1); 3176141cc406Sopenharmony_ci 3177141cc406Sopenharmony_ci rt_set_scan_frequency (regs, scan_frequency); 3178141cc406Sopenharmony_ci 3179141cc406Sopenharmony_ci tg_setting = resparms[jres].tg; 3180141cc406Sopenharmony_ci 3181141cc406Sopenharmony_ci rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p); 3182141cc406Sopenharmony_ci rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp); 3183141cc406Sopenharmony_ci rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp); 3184141cc406Sopenharmony_ci 3185141cc406Sopenharmony_ci rt_set_one_register (0xc6, 0); 3186141cc406Sopenharmony_ci rt_set_one_register (0xc6, 0); 3187141cc406Sopenharmony_ci 3188141cc406Sopenharmony_ci rt_set_step_size (regs, resparms[jres].step_size); 3189141cc406Sopenharmony_ci 3190141cc406Sopenharmony_ci rt_set_motor_movement_clock_multiplier (regs, 3191141cc406Sopenharmony_ci resparms[jres]. 3192141cc406Sopenharmony_ci motor_movement_clock_multiplier); 3193141cc406Sopenharmony_ci 3194141cc406Sopenharmony_ci rt_set_cdss (regs, tg_info[tg_setting].tg_cdss1, 3195141cc406Sopenharmony_ci tg_info[tg_setting].tg_cdss2); 3196141cc406Sopenharmony_ci rt_set_cdsc (regs, tg_info[tg_setting].tg_cdsc1, 3197141cc406Sopenharmony_ci tg_info[tg_setting].tg_cdsc2); 3198141cc406Sopenharmony_ci rt_update_after_setting_cdss2 (regs); 3199141cc406Sopenharmony_ci 3200141cc406Sopenharmony_ci regs[0x39] = resparms[jres].reg_39_value; 3201141cc406Sopenharmony_ci regs[0xc3] = (regs[0xc3] & 0xf8) | resparms[jres].reg_c3_value; 3202141cc406Sopenharmony_ci regs[0xc6] = (regs[0xc6] & 0xf8) | resparms[jres].reg_c6_value; 3203141cc406Sopenharmony_ci 3204141cc406Sopenharmony_ci rt_set_data_feed_on (regs); 3205141cc406Sopenharmony_ci 3206141cc406Sopenharmony_ci rt_set_all_registers (regs); 3207141cc406Sopenharmony_ci 3208141cc406Sopenharmony_ci rt_set_one_register (0x2c, regs[0x2c]); 3209141cc406Sopenharmony_ci 3210141cc406Sopenharmony_ci if (DBG_LEVEL >= 5) 3211141cc406Sopenharmony_ci dump_registers (regs); 3212141cc406Sopenharmony_ci 3213141cc406Sopenharmony_ci result = rts8801_doscan (w, 3214141cc406Sopenharmony_ci h, 3215141cc406Sopenharmony_ci colour, 3216141cc406Sopenharmony_ci red_green_offset, 3217141cc406Sopenharmony_ci green_blue_offset, 3218141cc406Sopenharmony_ci intra_channel_offset, 3219141cc406Sopenharmony_ci cbfunc, param, (x & 1), calib_info, 3220141cc406Sopenharmony_ci (regs[0x2f] & 0x04) != 0, 3221141cc406Sopenharmony_ci postprocess_offsets, 3222141cc406Sopenharmony_ci postprocess_gains); 3223141cc406Sopenharmony_ci return result; 3224141cc406Sopenharmony_ci} 3225141cc406Sopenharmony_ci 3226141cc406Sopenharmony_cistatic int 3227141cc406Sopenharmony_ciaccumfunc (struct dcalibdata *dcd, int bytes, char *data) 3228141cc406Sopenharmony_ci{ 3229141cc406Sopenharmony_ci unsigned char *c = (unsigned char *) data; 3230141cc406Sopenharmony_ci 3231141cc406Sopenharmony_ci while (bytes > 0) 3232141cc406Sopenharmony_ci { 3233141cc406Sopenharmony_ci if (dcd->firstrowdone) 3234141cc406Sopenharmony_ci dcd->buffers[dcd->channelnow][dcd->pixelnow - dcd->pixelsperrow] = *c; 3235141cc406Sopenharmony_ci if (++dcd->channelnow >= 3) 3236141cc406Sopenharmony_ci { 3237141cc406Sopenharmony_ci dcd->channelnow = 0; 3238141cc406Sopenharmony_ci if (++dcd->pixelnow == dcd->pixelsperrow) 3239141cc406Sopenharmony_ci ++dcd->firstrowdone; 3240141cc406Sopenharmony_ci } 3241141cc406Sopenharmony_ci c++; 3242141cc406Sopenharmony_ci bytes--; 3243141cc406Sopenharmony_ci } 3244141cc406Sopenharmony_ci return 1; 3245141cc406Sopenharmony_ci} 3246141cc406Sopenharmony_ci 3247141cc406Sopenharmony_cistatic int 3248141cc406Sopenharmony_cicalcmedian (unsigned char const *data, 3249141cc406Sopenharmony_ci int pixel, int pixels_per_row, int elements) 3250141cc406Sopenharmony_ci{ 3251141cc406Sopenharmony_ci int tallies[256]; 3252141cc406Sopenharmony_ci int i; 3253141cc406Sopenharmony_ci int elemstogo = elements / 2; 3254141cc406Sopenharmony_ci 3255141cc406Sopenharmony_ci memset (tallies, 0, sizeof (tallies)); 3256141cc406Sopenharmony_ci data += pixel; 3257141cc406Sopenharmony_ci for (i = 0; i < elements; ++i) 3258141cc406Sopenharmony_ci { 3259141cc406Sopenharmony_ci ++tallies[*data]; 3260141cc406Sopenharmony_ci data += pixels_per_row; 3261141cc406Sopenharmony_ci } 3262141cc406Sopenharmony_ci i = 0; 3263141cc406Sopenharmony_ci while (elemstogo - tallies[i] > 0) 3264141cc406Sopenharmony_ci elemstogo -= tallies[i++]; 3265141cc406Sopenharmony_ci return i; 3266141cc406Sopenharmony_ci} 3267141cc406Sopenharmony_ci 3268141cc406Sopenharmony_cistruct calibdata 3269141cc406Sopenharmony_ci{ 3270141cc406Sopenharmony_ci unsigned char *buffer; 3271141cc406Sopenharmony_ci int space; 3272141cc406Sopenharmony_ci}; 3273141cc406Sopenharmony_ci 3274141cc406Sopenharmony_cistatic int 3275141cc406Sopenharmony_cistorefunc (struct calibdata *cd, int bytes, char *data) 3276141cc406Sopenharmony_ci{ 3277141cc406Sopenharmony_ci if (cd->space > 0) 3278141cc406Sopenharmony_ci { 3279141cc406Sopenharmony_ci if (bytes > cd->space) 3280141cc406Sopenharmony_ci bytes = cd->space; 3281141cc406Sopenharmony_ci memcpy (cd->buffer, data, bytes); 3282141cc406Sopenharmony_ci cd->buffer += bytes; 3283141cc406Sopenharmony_ci cd->space -= bytes; 3284141cc406Sopenharmony_ci } 3285141cc406Sopenharmony_ci return 1; 3286141cc406Sopenharmony_ci} 3287141cc406Sopenharmony_ci 3288141cc406Sopenharmony_cistatic unsigned 3289141cc406Sopenharmony_cisum_channel (unsigned char *p, int n, int bytwo) 3290141cc406Sopenharmony_ci{ 3291141cc406Sopenharmony_ci unsigned v = 0; 3292141cc406Sopenharmony_ci 3293141cc406Sopenharmony_ci while (n-- > 0) 3294141cc406Sopenharmony_ci { 3295141cc406Sopenharmony_ci v += *p; 3296141cc406Sopenharmony_ci p += 3; 3297141cc406Sopenharmony_ci if (bytwo) 3298141cc406Sopenharmony_ci p += 3; 3299141cc406Sopenharmony_ci } 3300141cc406Sopenharmony_ci return v; 3301141cc406Sopenharmony_ci} 3302141cc406Sopenharmony_ci 3303141cc406Sopenharmony_cistatic int do_warmup = 1; 3304141cc406Sopenharmony_ci 3305141cc406Sopenharmony_ci#define DETAILED_PASS_COUNT 3 3306141cc406Sopenharmony_ci#define DETAILED_PASS_OFFSETS 0 3307141cc406Sopenharmony_ci#define DETAILED_PASS_GAINS_FIRSTPASS 1 3308141cc406Sopenharmony_ci#define DETAILED_PASS_GAINS_SECONDPASS 2 3309141cc406Sopenharmony_ci 3310141cc406Sopenharmony_cistatic int 3311141cc406Sopenharmony_cirts8801_scan (unsigned x, 3312141cc406Sopenharmony_ci unsigned y, 3313141cc406Sopenharmony_ci unsigned w, 3314141cc406Sopenharmony_ci unsigned h, 3315141cc406Sopenharmony_ci unsigned resolution, 3316141cc406Sopenharmony_ci unsigned colour, 3317141cc406Sopenharmony_ci unsigned brightness, 3318141cc406Sopenharmony_ci unsigned contrast, 3319141cc406Sopenharmony_ci rts8801_callback cbfunc, 3320141cc406Sopenharmony_ci void *param, 3321141cc406Sopenharmony_ci double gamma) 3322141cc406Sopenharmony_ci{ 3323141cc406Sopenharmony_ci unsigned char calib_info[9]; 3324141cc406Sopenharmony_ci unsigned char calibbuf[2400]; 3325141cc406Sopenharmony_ci struct dcalibdata dcd; 3326141cc406Sopenharmony_ci struct calibdata cd; 3327141cc406Sopenharmony_ci unsigned char *detail_buffer = 0; 3328141cc406Sopenharmony_ci int iCalibY; 3329141cc406Sopenharmony_ci int iCalibTarget; 3330141cc406Sopenharmony_ci int iMoveFlags = 0; 3331141cc406Sopenharmony_ci unsigned aiBestOffset[6]; 3332141cc406Sopenharmony_ci int aiPassed[6]; 3333141cc406Sopenharmony_ci int i; 3334141cc406Sopenharmony_ci unsigned j; 3335141cc406Sopenharmony_ci int k; 3336141cc406Sopenharmony_ci int calibration_size; 3337141cc406Sopenharmony_ci unsigned char *pDetailedCalib; 3338141cc406Sopenharmony_ci int red_calibration_offset; 3339141cc406Sopenharmony_ci int green_calibration_offset; 3340141cc406Sopenharmony_ci int blue_calibration_offset; 3341141cc406Sopenharmony_ci int end_calibration_offset; 3342141cc406Sopenharmony_ci int base_resolution; 3343141cc406Sopenharmony_ci int resolution_divisor; 3344141cc406Sopenharmony_ci int resolution_index; 3345141cc406Sopenharmony_ci int detailed_calibration_rows = 50; 3346141cc406Sopenharmony_ci unsigned char *tdetail_buffer; 3347141cc406Sopenharmony_ci int pass; 3348141cc406Sopenharmony_ci int onechanged; 3349141cc406Sopenharmony_ci double *postprocess_gains; 3350141cc406Sopenharmony_ci double *postprocess_offsets; 3351141cc406Sopenharmony_ci int needs_postprocessed_calibration = 0; 3352141cc406Sopenharmony_ci double contrast_adjust = (double) contrast / 64; 3353141cc406Sopenharmony_ci int brightness_adjust = brightness - 0x80; 3354141cc406Sopenharmony_ci 3355141cc406Sopenharmony_ci /* Initialise and power up */ 3356141cc406Sopenharmony_ci 3357141cc406Sopenharmony_ci rt_set_all_registers (initial_regs); 3358141cc406Sopenharmony_ci rt_set_powersave_mode (0); 3359141cc406Sopenharmony_ci 3360141cc406Sopenharmony_ci /* Initial rewind in case scanner is stuck away from home position */ 3361141cc406Sopenharmony_ci 3362141cc406Sopenharmony_ci rts8801_rewind (); 3363141cc406Sopenharmony_ci 3364141cc406Sopenharmony_ci /* Detect SRAM */ 3365141cc406Sopenharmony_ci 3366141cc406Sopenharmony_ci rt_detect_sram (&local_sram_size, &r93setting); 3367141cc406Sopenharmony_ci 3368141cc406Sopenharmony_ci /* Warm up the lamp */ 3369141cc406Sopenharmony_ci 3370141cc406Sopenharmony_ci DBG (10, "Warming up the lamp\n"); 3371141cc406Sopenharmony_ci 3372141cc406Sopenharmony_ci rt_turn_on_lamp (); 3373141cc406Sopenharmony_ci if (do_warmup) 3374141cc406Sopenharmony_ci sleep (25); 3375141cc406Sopenharmony_ci 3376141cc406Sopenharmony_ci /* Basic calibration */ 3377141cc406Sopenharmony_ci 3378141cc406Sopenharmony_ci DBG (10, "Calibrating (stage 1)\n"); 3379141cc406Sopenharmony_ci 3380141cc406Sopenharmony_ci calib_info[2] = calib_info[5] = calib_info[8] = 1; 3381141cc406Sopenharmony_ci 3382141cc406Sopenharmony_ci iCalibY = (resolution == 25) ? 1 : 2; 3383141cc406Sopenharmony_ci iCalibTarget = 550; 3384141cc406Sopenharmony_ci 3385141cc406Sopenharmony_ci rt_turn_off_lamp(); 3386141cc406Sopenharmony_ci 3387141cc406Sopenharmony_ci for (i = 0; i < 6; ++i) 3388141cc406Sopenharmony_ci { 3389141cc406Sopenharmony_ci aiBestOffset[i] = 0xbf; 3390141cc406Sopenharmony_ci aiPassed[i] = 0; 3391141cc406Sopenharmony_ci } 3392141cc406Sopenharmony_ci 3393141cc406Sopenharmony_ci do 3394141cc406Sopenharmony_ci { 3395141cc406Sopenharmony_ci DBG (30, "Initial calibration pass commences\n"); 3396141cc406Sopenharmony_ci 3397141cc406Sopenharmony_ci onechanged = 0; 3398141cc406Sopenharmony_ci for (i = 0; i < 3; ++i) 3399141cc406Sopenharmony_ci { 3400141cc406Sopenharmony_ci calib_info[i * 3] = aiBestOffset[i]; 3401141cc406Sopenharmony_ci calib_info[i * 3 + 1] = aiBestOffset[i + 3]; 3402141cc406Sopenharmony_ci } 3403141cc406Sopenharmony_ci 3404141cc406Sopenharmony_ci cd.buffer = calibbuf; 3405141cc406Sopenharmony_ci cd.space = sizeof (calibbuf); 3406141cc406Sopenharmony_ci DBG (30, "Commencing scan for initial calibration pass\n"); 3407141cc406Sopenharmony_ci rts8801_fullscan (1401, iCalibY, 100, 2, 400, resolution, 3408141cc406Sopenharmony_ci HP3500_COLOR_SCAN, (rts8801_callback) storefunc, &cd, 3409141cc406Sopenharmony_ci calib_info, iMoveFlags, -1, -1, -1, -1, 0, 0); 3410141cc406Sopenharmony_ci DBG (30, "Completed scan for initial calibration pass\n"); 3411141cc406Sopenharmony_ci iMoveFlags = RTS8801_F_SUPPRESS_MOVEMENT | RTS8801_F_NO_DISPLACEMENTS; 3412141cc406Sopenharmony_ci iCalibY = 2; 3413141cc406Sopenharmony_ci 3414141cc406Sopenharmony_ci for (i = 0; i < 6; ++i) 3415141cc406Sopenharmony_ci { 3416141cc406Sopenharmony_ci int sum; 3417141cc406Sopenharmony_ci 3418141cc406Sopenharmony_ci if (aiBestOffset[i] >= 255 || aiPassed[i] > 2) 3419141cc406Sopenharmony_ci continue; 3420141cc406Sopenharmony_ci sum = sum_channel (calibbuf + i, 50, 1); 3421141cc406Sopenharmony_ci DBG (20, "channel[%d] sum = %d (target %d)\n", i, sum, 3422141cc406Sopenharmony_ci iCalibTarget); 3423141cc406Sopenharmony_ci 3424141cc406Sopenharmony_ci if (sum < iCalibTarget) 3425141cc406Sopenharmony_ci { 3426141cc406Sopenharmony_ci onechanged = 1; 3427141cc406Sopenharmony_ci ++aiBestOffset[i]; 3428141cc406Sopenharmony_ci } 3429141cc406Sopenharmony_ci else 3430141cc406Sopenharmony_ci { 3431141cc406Sopenharmony_ci ++aiPassed[i]; 3432141cc406Sopenharmony_ci } 3433141cc406Sopenharmony_ci } 3434141cc406Sopenharmony_ci DBG (30, "Initial calibration pass completed\n"); 3435141cc406Sopenharmony_ci } 3436141cc406Sopenharmony_ci while (onechanged); 3437141cc406Sopenharmony_ci 3438141cc406Sopenharmony_ci DBG (20, "Offsets calculated\n"); 3439141cc406Sopenharmony_ci 3440141cc406Sopenharmony_ci rt_turn_on_lamp(); 3441141cc406Sopenharmony_ci usleep(500000); 3442141cc406Sopenharmony_ci 3443141cc406Sopenharmony_ci tdetail_buffer = 3444141cc406Sopenharmony_ci (unsigned char *) malloc (w * 3 * detailed_calibration_rows); 3445141cc406Sopenharmony_ci 3446141cc406Sopenharmony_ci for (i = 0; i < 3; ++i) 3447141cc406Sopenharmony_ci { 3448141cc406Sopenharmony_ci calib_info[i * 3 + 2] = 1; 3449141cc406Sopenharmony_ci aiPassed[i] = 0; 3450141cc406Sopenharmony_ci } 3451141cc406Sopenharmony_ci 3452141cc406Sopenharmony_ci do 3453141cc406Sopenharmony_ci { 3454141cc406Sopenharmony_ci struct dcalibdata dcdt; 3455141cc406Sopenharmony_ci 3456141cc406Sopenharmony_ci dcdt.buffers[0] = tdetail_buffer; 3457141cc406Sopenharmony_ci dcdt.buffers[1] = (tdetail_buffer + w * detailed_calibration_rows); 3458141cc406Sopenharmony_ci dcdt.buffers[2] = (dcdt.buffers[1] + w * detailed_calibration_rows); 3459141cc406Sopenharmony_ci dcdt.pixelsperrow = w; 3460141cc406Sopenharmony_ci dcdt.pixelnow = dcdt.channelnow = dcdt.firstrowdone = 0; 3461141cc406Sopenharmony_ci DBG (20, "Scanning for part 2 of initial calibration\n"); 3462141cc406Sopenharmony_ci rts8801_fullscan (x, 4, w, detailed_calibration_rows + 1, resolution, 3463141cc406Sopenharmony_ci resolution, HP3500_COLOR_SCAN, 3464141cc406Sopenharmony_ci (rts8801_callback) accumfunc, &dcdt, calib_info, 3465141cc406Sopenharmony_ci RTS8801_F_SUPPRESS_MOVEMENT | RTS8801_F_NO_DISPLACEMENTS, -1, -1, -1, -1, 0, 0); 3466141cc406Sopenharmony_ci DBG (20, "Scan for part 2 of initial calibration completed\n"); 3467141cc406Sopenharmony_ci 3468141cc406Sopenharmony_ci onechanged = 0; 3469141cc406Sopenharmony_ci for (i = 0; i < 3; ++i) 3470141cc406Sopenharmony_ci { 3471141cc406Sopenharmony_ci int largest = 1; 3472141cc406Sopenharmony_ci 3473141cc406Sopenharmony_ci if (aiPassed[i] > 2 || calib_info[i * 3 + 2] >= 63) 3474141cc406Sopenharmony_ci continue; 3475141cc406Sopenharmony_ci 3476141cc406Sopenharmony_ci for (j = 0; j < w; ++j) 3477141cc406Sopenharmony_ci { 3478141cc406Sopenharmony_ci int val = 3479141cc406Sopenharmony_ci calcmedian (dcdt.buffers[i], j, w, detailed_calibration_rows); 3480141cc406Sopenharmony_ci 3481141cc406Sopenharmony_ci if (val > largest) 3482141cc406Sopenharmony_ci largest = val; 3483141cc406Sopenharmony_ci } 3484141cc406Sopenharmony_ci 3485141cc406Sopenharmony_ci if (largest < 0xe0) 3486141cc406Sopenharmony_ci { 3487141cc406Sopenharmony_ci ++calib_info[i * 3 + 2]; 3488141cc406Sopenharmony_ci onechanged = 1; 3489141cc406Sopenharmony_ci } 3490141cc406Sopenharmony_ci else 3491141cc406Sopenharmony_ci { 3492141cc406Sopenharmony_ci ++aiPassed[i]; 3493141cc406Sopenharmony_ci } 3494141cc406Sopenharmony_ci } 3495141cc406Sopenharmony_ci } 3496141cc406Sopenharmony_ci while (onechanged); 3497141cc406Sopenharmony_ci 3498141cc406Sopenharmony_ci for (i = 0; i < 3; ++i) 3499141cc406Sopenharmony_ci { 3500141cc406Sopenharmony_ci DBG (10, "Channel [%d] gain=%02x offset=%02x\n", 3501141cc406Sopenharmony_ci i, calib_info[i * 3] + 2, calib_info[i * 3]); 3502141cc406Sopenharmony_ci } 3503141cc406Sopenharmony_ci 3504141cc406Sopenharmony_ci DBG (20, "Gain factors calculated\n"); 3505141cc406Sopenharmony_ci 3506141cc406Sopenharmony_ci /* Stage 2 calibration */ 3507141cc406Sopenharmony_ci 3508141cc406Sopenharmony_ci DBG (10, "Calibrating (stage 2)\n"); 3509141cc406Sopenharmony_ci 3510141cc406Sopenharmony_ci detail_buffer = 3511141cc406Sopenharmony_ci (unsigned char *) malloc (w * 3 * detailed_calibration_rows); 3512141cc406Sopenharmony_ci 3513141cc406Sopenharmony_ci dcd.buffers[0] = detail_buffer; 3514141cc406Sopenharmony_ci dcd.buffers[1] = (detail_buffer + w * detailed_calibration_rows); 3515141cc406Sopenharmony_ci dcd.buffers[2] = (dcd.buffers[1] + w * detailed_calibration_rows); 3516141cc406Sopenharmony_ci dcd.pixelsperrow = w; 3517141cc406Sopenharmony_ci 3518141cc406Sopenharmony_ci 3519141cc406Sopenharmony_ci /* And now for the detailed calibration */ 3520141cc406Sopenharmony_ci resolution_index = find_resolution_index (resolution); 3521141cc406Sopenharmony_ci base_resolution = 300; 3522141cc406Sopenharmony_ci if (resparms[resolution_index].cph0s) 3523141cc406Sopenharmony_ci base_resolution *= 2; 3524141cc406Sopenharmony_ci if (resparms[resolution_index].d3_bit_3_value) 3525141cc406Sopenharmony_ci base_resolution *= 2; 3526141cc406Sopenharmony_ci resolution_divisor = base_resolution / resolution; 3527141cc406Sopenharmony_ci 3528141cc406Sopenharmony_ci calibration_size = w * resolution_divisor * 6 + 1568 + 96; 3529141cc406Sopenharmony_ci red_calibration_offset = 0x600; 3530141cc406Sopenharmony_ci green_calibration_offset = 3531141cc406Sopenharmony_ci red_calibration_offset + w * resolution_divisor * 2; 3532141cc406Sopenharmony_ci blue_calibration_offset = 3533141cc406Sopenharmony_ci green_calibration_offset + w * resolution_divisor * 2; 3534141cc406Sopenharmony_ci end_calibration_offset = 3535141cc406Sopenharmony_ci blue_calibration_offset + w * resolution_divisor * 2; 3536141cc406Sopenharmony_ci pDetailedCalib = (unsigned char *) malloc (calibration_size); 3537141cc406Sopenharmony_ci 3538141cc406Sopenharmony_ci memset (pDetailedCalib, 0, calibration_size); 3539141cc406Sopenharmony_ci 3540141cc406Sopenharmony_ci for (i = 0; i < 3; ++i) 3541141cc406Sopenharmony_ci { 3542141cc406Sopenharmony_ci int idx = 3543141cc406Sopenharmony_ci (i == 0) ? red_calibration_offset : 3544141cc406Sopenharmony_ci (i == 1) ? green_calibration_offset : 3545141cc406Sopenharmony_ci blue_calibration_offset; 3546141cc406Sopenharmony_ci 3547141cc406Sopenharmony_ci for (j = 0; j < 256; j++) 3548141cc406Sopenharmony_ci { 3549141cc406Sopenharmony_ci /* Gamma table - appears to be 256 byte pairs for each input 3550141cc406Sopenharmony_ci * range (so the first entry cover inputs in the range 0 to 1, 3551141cc406Sopenharmony_ci * the second 1 to 2, and so on), mapping that input range 3552141cc406Sopenharmony_ci * (including the fractional parts within it) to an output 3553141cc406Sopenharmony_ci * range. 3554141cc406Sopenharmony_ci */ 3555141cc406Sopenharmony_ci pDetailedCalib[i * 512 + j * 2] = j; 3556141cc406Sopenharmony_ci pDetailedCalib[i * 512 + j * 2 + 1] = j; 3557141cc406Sopenharmony_ci } 3558141cc406Sopenharmony_ci 3559141cc406Sopenharmony_ci for (j = 0; j < w; ++j) 3560141cc406Sopenharmony_ci { 3561141cc406Sopenharmony_ci for (k = 0; k < resolution_divisor; ++k) 3562141cc406Sopenharmony_ci { 3563141cc406Sopenharmony_ci pDetailedCalib[idx++] = 0; 3564141cc406Sopenharmony_ci pDetailedCalib[idx++] = 0x80; 3565141cc406Sopenharmony_ci } 3566141cc406Sopenharmony_ci } 3567141cc406Sopenharmony_ci } 3568141cc406Sopenharmony_ci 3569141cc406Sopenharmony_ci rt_set_sram_page (0); 3570141cc406Sopenharmony_ci rt_set_one_register (0x93, r93setting); 3571141cc406Sopenharmony_ci rt_write_sram (calibration_size, pDetailedCalib); 3572141cc406Sopenharmony_ci 3573141cc406Sopenharmony_ci postprocess_gains = (double *) malloc(sizeof(double) * 3 * w); 3574141cc406Sopenharmony_ci postprocess_offsets = (double *) malloc(sizeof(double) * 3 * w); 3575141cc406Sopenharmony_ci 3576141cc406Sopenharmony_ci for (pass = 0; pass < DETAILED_PASS_COUNT; ++pass) 3577141cc406Sopenharmony_ci { 3578141cc406Sopenharmony_ci int ppidx = 0; 3579141cc406Sopenharmony_ci 3580141cc406Sopenharmony_ci DBG (10, "Performing detailed calibration scan %d\n", pass); 3581141cc406Sopenharmony_ci 3582141cc406Sopenharmony_ci switch (pass) 3583141cc406Sopenharmony_ci { 3584141cc406Sopenharmony_ci case DETAILED_PASS_OFFSETS: 3585141cc406Sopenharmony_ci rt_turn_off_lamp(); 3586141cc406Sopenharmony_ci usleep(500000); /* To be sure it has gone off */ 3587141cc406Sopenharmony_ci break; 3588141cc406Sopenharmony_ci 3589141cc406Sopenharmony_ci case DETAILED_PASS_GAINS_FIRSTPASS: 3590141cc406Sopenharmony_ci rt_turn_on_lamp(); 3591141cc406Sopenharmony_ci usleep(500000); /* Give the lamp time to settle */ 3592141cc406Sopenharmony_ci break; 3593141cc406Sopenharmony_ci } 3594141cc406Sopenharmony_ci 3595141cc406Sopenharmony_ci dcd.pixelnow = dcd.channelnow = dcd.firstrowdone = 0; 3596141cc406Sopenharmony_ci rts8801_fullscan (x, iCalibY, w, detailed_calibration_rows + 1, 3597141cc406Sopenharmony_ci resolution, resolution, HP3500_COLOR_SCAN, 3598141cc406Sopenharmony_ci (rts8801_callback) accumfunc, &dcd, 3599141cc406Sopenharmony_ci calib_info, 3600141cc406Sopenharmony_ci RTS8801_F_SUPPRESS_MOVEMENT | RTS8801_F_NO_DISPLACEMENTS, 3601141cc406Sopenharmony_ci red_calibration_offset, 3602141cc406Sopenharmony_ci green_calibration_offset, 3603141cc406Sopenharmony_ci blue_calibration_offset, 3604141cc406Sopenharmony_ci end_calibration_offset, 3605141cc406Sopenharmony_ci 0, 0); 3606141cc406Sopenharmony_ci 3607141cc406Sopenharmony_ci DBG (10, " Detailed calibration scan %d completed\n", pass); 3608141cc406Sopenharmony_ci 3609141cc406Sopenharmony_ci for (i = 0; i < 3; ++i) 3610141cc406Sopenharmony_ci { 3611141cc406Sopenharmony_ci int idx = 3612141cc406Sopenharmony_ci (i == 0) ? red_calibration_offset : 3613141cc406Sopenharmony_ci (i == 1) ? green_calibration_offset : 3614141cc406Sopenharmony_ci blue_calibration_offset; 3615141cc406Sopenharmony_ci 3616141cc406Sopenharmony_ci for (j = 0; j < w; ++j) 3617141cc406Sopenharmony_ci { 3618141cc406Sopenharmony_ci double multnow = 0x80; 3619141cc406Sopenharmony_ci int offnow = 0; 3620141cc406Sopenharmony_ci 3621141cc406Sopenharmony_ci /* This seems to be the approach for reg 0x40 & 0x3f == 0x27, which allows detailed 3622141cc406Sopenharmony_ci * calibration to return either higher or lower values. 3623141cc406Sopenharmony_ci */ 3624141cc406Sopenharmony_ci 3625141cc406Sopenharmony_ci { 3626141cc406Sopenharmony_ci double denom1 = 3627141cc406Sopenharmony_ci calcmedian (dcd.buffers[i], j, w, detailed_calibration_rows); 3628141cc406Sopenharmony_ci 3629141cc406Sopenharmony_ci switch (pass) 3630141cc406Sopenharmony_ci { 3631141cc406Sopenharmony_ci case DETAILED_PASS_OFFSETS: 3632141cc406Sopenharmony_ci /* The offset is the number needed to be subtracted from "black" at detailed gain = 0x80, 3633141cc406Sopenharmony_ci * which is the value we started with. For the next round, pull the gain down to 0x20. Our 3634141cc406Sopenharmony_ci * next scan is a test scan to confirm the offset works. 3635141cc406Sopenharmony_ci */ 3636141cc406Sopenharmony_ci multnow = 0x20; 3637141cc406Sopenharmony_ci offnow = denom1; 3638141cc406Sopenharmony_ci break; 3639141cc406Sopenharmony_ci 3640141cc406Sopenharmony_ci case DETAILED_PASS_GAINS_FIRSTPASS: 3641141cc406Sopenharmony_ci multnow = 128.0 / denom1 * 0x20; /* Then bring it up to whatever we need to hit 192 */ 3642141cc406Sopenharmony_ci if (multnow > 255) 3643141cc406Sopenharmony_ci multnow = 255; 3644141cc406Sopenharmony_ci offnow = pDetailedCalib[idx]; 3645141cc406Sopenharmony_ci break; 3646141cc406Sopenharmony_ci 3647141cc406Sopenharmony_ci case DETAILED_PASS_GAINS_SECONDPASS: 3648141cc406Sopenharmony_ci multnow = 255.0 / denom1 * contrast_adjust * pDetailedCalib[idx+1]; /* And finally to 255 */ 3649141cc406Sopenharmony_ci offnow = pDetailedCalib[idx] - brightness_adjust * 0x80 / multnow; 3650141cc406Sopenharmony_ci 3651141cc406Sopenharmony_ci if (offnow < 0) 3652141cc406Sopenharmony_ci { 3653141cc406Sopenharmony_ci postprocess_offsets[ppidx] = multnow * offnow / 0x80; 3654141cc406Sopenharmony_ci offnow = 0; 3655141cc406Sopenharmony_ci needs_postprocessed_calibration = 1; 3656141cc406Sopenharmony_ci } 3657141cc406Sopenharmony_ci else if (offnow > 255) 3658141cc406Sopenharmony_ci { 3659141cc406Sopenharmony_ci postprocess_offsets[ppidx] = multnow * (offnow - 255) / 0x80; 3660141cc406Sopenharmony_ci offnow = 255; 3661141cc406Sopenharmony_ci needs_postprocessed_calibration = 1; 3662141cc406Sopenharmony_ci } 3663141cc406Sopenharmony_ci else 3664141cc406Sopenharmony_ci { 3665141cc406Sopenharmony_ci postprocess_offsets[ppidx] = 0; 3666141cc406Sopenharmony_ci } 3667141cc406Sopenharmony_ci if (multnow > 255) 3668141cc406Sopenharmony_ci { 3669141cc406Sopenharmony_ci postprocess_gains[ppidx] = multnow / 255; 3670141cc406Sopenharmony_ci multnow = 255; 3671141cc406Sopenharmony_ci needs_postprocessed_calibration = 1; 3672141cc406Sopenharmony_ci } 3673141cc406Sopenharmony_ci else 3674141cc406Sopenharmony_ci { 3675141cc406Sopenharmony_ci postprocess_gains[ppidx] = 1.0; 3676141cc406Sopenharmony_ci } 3677141cc406Sopenharmony_ci break; 3678141cc406Sopenharmony_ci } 3679141cc406Sopenharmony_ci } 3680141cc406Sopenharmony_ci if (offnow > 255) 3681141cc406Sopenharmony_ci offnow = 255; 3682141cc406Sopenharmony_ci 3683141cc406Sopenharmony_ci for (k = 0; k < resolution_divisor; ++k) 3684141cc406Sopenharmony_ci { 3685141cc406Sopenharmony_ci pDetailedCalib[idx++] = offnow; /* Subtract this value from the result at gains = 0x80*/ 3686141cc406Sopenharmony_ci pDetailedCalib[idx++] = multnow; /* Then multiply by this value divided by 0x80 */ 3687141cc406Sopenharmony_ci } 3688141cc406Sopenharmony_ci ++ppidx; 3689141cc406Sopenharmony_ci } 3690141cc406Sopenharmony_ci } 3691141cc406Sopenharmony_ci 3692141cc406Sopenharmony_ci if (pass == DETAILED_PASS_GAINS_SECONDPASS) 3693141cc406Sopenharmony_ci { 3694141cc406Sopenharmony_ci /* Build gamma table */ 3695141cc406Sopenharmony_ci unsigned char *redgamma = pDetailedCalib; 3696141cc406Sopenharmony_ci unsigned char *greengamma = redgamma + 512; 3697141cc406Sopenharmony_ci unsigned char *bluegamma = greengamma + 512; 3698141cc406Sopenharmony_ci double val; 3699141cc406Sopenharmony_ci double invgamma = 1.0l / gamma; 3700141cc406Sopenharmony_ci 3701141cc406Sopenharmony_ci *redgamma++ = *bluegamma++ = *greengamma++ = 0; 3702141cc406Sopenharmony_ci 3703141cc406Sopenharmony_ci /* The windows driver does a linear interpolation for the next 19 boundaries */ 3704141cc406Sopenharmony_ci val = pow (20.0l / 255, invgamma) * 255; 3705141cc406Sopenharmony_ci 3706141cc406Sopenharmony_ci for (j = 1; j <= 20; ++j) 3707141cc406Sopenharmony_ci { 3708141cc406Sopenharmony_ci *redgamma++ = *bluegamma++ = *greengamma++ = val * j / 20 + 0.5; 3709141cc406Sopenharmony_ci *redgamma++ = *bluegamma++ = *greengamma++ = val * j / 20 + 0.5; 3710141cc406Sopenharmony_ci } 3711141cc406Sopenharmony_ci 3712141cc406Sopenharmony_ci for (; j <= 255; ++j) 3713141cc406Sopenharmony_ci { 3714141cc406Sopenharmony_ci val = pow((double) j / 255, invgamma) * 255; 3715141cc406Sopenharmony_ci 3716141cc406Sopenharmony_ci *redgamma++ = *bluegamma++ = *greengamma++ = val + 0.5; 3717141cc406Sopenharmony_ci *redgamma++ = *bluegamma++ = *greengamma++ = val + 0.5; 3718141cc406Sopenharmony_ci } 3719141cc406Sopenharmony_ci *redgamma++ = *bluegamma++ = *greengamma++ = 255; 3720141cc406Sopenharmony_ci } 3721141cc406Sopenharmony_ci 3722141cc406Sopenharmony_ci DBG (10, "\n"); 3723141cc406Sopenharmony_ci 3724141cc406Sopenharmony_ci rt_set_sram_page (0); 3725141cc406Sopenharmony_ci rt_set_one_register (0x93, r93setting); 3726141cc406Sopenharmony_ci rt_write_sram (calibration_size, pDetailedCalib); 3727141cc406Sopenharmony_ci } 3728141cc406Sopenharmony_ci 3729141cc406Sopenharmony_ci /* And finally, perform the scan */ 3730141cc406Sopenharmony_ci DBG (10, "Scanning\n"); 3731141cc406Sopenharmony_ci 3732141cc406Sopenharmony_ci rts8801_rewind (); 3733141cc406Sopenharmony_ci 3734141cc406Sopenharmony_ci rts8801_fullscan (x, y, w, h, resolution, resolution, colour, cbfunc, param, 3735141cc406Sopenharmony_ci calib_info, 0, 3736141cc406Sopenharmony_ci red_calibration_offset, green_calibration_offset, 3737141cc406Sopenharmony_ci blue_calibration_offset, end_calibration_offset, 3738141cc406Sopenharmony_ci needs_postprocessed_calibration ? postprocess_offsets : 0, 3739141cc406Sopenharmony_ci needs_postprocessed_calibration ? postprocess_gains : 0); 3740141cc406Sopenharmony_ci 3741141cc406Sopenharmony_ci rt_turn_off_lamp (); 3742141cc406Sopenharmony_ci 3743141cc406Sopenharmony_ci rts8801_rewind (); 3744141cc406Sopenharmony_ci rt_set_powersave_mode (1); 3745141cc406Sopenharmony_ci 3746141cc406Sopenharmony_ci if (pDetailedCalib) 3747141cc406Sopenharmony_ci free (pDetailedCalib); 3748141cc406Sopenharmony_ci if (detail_buffer) 3749141cc406Sopenharmony_ci free (detail_buffer); 3750141cc406Sopenharmony_ci if (tdetail_buffer) 3751141cc406Sopenharmony_ci free(tdetail_buffer); 3752141cc406Sopenharmony_ci if (postprocess_gains) 3753141cc406Sopenharmony_ci free(postprocess_gains); 3754141cc406Sopenharmony_ci if (postprocess_offsets) 3755141cc406Sopenharmony_ci free(postprocess_offsets); 3756141cc406Sopenharmony_ci return 0; 3757141cc406Sopenharmony_ci} 3758141cc406Sopenharmony_ci 3759141cc406Sopenharmony_cistatic int 3760141cc406Sopenharmony_ciwritefunc (struct hp3500_write_info *winfo, int bytes, char *data) 3761141cc406Sopenharmony_ci{ 3762141cc406Sopenharmony_ci static int warned = 0; 3763141cc406Sopenharmony_ci 3764141cc406Sopenharmony_ci if (bytes > winfo->bytesleft) 3765141cc406Sopenharmony_ci { 3766141cc406Sopenharmony_ci if (!warned) 3767141cc406Sopenharmony_ci { 3768141cc406Sopenharmony_ci warned = 1; 3769141cc406Sopenharmony_ci DBG (1, "Overflow protection triggered\n"); 3770141cc406Sopenharmony_ci rt_stop_moving (); 3771141cc406Sopenharmony_ci } 3772141cc406Sopenharmony_ci bytes = winfo->bytesleft; 3773141cc406Sopenharmony_ci if (!bytes) 3774141cc406Sopenharmony_ci return 0; 3775141cc406Sopenharmony_ci } 3776141cc406Sopenharmony_ci winfo->bytesleft -= bytes; 3777141cc406Sopenharmony_ci return write (winfo->scanner->pipe_w, data, bytes) == bytes; 3778141cc406Sopenharmony_ci} 3779141cc406Sopenharmony_ci 3780141cc406Sopenharmony_ci#ifdef _POSIX_SOURCE 3781141cc406Sopenharmony_cistatic void 3782141cc406Sopenharmony_cisigtermHandler (int signal) 3783141cc406Sopenharmony_ci{ 3784141cc406Sopenharmony_ci (void) signal; /* get rid of compiler warning */ 3785141cc406Sopenharmony_ci cancelled_scan = 1; 3786141cc406Sopenharmony_ci} 3787141cc406Sopenharmony_ci#endif 3788141cc406Sopenharmony_ci 3789141cc406Sopenharmony_cistatic int 3790141cc406Sopenharmony_cireader_process (void *pv) 3791141cc406Sopenharmony_ci{ 3792141cc406Sopenharmony_ci struct hp3500_data *scanner = pv; 3793141cc406Sopenharmony_ci time_t t; 3794141cc406Sopenharmony_ci sigset_t ignore_set; 3795141cc406Sopenharmony_ci sigset_t sigterm_set; 3796141cc406Sopenharmony_ci struct SIGACTION act; 3797141cc406Sopenharmony_ci struct hp3500_write_info winfo; 3798141cc406Sopenharmony_ci int status; 3799141cc406Sopenharmony_ci 3800141cc406Sopenharmony_ci if (sanei_thread_is_forked ()) 3801141cc406Sopenharmony_ci { 3802141cc406Sopenharmony_ci close (scanner->pipe_r); 3803141cc406Sopenharmony_ci 3804141cc406Sopenharmony_ci sigfillset (&ignore_set); 3805141cc406Sopenharmony_ci sigdelset (&ignore_set, SIGTERM); 3806141cc406Sopenharmony_ci#if defined (__APPLE__) && defined (__MACH__) 3807141cc406Sopenharmony_ci sigdelset (&ignore_set, SIGUSR2); 3808141cc406Sopenharmony_ci#endif 3809141cc406Sopenharmony_ci sigprocmask (SIG_SETMASK, &ignore_set, 0); 3810141cc406Sopenharmony_ci 3811141cc406Sopenharmony_ci sigemptyset (&sigterm_set); 3812141cc406Sopenharmony_ci sigaddset (&sigterm_set, SIGTERM); 3813141cc406Sopenharmony_ci 3814141cc406Sopenharmony_ci memset (&act, 0, sizeof (act)); 3815141cc406Sopenharmony_ci#ifdef _POSIX_SOURCE 3816141cc406Sopenharmony_ci act.sa_handler = sigtermHandler; 3817141cc406Sopenharmony_ci#endif 3818141cc406Sopenharmony_ci sigaction (SIGTERM, &act, 0); 3819141cc406Sopenharmony_ci } 3820141cc406Sopenharmony_ci 3821141cc406Sopenharmony_ci /* Warm up the lamp again if our last scan ended more than 5 minutes ago. */ 3822141cc406Sopenharmony_ci time (&t); 3823141cc406Sopenharmony_ci do_warmup = (t - scanner->last_scan) > 300; 3824141cc406Sopenharmony_ci 3825141cc406Sopenharmony_ci if (getenv ("HP3500_NOWARMUP") && atoi (getenv ("HP3500_NOWARMUP")) > 0) 3826141cc406Sopenharmony_ci do_warmup = 0; 3827141cc406Sopenharmony_ci 3828141cc406Sopenharmony_ci udh = scanner->sfd; 3829141cc406Sopenharmony_ci 3830141cc406Sopenharmony_ci cancelled_scan = 0; 3831141cc406Sopenharmony_ci 3832141cc406Sopenharmony_ci winfo.scanner = scanner; 3833141cc406Sopenharmony_ci winfo.bytesleft = 3834141cc406Sopenharmony_ci scanner->bytes_per_scan_line * scanner->scan_height_pixels; 3835141cc406Sopenharmony_ci 3836141cc406Sopenharmony_ci if (getenv ("HP3500_SLEEP")) 3837141cc406Sopenharmony_ci { 3838141cc406Sopenharmony_ci int seconds = atoi (getenv ("HP3500_SLEEP")); 3839141cc406Sopenharmony_ci 3840141cc406Sopenharmony_ci DBG (1, "Backend process %d sleeping for %d seconds\n", getpid (), 3841141cc406Sopenharmony_ci seconds); 3842141cc406Sopenharmony_ci sleep (seconds); 3843141cc406Sopenharmony_ci } 3844141cc406Sopenharmony_ci DBG (10, "Scanning at %ddpi, mode=%s\n", scanner->resolution, 3845141cc406Sopenharmony_ci scan_mode_list[scanner->mode]); 3846141cc406Sopenharmony_ci if (rts8801_scan 3847141cc406Sopenharmony_ci (scanner->actres_pixels.left + 250 * scanner->resolution / 1200, 3848141cc406Sopenharmony_ci scanner->actres_pixels.top + 599 * scanner->resolution / 1200, 3849141cc406Sopenharmony_ci scanner->actres_pixels.right - scanner->actres_pixels.left, 3850141cc406Sopenharmony_ci scanner->actres_pixels.bottom - scanner->actres_pixels.top, 3851141cc406Sopenharmony_ci scanner->resolution, scanner->mode, scanner->brightness, 3852141cc406Sopenharmony_ci scanner->contrast, (rts8801_callback) writefunc, &winfo, 3853141cc406Sopenharmony_ci scanner->gamma) >= 0) 3854141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 3855141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 3856141cc406Sopenharmony_ci close (scanner->pipe_w); 3857141cc406Sopenharmony_ci return status; 3858141cc406Sopenharmony_ci} 3859141cc406Sopenharmony_ci 3860141cc406Sopenharmony_cistatic size_t 3861141cc406Sopenharmony_cimax_string_size (char const **strings) 3862141cc406Sopenharmony_ci{ 3863141cc406Sopenharmony_ci size_t size, max_size = 0; 3864141cc406Sopenharmony_ci SANE_Int i; 3865141cc406Sopenharmony_ci 3866141cc406Sopenharmony_ci for (i = 0; strings[i]; ++i) 3867141cc406Sopenharmony_ci { 3868141cc406Sopenharmony_ci size = strlen (strings[i]) + 1; 3869141cc406Sopenharmony_ci if (size > max_size) 3870141cc406Sopenharmony_ci max_size = size; 3871141cc406Sopenharmony_ci } 3872141cc406Sopenharmony_ci return max_size; 3873141cc406Sopenharmony_ci} 3874