1141cc406Sopenharmony_ci/***************************************************************************
2141cc406Sopenharmony_ci * SANE - Scanner Access Now Easy.
3141cc406Sopenharmony_ci
4141cc406Sopenharmony_ci   microtek.c
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file Copyright 2002 Matthew Marjanovic
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   This file is part of the SANE package.
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
11141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
12141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
13141cc406Sopenharmony_ci   License, or (at your option) any later version.
14141cc406Sopenharmony_ci
15141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
16141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
17141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18141cc406Sopenharmony_ci   General Public License for more details.
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
21141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
24141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
25141cc406Sopenharmony_ci
26141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
27141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
28141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
29141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
30141cc406Sopenharmony_ci   account of linking the SANE library code into it.
31141cc406Sopenharmony_ci
32141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
33141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
34141cc406Sopenharmony_ci   License.
35141cc406Sopenharmony_ci
36141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
37141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
38141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
39141cc406Sopenharmony_ci
40141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
41141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
42141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci ***************************************************************************
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci   This file implements a SANE backend for Microtek scanners.
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci   (feedback to:  mtek-bugs@mir.com)
49141cc406Sopenharmony_ci   (for latest info:  http://www.mir.com/mtek/)
50141cc406Sopenharmony_ci
51141cc406Sopenharmony_ci ***************************************************************************/
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci
54141cc406Sopenharmony_ci#define MICROTEK_MAJOR 0
55141cc406Sopenharmony_ci#define MICROTEK_MINOR 13
56141cc406Sopenharmony_ci#define MICROTEK_PATCH 1
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci#include "../include/sane/config.h"
59141cc406Sopenharmony_ci
60141cc406Sopenharmony_ci#include <stdarg.h>
61141cc406Sopenharmony_ci#include <stdlib.h>
62141cc406Sopenharmony_ci#include <string.h>
63141cc406Sopenharmony_ci#include <unistd.h>
64141cc406Sopenharmony_ci#include <fcntl.h>
65141cc406Sopenharmony_ci#include <math.h>
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci#include "../include/_stdint.h"
68141cc406Sopenharmony_ci
69141cc406Sopenharmony_ci#include "../include/sane/sane.h"
70141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
71141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
72141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
73141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci#define BACKEND_NAME microtek
76141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_ci#include "microtek.h"
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci#define MICROTEK_CONFIG_FILE "microtek.conf"
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_ci#ifndef PATH_MAX
84141cc406Sopenharmony_ci# define PATH_MAX	1024
85141cc406Sopenharmony_ci#endif
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_ci#define SCSI_BUFF_SIZE sanei_scsi_max_request_size
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci#define MIN(a,b) (((a) < (b)) ? (a) : (b))
92141cc406Sopenharmony_ci#define MAX(a,b) (((a) > (b)) ? (a) : (b))
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_cistatic int num_devices = 0;
95141cc406Sopenharmony_cistatic Microtek_Device *first_dev = NULL;     /* list of known devices */
96141cc406Sopenharmony_cistatic Microtek_Scanner *first_handle = NULL; /* list of open scanners */
97141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL;    /* sane_get_devices() */
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci
100141cc406Sopenharmony_cistatic SANE_Bool inhibit_clever_precal = SANE_FALSE;
101141cc406Sopenharmony_cistatic SANE_Bool inhibit_real_calib = SANE_FALSE;
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci
104141cc406Sopenharmony_ci#define M_GSS_WAIT 5 /* seconds */
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci#define M_LINEART  SANE_VALUE_SCAN_MODE_LINEART
107141cc406Sopenharmony_ci#define M_HALFTONE SANE_VALUE_SCAN_MODE_HALFTONE
108141cc406Sopenharmony_ci#define M_GRAY     SANE_VALUE_SCAN_MODE_GRAY
109141cc406Sopenharmony_ci#define M_COLOR    SANE_VALUE_SCAN_MODE_COLOR
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci#define M_OPAQUE   "Opaque/Normal"
112141cc406Sopenharmony_ci#define M_TRANS    "Transparency"
113141cc406Sopenharmony_ci#define M_AUTOFEED "AutoFeeder"
114141cc406Sopenharmony_ci
115141cc406Sopenharmony_ci#define M_NONE   "None"
116141cc406Sopenharmony_ci#define M_SCALAR "Scalar"
117141cc406Sopenharmony_ci#define M_TABLE  "Table"
118141cc406Sopenharmony_ci
119141cc406Sopenharmony_cistatic SANE_String_Const gamma_mode_list[4] = {
120141cc406Sopenharmony_ci  M_NONE,
121141cc406Sopenharmony_ci  M_SCALAR,
122141cc406Sopenharmony_ci  M_TABLE,
123141cc406Sopenharmony_ci  NULL
124141cc406Sopenharmony_ci};
125141cc406Sopenharmony_ci
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci/* These are for the E6.  Does this hold for other models? */
128141cc406Sopenharmony_cistatic SANE_String_Const halftone_mode_list[13] = {
129141cc406Sopenharmony_ci  " 1 53-dot screen (53 gray levels)",
130141cc406Sopenharmony_ci  " 2 Horiz. screen (65 gray levels)",
131141cc406Sopenharmony_ci  " 3 Vert. screen (65 gray levels)",
132141cc406Sopenharmony_ci  " 4 Mixed page (33 gray levels)",
133141cc406Sopenharmony_ci  " 5 71-dot screen (29 gray levels)",
134141cc406Sopenharmony_ci  " 6 60-dot #1 (26 gray levels)",
135141cc406Sopenharmony_ci  " 7 60-dot #2 (26 gray levels)",
136141cc406Sopenharmony_ci  " 8 Fine detail #1 (17 gray levels)",
137141cc406Sopenharmony_ci  " 9 Fine detail #2 (17 gray levels)",
138141cc406Sopenharmony_ci  "10 Slant line (17 gray levels)",
139141cc406Sopenharmony_ci  "11 Posterizing (10 gray levels)",
140141cc406Sopenharmony_ci  "12 High Contrast (5 gray levels)",
141141cc406Sopenharmony_ci  NULL
142141cc406Sopenharmony_ci};
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_ci
145141cc406Sopenharmony_ci
146141cc406Sopenharmony_cistatic SANE_Range speed_range = {1, 7, 1};
147141cc406Sopenharmony_ci
148141cc406Sopenharmony_cistatic SANE_Range brightness_range = {-100, 100, 1};
149141cc406Sopenharmony_ci/*static SANE_Range brightness_range = {0, 255, 1};*/
150141cc406Sopenharmony_ci/*static SANE_Range exposure_range = {-18, 21, 3};*/
151141cc406Sopenharmony_ci/*static SANE_Range contrast_range = {-42, 49, 7};*/
152141cc406Sopenharmony_cistatic SANE_Range u8_range = {0, 255, 1};
153141cc406Sopenharmony_cistatic SANE_Range analog_gamma_range =
154141cc406Sopenharmony_ci{ SANE_FIX(0.1), SANE_FIX(4.0), SANE_FIX(0) };
155141cc406Sopenharmony_ci
156141cc406Sopenharmony_ci
157141cc406Sopenharmony_ci
158141cc406Sopenharmony_ci
159141cc406Sopenharmony_ci#define MAX_MDBG_LENGTH 1024
160141cc406Sopenharmony_cistatic char _mdebug_string[MAX_MDBG_LENGTH];
161141cc406Sopenharmony_ci
162141cc406Sopenharmony_cistatic void MDBG_INIT(const char *format, ...)
163141cc406Sopenharmony_ci{
164141cc406Sopenharmony_ci  va_list ap;
165141cc406Sopenharmony_ci  va_start(ap, format);
166141cc406Sopenharmony_ci  vsnprintf(_mdebug_string, MAX_MDBG_LENGTH, format, ap);
167141cc406Sopenharmony_ci  va_end(ap);
168141cc406Sopenharmony_ci}
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_cistatic void MDBG_ADD(const char *format, ...)
171141cc406Sopenharmony_ci{
172141cc406Sopenharmony_ci  int len = strlen(_mdebug_string);
173141cc406Sopenharmony_ci  va_list ap;
174141cc406Sopenharmony_ci  va_start(ap, format);
175141cc406Sopenharmony_ci  vsnprintf(_mdebug_string+len, MAX_MDBG_LENGTH-len, format, ap);
176141cc406Sopenharmony_ci  va_end(ap);
177141cc406Sopenharmony_ci}
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_cistatic void MDBG_FINISH(int dbglvl)
180141cc406Sopenharmony_ci{
181141cc406Sopenharmony_ci  DBG(dbglvl, "%s\n", _mdebug_string);
182141cc406Sopenharmony_ci}
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci
185141cc406Sopenharmony_ci
186141cc406Sopenharmony_ci/********************************************************************/
187141cc406Sopenharmony_ci/********************************************************************/
188141cc406Sopenharmony_ci/*** Utility Functions **********************************************/
189141cc406Sopenharmony_ci/********************************************************************/
190141cc406Sopenharmony_ci/********************************************************************/
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_cistatic size_t max_string_size (const SANE_String_Const strings[])
193141cc406Sopenharmony_ci{
194141cc406Sopenharmony_ci  size_t size, max_size = 0;
195141cc406Sopenharmony_ci  int i;
196141cc406Sopenharmony_ci
197141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i) {
198141cc406Sopenharmony_ci    size = strlen(strings[i]) + 1;
199141cc406Sopenharmony_ci    if (size > max_size) max_size = size;
200141cc406Sopenharmony_ci  }
201141cc406Sopenharmony_ci  return max_size;
202141cc406Sopenharmony_ci}
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_ci
205141cc406Sopenharmony_ci
206141cc406Sopenharmony_ci/********************************************************************/
207141cc406Sopenharmony_ci/* Allocate/create a new ring buffer                                */
208141cc406Sopenharmony_ci/********************************************************************/
209141cc406Sopenharmony_cistatic ring_buffer *
210141cc406Sopenharmony_ciring_alloc (size_t initial_size, size_t bpl, size_t ppl)
211141cc406Sopenharmony_ci{
212141cc406Sopenharmony_ci  ring_buffer *rb;
213141cc406Sopenharmony_ci  uint8_t *buff;
214141cc406Sopenharmony_ci
215141cc406Sopenharmony_ci  if ((rb = (ring_buffer *)malloc(sizeof(*rb))) == NULL)
216141cc406Sopenharmony_ci    return NULL;
217141cc406Sopenharmony_ci  if ((buff = (uint8_t *)malloc(initial_size * sizeof(*buff))) == NULL) {
218141cc406Sopenharmony_ci    free(rb);
219141cc406Sopenharmony_ci    return NULL;
220141cc406Sopenharmony_ci  }
221141cc406Sopenharmony_ci  rb->base = buff;
222141cc406Sopenharmony_ci  rb->size = initial_size;
223141cc406Sopenharmony_ci  rb->initial_size = initial_size;
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci  rb->bpl = bpl;
226141cc406Sopenharmony_ci  rb->ppl = ppl;
227141cc406Sopenharmony_ci
228141cc406Sopenharmony_ci  rb->tail_red   = 0;
229141cc406Sopenharmony_ci  rb->tail_green = 1;
230141cc406Sopenharmony_ci  rb->tail_blue  = 2;
231141cc406Sopenharmony_ci  rb->head_complete = 0;
232141cc406Sopenharmony_ci
233141cc406Sopenharmony_ci  rb->red_extra   = 0;
234141cc406Sopenharmony_ci  rb->green_extra = 0;
235141cc406Sopenharmony_ci  rb->blue_extra  = 0;
236141cc406Sopenharmony_ci  rb->complete_count = 0;
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci  return rb;
239141cc406Sopenharmony_ci}
240141cc406Sopenharmony_ci
241141cc406Sopenharmony_ci
242141cc406Sopenharmony_ci/********************************************************************/
243141cc406Sopenharmony_ci/* Enlarge an existing ring buffer                                  */
244141cc406Sopenharmony_ci/********************************************************************/
245141cc406Sopenharmony_cistatic SANE_Status
246141cc406Sopenharmony_ciring_expand (ring_buffer *rb, size_t amount)
247141cc406Sopenharmony_ci{
248141cc406Sopenharmony_ci  uint8_t *buff;
249141cc406Sopenharmony_ci  size_t oldsize;
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci  if (rb == NULL) return SANE_STATUS_INVAL;
252141cc406Sopenharmony_ci  buff = (uint8_t *)realloc(rb->base, (rb->size + amount) * sizeof(*buff));
253141cc406Sopenharmony_ci  if (buff == NULL) return SANE_STATUS_NO_MEM;
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci  rb->base = buff;
256141cc406Sopenharmony_ci  oldsize = rb->size;
257141cc406Sopenharmony_ci  rb->size += amount;
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci  DBG(23, "ring_expand:  old, new, inc size:  %lu, %lu, %lu\n",
260141cc406Sopenharmony_ci      (u_long)oldsize, (u_long)rb->size, (u_long)amount);
261141cc406Sopenharmony_ci  DBG(23, "ring_expand:  old  tr: %lu  tg: %lu  tb: %lu  hc: %lu\n",
262141cc406Sopenharmony_ci      (u_long)rb->tail_red, (u_long)rb->tail_green,
263141cc406Sopenharmony_ci      (u_long)rb->tail_blue, (u_long)rb->head_complete);
264141cc406Sopenharmony_ci  /* if necessary, move data and fix up them pointers */
265141cc406Sopenharmony_ci  /* (will break subtly if ring is filled with G or B bytes,
266141cc406Sopenharmony_ci     and tail_g or tail_b have rolled over...) */
267141cc406Sopenharmony_ci  if (((rb->complete_count) ||
268141cc406Sopenharmony_ci       (rb->red_extra) ||
269141cc406Sopenharmony_ci       (rb->green_extra) ||
270141cc406Sopenharmony_ci       (rb->blue_extra)) && ((rb->tail_red <= rb->head_complete) ||
271141cc406Sopenharmony_ci			     (rb->tail_green <= rb->head_complete) ||
272141cc406Sopenharmony_ci			     (rb->tail_blue <= rb->head_complete))) {
273141cc406Sopenharmony_ci    memmove(rb->base + rb->head_complete + amount,
274141cc406Sopenharmony_ci	    rb->base + rb->head_complete,
275141cc406Sopenharmony_ci	    oldsize - rb->head_complete);
276141cc406Sopenharmony_ci    if ((rb->tail_red > rb->head_complete) ||
277141cc406Sopenharmony_ci	((rb->tail_red == rb->head_complete) &&
278141cc406Sopenharmony_ci	 !(rb->complete_count) && !(rb->red_extra)))
279141cc406Sopenharmony_ci      rb->tail_red += amount;
280141cc406Sopenharmony_ci    if ((rb->tail_green > rb->head_complete) ||
281141cc406Sopenharmony_ci	((rb->tail_green == rb->head_complete) &&
282141cc406Sopenharmony_ci	 !(rb->complete_count) && !(rb->green_extra)))
283141cc406Sopenharmony_ci      rb->tail_green += amount;
284141cc406Sopenharmony_ci    if ((rb->tail_blue > rb->head_complete) ||
285141cc406Sopenharmony_ci	((rb->tail_blue == rb->head_complete) &&
286141cc406Sopenharmony_ci	 !(rb->complete_count) && !(rb->blue_extra)))
287141cc406Sopenharmony_ci      rb->tail_blue += amount;
288141cc406Sopenharmony_ci    rb->head_complete += amount;
289141cc406Sopenharmony_ci  }
290141cc406Sopenharmony_ci  DBG(23, "ring_expand:  new  tr: %lu  tg: %lu  tb: %lu  hc: %lu\n",
291141cc406Sopenharmony_ci      (u_long)rb->tail_red, (u_long)rb->tail_green,
292141cc406Sopenharmony_ci      (u_long)rb->tail_blue, (u_long)rb->head_complete);
293141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
294141cc406Sopenharmony_ci}
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci
297141cc406Sopenharmony_ci/********************************************************************/
298141cc406Sopenharmony_ci/* Deallocate a ring buffer                                         */
299141cc406Sopenharmony_ci/********************************************************************/
300141cc406Sopenharmony_cistatic void
301141cc406Sopenharmony_ciring_free (ring_buffer *rb)
302141cc406Sopenharmony_ci{
303141cc406Sopenharmony_ci  free(rb->base);
304141cc406Sopenharmony_ci  free(rb);
305141cc406Sopenharmony_ci}
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci
308141cc406Sopenharmony_ci
309141cc406Sopenharmony_ci/********************************************************************/
310141cc406Sopenharmony_ci/********************************************************************/
311141cc406Sopenharmony_ci/*** Basic SCSI Commands ********************************************/
312141cc406Sopenharmony_ci/********************************************************************/
313141cc406Sopenharmony_ci/********************************************************************/
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ci
316141cc406Sopenharmony_ci/********************************************************************/
317141cc406Sopenharmony_ci/* parse sense from scsi error                                      */
318141cc406Sopenharmony_ci/*  (even though microtek sense codes are non-standard and          */
319141cc406Sopenharmony_ci/*   typically misinterpreted/munged by the low-level scsi driver)  */
320141cc406Sopenharmony_ci/********************************************************************/
321141cc406Sopenharmony_cistatic SANE_Status
322141cc406Sopenharmony_cisense_handler (int scsi_fd, u_char *sense, void *arg)
323141cc406Sopenharmony_ci{
324141cc406Sopenharmony_ci  int *sense_flags = (int *)arg;
325141cc406Sopenharmony_ci  SANE_Status stat;
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci  DBG(10, "SENSE!  fd = %d\n", scsi_fd);
328141cc406Sopenharmony_ci  DBG(10, "sense = %02x %02x %02x %02x.\n",
329141cc406Sopenharmony_ci            sense[0], sense[1], sense[2], sense[3]);
330141cc406Sopenharmony_ci  switch(sense[0]) {
331141cc406Sopenharmony_ci  case 0x00:
332141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
333141cc406Sopenharmony_ci  case 0x81:           /* COMMAND/DATA ERROR */
334141cc406Sopenharmony_ci    stat = SANE_STATUS_GOOD;
335141cc406Sopenharmony_ci    if (sense[1] & 0x01) {
336141cc406Sopenharmony_ci      if ((sense_flags != NULL) && (*sense_flags & MS_SENSE_IGNORE))
337141cc406Sopenharmony_ci	DBG(10, "sense:  ERR_SCSICMD -- ignored\n");
338141cc406Sopenharmony_ci      else {
339141cc406Sopenharmony_ci	DBG(10, "sense:  ERR_SCSICMD\n");
340141cc406Sopenharmony_ci	stat = SANE_STATUS_IO_ERROR;
341141cc406Sopenharmony_ci      }
342141cc406Sopenharmony_ci    }
343141cc406Sopenharmony_ci    if (sense[1] & 0x02) {
344141cc406Sopenharmony_ci      DBG(10, "sense:  ERR_TOOMANY\n");
345141cc406Sopenharmony_ci      stat = SANE_STATUS_IO_ERROR;
346141cc406Sopenharmony_ci    }
347141cc406Sopenharmony_ci    return stat;
348141cc406Sopenharmony_ci  case 0x82 :           /* SCANNER HARDWARE ERROR */
349141cc406Sopenharmony_ci    if (sense[1] & 0x01) DBG(10, "sense:  ERR_CPURAMFAIL\n");
350141cc406Sopenharmony_ci    if (sense[1] & 0x02) DBG(10, "sense:  ERR_SYSRAMFAIL\n");
351141cc406Sopenharmony_ci    if (sense[1] & 0x04) DBG(10, "sense:  ERR_IMGRAMFAIL\n");
352141cc406Sopenharmony_ci    if (sense[1] & 0x10) DBG(10, "sense:  ERR_CALIBRATE\n");
353141cc406Sopenharmony_ci    if (sense[1] & 0x20) DBG(10, "sense:  ERR_LAMPFAIL\n");
354141cc406Sopenharmony_ci    if (sense[1] & 0x40) DBG(10, "sense:  ERR_MOTORFAIL\n");
355141cc406Sopenharmony_ci    if (sense[1] & 0x80) DBG(10, "sense:  ERR_FEEDERFAIL\n");
356141cc406Sopenharmony_ci    if (sense[2] & 0x01) DBG(10, "sense:  ERR_POWERFAIL\n");
357141cc406Sopenharmony_ci    if (sense[2] & 0x02) DBG(10, "sense:  ERR_ILAMPFAIL\n");
358141cc406Sopenharmony_ci    if (sense[2] & 0x04) DBG(10, "sense:  ERR_IMOTORFAIL\n");
359141cc406Sopenharmony_ci    if (sense[2] & 0x08) DBG(10, "sense:  ERR_PAPERFAIL\n");
360141cc406Sopenharmony_ci    if (sense[2] & 0x10) DBG(10, "sense:  ERR_FILTERFAIL\n");
361141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
362141cc406Sopenharmony_ci  case 0x83 :           /* OPERATION ERROR */
363141cc406Sopenharmony_ci    if (sense[1] & 0x01) DBG(10, "sense:  ERR_ILLGRAIN\n");
364141cc406Sopenharmony_ci    if (sense[1] & 0x02) DBG(10, "sense:  ERR_ILLRES\n");
365141cc406Sopenharmony_ci    if (sense[1] & 0x04) DBG(10, "sense:  ERR_ILLCOORD\n");
366141cc406Sopenharmony_ci    if (sense[1] & 0x10) DBG(10, "sense:  ERR_ILLCNTR\n");
367141cc406Sopenharmony_ci    if (sense[1] & 0x20) DBG(10, "sense:  ERR_ILLLENGTH\n");
368141cc406Sopenharmony_ci    if (sense[1] & 0x40) DBG(10, "sense:  ERR_ILLADJUST\n");
369141cc406Sopenharmony_ci    if (sense[1] & 0x80) DBG(10, "sense:  ERR_ILLEXPOSE\n");
370141cc406Sopenharmony_ci    if (sense[2] & 0x01) DBG(10, "sense:  ERR_ILLFILTER\n");
371141cc406Sopenharmony_ci    if (sense[2] & 0x02) DBG(10, "sense:  ERR_NOPAPER\n");
372141cc406Sopenharmony_ci    if (sense[2] & 0x04) DBG(10, "sense:  ERR_ILLTABLE\n");
373141cc406Sopenharmony_ci    if (sense[2] & 0x08) DBG(10, "sense:  ERR_ILLOFFSET\n");
374141cc406Sopenharmony_ci    if (sense[2] & 0x10) DBG(10, "sense:  ERR_ILLBPP\n");
375141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
376141cc406Sopenharmony_ci  default :
377141cc406Sopenharmony_ci    DBG(10, "sense: unknown error\n");
378141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
379141cc406Sopenharmony_ci  }
380141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
381141cc406Sopenharmony_ci}
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci
385141cc406Sopenharmony_ci/********************************************************************/
386141cc406Sopenharmony_ci/* wait (via polling) until scanner seems "ready"                   */
387141cc406Sopenharmony_ci/********************************************************************/
388141cc406Sopenharmony_cistatic SANE_Status
389141cc406Sopenharmony_ciwait_ready(Microtek_Scanner *ms)
390141cc406Sopenharmony_ci{
391141cc406Sopenharmony_ci  uint8_t comm[6] = { 0, 0, 0, 0, 0, 0 };
392141cc406Sopenharmony_ci  SANE_Status status;
393141cc406Sopenharmony_ci  int retry = 0;
394141cc406Sopenharmony_ci
395141cc406Sopenharmony_ci  DBG(23, ".wait_ready %d...\n", ms->sfd);
396141cc406Sopenharmony_ci  while ((status = sanei_scsi_cmd(ms->sfd, comm, 6, 0, 0))
397141cc406Sopenharmony_ci	 != SANE_STATUS_GOOD) {
398141cc406Sopenharmony_ci    DBG(23, "wait_ready failed (%d)\n", retry);
399141cc406Sopenharmony_ci    if (retry > 5) return SANE_STATUS_IO_ERROR; /* XXXXXXXX */
400141cc406Sopenharmony_ci    retry++;
401141cc406Sopenharmony_ci    sleep(3);
402141cc406Sopenharmony_ci  }
403141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
404141cc406Sopenharmony_ci}
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_ci
407141cc406Sopenharmony_ci/********************************************************************/
408141cc406Sopenharmony_ci/* send scan region coordinates                                     */
409141cc406Sopenharmony_ci/********************************************************************/
410141cc406Sopenharmony_cistatic SANE_Status
411141cc406Sopenharmony_ciscanning_frame(Microtek_Scanner *ms)
412141cc406Sopenharmony_ci{
413141cc406Sopenharmony_ci  uint8_t *data, comm[15] = { 0x04, 0, 0, 0, 0x09, 0 };
414141cc406Sopenharmony_ci  int x1, y1, x2, y2;
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci  DBG(23, ".scanning_frame...\n");
417141cc406Sopenharmony_ci
418141cc406Sopenharmony_ci  x1 = ms->x1;
419141cc406Sopenharmony_ci  x2 = ms->x2;
420141cc406Sopenharmony_ci  y1 = ms->y1;
421141cc406Sopenharmony_ci  y2 = ms->y2;
422141cc406Sopenharmony_ci  /* E6 weirdness (other models too?) */
423141cc406Sopenharmony_ci  if (ms->unit_type == MS_UNIT_18INCH) {
424141cc406Sopenharmony_ci    x1 /= 2;
425141cc406Sopenharmony_ci    x2 /= 2;
426141cc406Sopenharmony_ci    y1 /= 2;
427141cc406Sopenharmony_ci    y2 /= 2;
428141cc406Sopenharmony_ci  }
429141cc406Sopenharmony_ci
430141cc406Sopenharmony_ci  DBG(23, ".scanning_frame:  in- %d,%d  %d,%d\n",
431141cc406Sopenharmony_ci      ms->x1, ms->y1, ms->x2, ms->y2);
432141cc406Sopenharmony_ci  DBG(23, ".scanning_frame: out- %d,%d  %d,%d\n", x1, y1, x2, y2);
433141cc406Sopenharmony_ci  data = comm + 6;
434141cc406Sopenharmony_ci  data[0] =
435141cc406Sopenharmony_ci    ((ms->unit_type == MS_UNIT_PIXELS) ? 0x08 : 0 ) |
436141cc406Sopenharmony_ci    ((ms->mode == MS_MODE_HALFTONE) ? 0x01 : 0 );
437141cc406Sopenharmony_ci  data[1] = x1 & 0xFF;
438141cc406Sopenharmony_ci  data[2] = (x1 >> 8) & 0xFF;
439141cc406Sopenharmony_ci  data[3] = y1 & 0xFF;
440141cc406Sopenharmony_ci  data[4] = (y1 >> 8) & 0xFF;
441141cc406Sopenharmony_ci  data[5] = x2 & 0xFF;
442141cc406Sopenharmony_ci  data[6] = (x2 >> 8) & 0xFF;
443141cc406Sopenharmony_ci  data[7] = y2 & 0xFF;
444141cc406Sopenharmony_ci  data[8] = (y2 >> 8) & 0xFF;
445141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
446141cc406Sopenharmony_ci    int i;
447141cc406Sopenharmony_ci#if 0
448141cc406Sopenharmony_ci    fprintf(stderr, "SF: ");
449141cc406Sopenharmony_ci    for (i=0;i<6+0x09;i++) fprintf(stderr, "%2x ", comm[i]);
450141cc406Sopenharmony_ci    fprintf(stderr, "\n");
451141cc406Sopenharmony_ci#endif
452141cc406Sopenharmony_ci    MDBG_INIT("SF: ");
453141cc406Sopenharmony_ci    for (i=0;i<6+0x09;i++) MDBG_ADD("%2x ", comm[i]);
454141cc406Sopenharmony_ci    MDBG_FINISH(192);
455141cc406Sopenharmony_ci  }
456141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 6 + 0x09, 0, 0);
457141cc406Sopenharmony_ci}
458141cc406Sopenharmony_ci
459141cc406Sopenharmony_ci
460141cc406Sopenharmony_ci
461141cc406Sopenharmony_ci/********************************************************************/
462141cc406Sopenharmony_ci/* send "mode_select"                                               */
463141cc406Sopenharmony_ci/********************************************************************/
464141cc406Sopenharmony_cistatic SANE_Status
465141cc406Sopenharmony_cimode_select(Microtek_Scanner *ms)
466141cc406Sopenharmony_ci{
467141cc406Sopenharmony_ci  uint8_t *data, comm[19] = { 0x15, 0, 0, 0, 0, 0 };
468141cc406Sopenharmony_ci
469141cc406Sopenharmony_ci  DBG(23, ".mode_select %d...\n", ms->sfd);
470141cc406Sopenharmony_ci  data = comm + 6;
471141cc406Sopenharmony_ci  data[0] =
472141cc406Sopenharmony_ci    0x81 |
473141cc406Sopenharmony_ci    ((ms->unit_type == MS_UNIT_18INCH) ? 0 : 0x08) |
474141cc406Sopenharmony_ci    ((ms->res_type == MS_RES_5PER) ? 0 : 0x02);
475141cc406Sopenharmony_ci  data[1] = ms->resolution_code;
476141cc406Sopenharmony_ci  data[2] = ms->exposure;
477141cc406Sopenharmony_ci  data[3] = ms->contrast;
478141cc406Sopenharmony_ci  data[4] = ms->pattern;
479141cc406Sopenharmony_ci  data[5] = ms->velocity;
480141cc406Sopenharmony_ci  data[6] = ms->shadow;
481141cc406Sopenharmony_ci  data[7] = ms->highlight;
482141cc406Sopenharmony_ci  DBG(23, ".mode_select:  pap_len: %d\n", ms->paper_length);
483141cc406Sopenharmony_ci  data[8] = ms->paper_length & 0xFF;
484141cc406Sopenharmony_ci  data[9] = (ms->paper_length >> 8) & 0xFF;
485141cc406Sopenharmony_ci  data[10] = ms->midtone;
486141cc406Sopenharmony_ci  /* set command/data length */
487141cc406Sopenharmony_ci  comm[4] = (ms->midtone_support) ? 0x0B : 0x0A;
488141cc406Sopenharmony_ci
489141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
490141cc406Sopenharmony_ci    int i;
491141cc406Sopenharmony_ci#if 0
492141cc406Sopenharmony_ci    fprintf(stderr, "MSL: ");
493141cc406Sopenharmony_ci    for (i=0;i<6+comm[4];i++) fprintf(stderr, "%2x ", comm[i]);
494141cc406Sopenharmony_ci    fprintf(stderr, "\n");
495141cc406Sopenharmony_ci#endif
496141cc406Sopenharmony_ci    MDBG_INIT("MSL: ");
497141cc406Sopenharmony_ci    for (i=0;i<6+comm[4];i++) MDBG_ADD("%2x ", comm[i]);
498141cc406Sopenharmony_ci    MDBG_FINISH(192);
499141cc406Sopenharmony_ci  }
500141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 6 + comm[4], 0, 0);
501141cc406Sopenharmony_ci}
502141cc406Sopenharmony_ci
503141cc406Sopenharmony_ci
504141cc406Sopenharmony_ci
505141cc406Sopenharmony_ci/********************************************************************/
506141cc406Sopenharmony_ci/* send "mode_select_1"                                             */
507141cc406Sopenharmony_ci/********************************************************************/
508141cc406Sopenharmony_cistatic SANE_Status
509141cc406Sopenharmony_cimode_select_1(Microtek_Scanner *ms)
510141cc406Sopenharmony_ci{
511141cc406Sopenharmony_ci  uint8_t *data, comm[16] = { 0x16, 0, 0, 0, 0x0A, 0,
512141cc406Sopenharmony_ci                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
513141cc406Sopenharmony_ci
514141cc406Sopenharmony_ci  DBG(23, ".mode_select_1 %d...\n", ms->sfd);
515141cc406Sopenharmony_ci  data = comm + 6;
516141cc406Sopenharmony_ci  data[1] = ms->bright_r;
517141cc406Sopenharmony_ci  data[3] = ((ms->allow_calibrate) ? 0 : 0x02); /* | 0x01; */
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
520141cc406Sopenharmony_ci    int i;
521141cc406Sopenharmony_ci#if 0
522141cc406Sopenharmony_ci    fprintf(stderr, "MSL1: ");
523141cc406Sopenharmony_ci    for (i=0;i<6+0x0A;i++) fprintf(stderr, "%2x ", comm[i]);
524141cc406Sopenharmony_ci    fprintf(stderr, "\n");
525141cc406Sopenharmony_ci#endif
526141cc406Sopenharmony_ci    MDBG_INIT("MSL1: ");
527141cc406Sopenharmony_ci    for (i=0;i<6+0x0A;i++) MDBG_ADD("%2x ", comm[i]);
528141cc406Sopenharmony_ci    MDBG_FINISH(192);
529141cc406Sopenharmony_ci  }
530141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 6 + 0x0A, 0, 0);
531141cc406Sopenharmony_ci}
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci/********************************************************************/
536141cc406Sopenharmony_ci/* record mode_sense results in the mode_sense buffer               */
537141cc406Sopenharmony_ci/*  (this is to tell if something catastrophic has happened         */
538141cc406Sopenharmony_ci/*   to the scanner in-between scans)                               */
539141cc406Sopenharmony_ci/********************************************************************/
540141cc406Sopenharmony_cistatic SANE_Status
541141cc406Sopenharmony_cisave_mode_sense(Microtek_Scanner *ms)
542141cc406Sopenharmony_ci{
543141cc406Sopenharmony_ci  uint8_t data[20], comm[6] = { 0x1A, 0, 0, 0, 0, 0};
544141cc406Sopenharmony_ci  size_t lenp;
545141cc406Sopenharmony_ci  SANE_Status status;
546141cc406Sopenharmony_ci  int i;
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci  DBG(23, ".save_mode_sense %d...\n", ms->sfd);
549141cc406Sopenharmony_ci  if (ms->onepass) comm[4] = 0x13;
550141cc406Sopenharmony_ci  else if (ms->midtone_support) comm[4] = 0x0B;
551141cc406Sopenharmony_ci  else comm[4] = 0x0A;
552141cc406Sopenharmony_ci  lenp = comm[4];
553141cc406Sopenharmony_ci
554141cc406Sopenharmony_ci  status = sanei_scsi_cmd(ms->sfd, comm, 6, data, &lenp);
555141cc406Sopenharmony_ci  for (i=0; i<10; i++) ms->mode_sense_cache[i] = data[i];
556141cc406Sopenharmony_ci
557141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
558141cc406Sopenharmony_ci    unsigned int i;
559141cc406Sopenharmony_ci#if 0
560141cc406Sopenharmony_ci    fprintf(stderr, "SMS: ");
561141cc406Sopenharmony_ci    for (i=0;i<lenp;i++) fprintf(stderr, "%2x ", data[i]);
562141cc406Sopenharmony_ci    fprintf(stderr, "\n");
563141cc406Sopenharmony_ci#endif
564141cc406Sopenharmony_ci    MDBG_INIT("SMS: ");
565141cc406Sopenharmony_ci    for (i=0;i<lenp;i++) MDBG_ADD("%2x ", data[i]);
566141cc406Sopenharmony_ci    MDBG_FINISH(192);
567141cc406Sopenharmony_ci  }
568141cc406Sopenharmony_ci
569141cc406Sopenharmony_ci  return status;
570141cc406Sopenharmony_ci}
571141cc406Sopenharmony_ci
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_ci/********************************************************************/
574141cc406Sopenharmony_ci/* read mode_sense and compare to what we saved before              */
575141cc406Sopenharmony_ci/********************************************************************/
576141cc406Sopenharmony_cistatic SANE_Status
577141cc406Sopenharmony_cicompare_mode_sense(Microtek_Scanner *ms, int *match)
578141cc406Sopenharmony_ci{
579141cc406Sopenharmony_ci  uint8_t data[20], comm[6] = { 0x1A, 0, 0, 0, 0, 0};
580141cc406Sopenharmony_ci  size_t lenp;
581141cc406Sopenharmony_ci  SANE_Status status;
582141cc406Sopenharmony_ci  int i;
583141cc406Sopenharmony_ci
584141cc406Sopenharmony_ci  DBG(23, ".compare_mode_sense %d...\n", ms->sfd);
585141cc406Sopenharmony_ci  if (ms->onepass) comm[4] = 0x13;
586141cc406Sopenharmony_ci  else if (ms->midtone_support) comm[4] = 0x0B;
587141cc406Sopenharmony_ci  else comm[4] = 0x0A;
588141cc406Sopenharmony_ci  lenp = comm[4];
589141cc406Sopenharmony_ci
590141cc406Sopenharmony_ci  status = sanei_scsi_cmd(ms->sfd, comm, 6, data, &lenp);
591141cc406Sopenharmony_ci  *match = 1;
592141cc406Sopenharmony_ci  for (i=0; i<10; i++)
593141cc406Sopenharmony_ci    *match = *match && (ms->mode_sense_cache[i] == data[i]);
594141cc406Sopenharmony_ci
595141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
596141cc406Sopenharmony_ci    unsigned int i;
597141cc406Sopenharmony_ci#if 0
598141cc406Sopenharmony_ci    fprintf(stderr, "CMS: ");
599141cc406Sopenharmony_ci    for (i=0;i<lenp;i++) fprintf(stderr, "%2x(%2x) ",
600141cc406Sopenharmony_ci				 data[i],
601141cc406Sopenharmony_ci				 ms->mode_sense_cache[i]);
602141cc406Sopenharmony_ci    fprintf(stderr, "\n");
603141cc406Sopenharmony_ci#endif
604141cc406Sopenharmony_ci    MDBG_INIT("CMS: ");
605141cc406Sopenharmony_ci    for (i=0;i<lenp;i++) MDBG_ADD("%2x(%2x) ",
606141cc406Sopenharmony_ci				  data[i],
607141cc406Sopenharmony_ci				  ms->mode_sense_cache[i]);
608141cc406Sopenharmony_ci    MDBG_FINISH(192);
609141cc406Sopenharmony_ci  }
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci  return status;
612141cc406Sopenharmony_ci}
613141cc406Sopenharmony_ci
614141cc406Sopenharmony_ci/********************************************************************/
615141cc406Sopenharmony_ci/* send mode_sense_1, and upset every scsi driver known to mankind  */
616141cc406Sopenharmony_ci/********************************************************************/
617141cc406Sopenharmony_ci#if 0
618141cc406Sopenharmony_cistatic SANE_Status
619141cc406Sopenharmony_cimode_sense_1(Microtek_Scanner *ms)
620141cc406Sopenharmony_ci{
621141cc406Sopenharmony_ci  uint8_t *data, comm[36] = { 0x19, 0, 0, 0, 0x1E, 0 };
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci  DBG(23, ".mode_sense_1...\n");
624141cc406Sopenharmony_ci  data = comm + 6;
625141cc406Sopenharmony_ci  memset(data, 0, 30);
626141cc406Sopenharmony_ci  data[1] = ms->bright_r;
627141cc406Sopenharmony_ci  data[2] = ms->bright_g;
628141cc406Sopenharmony_ci  data[3] = ms->bright_b;
629141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
630141cc406Sopenharmony_ci    int i;
631141cc406Sopenharmony_ci    fprintf(stderr, "MS1: ");
632141cc406Sopenharmony_ci    for (i=0;i<6+0x1E;i++) fprintf(stderr, "%2x ", comm[i]);
633141cc406Sopenharmony_ci    fprintf(stderr, "\n");
634141cc406Sopenharmony_ci  }
635141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 6 + 0x1E, 0, 0);
636141cc406Sopenharmony_ci}
637141cc406Sopenharmony_ci#endif
638141cc406Sopenharmony_ci
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci
641141cc406Sopenharmony_ci/********************************************************************/
642141cc406Sopenharmony_ci/* send "accessory" command                                         */
643141cc406Sopenharmony_ci/********************************************************************/
644141cc406Sopenharmony_cistatic SANE_Status
645141cc406Sopenharmony_ciaccessory(Microtek_Scanner *ms)
646141cc406Sopenharmony_ci{
647141cc406Sopenharmony_ci  uint8_t comm[6] = { 0x10, 0, 0, 0, 0, 0 };
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci  DBG(23, ".accessory...\n");
650141cc406Sopenharmony_ci  comm[4] =
651141cc406Sopenharmony_ci    ((ms->useADF) ? 0x41 : 0x40) |
652141cc406Sopenharmony_ci    ((ms->prescan) ? 0x18 : 0x10) |
653141cc406Sopenharmony_ci    ((ms->transparency) ? 0x24 : 0x20) |
654141cc406Sopenharmony_ci    ((ms->allowbacktrack) ? 0x82 : 0x80);
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
657141cc406Sopenharmony_ci    int i;
658141cc406Sopenharmony_ci#if 0
659141cc406Sopenharmony_ci    fprintf(stderr, "AC: ");
660141cc406Sopenharmony_ci    for (i=0;i<6;i++) fprintf(stderr, "%2x ", comm[i]);
661141cc406Sopenharmony_ci    fprintf(stderr, "\n");
662141cc406Sopenharmony_ci#endif
663141cc406Sopenharmony_ci    MDBG_INIT("AC: ");
664141cc406Sopenharmony_ci    for (i=0;i<6;i++) MDBG_ADD("%2x ", comm[i]);
665141cc406Sopenharmony_ci    MDBG_FINISH(192);
666141cc406Sopenharmony_ci  }
667141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 6, 0, 0);
668141cc406Sopenharmony_ci}
669141cc406Sopenharmony_ci
670141cc406Sopenharmony_ci
671141cc406Sopenharmony_ci
672141cc406Sopenharmony_ci/********************************************************************/
673141cc406Sopenharmony_ci/* start the scanner a-scannin'                                     */
674141cc406Sopenharmony_ci/********************************************************************/
675141cc406Sopenharmony_cistatic SANE_Status
676141cc406Sopenharmony_cistart_scan(Microtek_Scanner *ms)
677141cc406Sopenharmony_ci{
678141cc406Sopenharmony_ci  uint8_t comm[6] = { 0x1B, 0, 0, 0, 0, 0 };
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci  DBG(23, ".start_scan...\n");
681141cc406Sopenharmony_ci  comm[4] =
682141cc406Sopenharmony_ci    0x01 |  /* "start" */
683141cc406Sopenharmony_ci    ((ms->expandedresolution) ? 0x80 : 0) |
684141cc406Sopenharmony_ci    ((ms->multibit) ? 0x40 : 0) |
685141cc406Sopenharmony_ci    ((ms->onepasscolor) ? 0x20 : 0) |
686141cc406Sopenharmony_ci    ((ms->reversecolors) ? 0x04 : 0) |
687141cc406Sopenharmony_ci    ((ms->fastprescan) ? 0x02 : 0) |
688141cc406Sopenharmony_ci    ((ms->filter == MS_FILT_RED) ? 0x08 : 0) |
689141cc406Sopenharmony_ci    ((ms->filter == MS_FILT_GREEN) ? 0x10 : 0) |
690141cc406Sopenharmony_ci    ((ms->filter == MS_FILT_BLUE) ? 0x18 : 0) ;
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
693141cc406Sopenharmony_ci    int i;
694141cc406Sopenharmony_ci#if 0
695141cc406Sopenharmony_ci    fprintf(stderr, "SS: ");
696141cc406Sopenharmony_ci    for (i=0;i<6;i++) fprintf(stderr, "%2x ", comm[i]);
697141cc406Sopenharmony_ci    fprintf(stderr, "\n");
698141cc406Sopenharmony_ci#endif
699141cc406Sopenharmony_ci    MDBG_INIT("SS: ");
700141cc406Sopenharmony_ci    for (i=0;i<6;i++) MDBG_ADD("%2x ", comm[i]);
701141cc406Sopenharmony_ci    MDBG_FINISH(192);
702141cc406Sopenharmony_ci  }
703141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 6, 0, 0);
704141cc406Sopenharmony_ci}
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ci
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci/********************************************************************/
709141cc406Sopenharmony_ci/* stop the scanner a-scannin'                                      */
710141cc406Sopenharmony_ci/********************************************************************/
711141cc406Sopenharmony_cistatic SANE_Status
712141cc406Sopenharmony_cistop_scan(Microtek_Scanner *ms)
713141cc406Sopenharmony_ci{
714141cc406Sopenharmony_ci  uint8_t comm[6] = { 0x1B, 0, 0, 0, 0, 0 };
715141cc406Sopenharmony_ci
716141cc406Sopenharmony_ci  DBG(23, ".stop_scan...\n");
717141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
718141cc406Sopenharmony_ci    int i;
719141cc406Sopenharmony_ci#if 0
720141cc406Sopenharmony_ci    fprintf(stderr, "SPS:");
721141cc406Sopenharmony_ci    for (i=0;i<6;i++) fprintf(stderr, "%2x ", comm[i]);
722141cc406Sopenharmony_ci    fprintf(stderr, "\n");
723141cc406Sopenharmony_ci#endif
724141cc406Sopenharmony_ci    MDBG_INIT("SPS:");
725141cc406Sopenharmony_ci    for (i=0;i<6;i++) MDBG_ADD("%2x ", comm[i]);
726141cc406Sopenharmony_ci    MDBG_FINISH(192);
727141cc406Sopenharmony_ci  }
728141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 6, 0, 0);
729141cc406Sopenharmony_ci}
730141cc406Sopenharmony_ci
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci
733141cc406Sopenharmony_ci/********************************************************************/
734141cc406Sopenharmony_ci/* get scan status                                                  */
735141cc406Sopenharmony_ci/********************************************************************/
736141cc406Sopenharmony_cistatic SANE_Status
737141cc406Sopenharmony_ciget_scan_status(Microtek_Scanner *ms,
738141cc406Sopenharmony_ci		SANE_Int *busy,
739141cc406Sopenharmony_ci		SANE_Int *bytes_per_line,
740141cc406Sopenharmony_ci		SANE_Int *lines)
741141cc406Sopenharmony_ci{
742141cc406Sopenharmony_ci  uint8_t data[6], comm[6] = { 0x0F, 0, 0, 0, 0x06, 0 };
743141cc406Sopenharmony_ci  SANE_Status status;
744141cc406Sopenharmony_ci  size_t lenp;
745141cc406Sopenharmony_ci  int retry = 0;
746141cc406Sopenharmony_ci
747141cc406Sopenharmony_ci  DBG(23, ".get_scan_status %d...\n", ms->sfd);
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ci  do {
750141cc406Sopenharmony_ci    lenp = 6;
751141cc406Sopenharmony_ci    /* do some retry stuff in here, too */
752141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd, comm, 6, data, &lenp);
753141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) {
754141cc406Sopenharmony_ci      DBG(20, "get_scan_status:  scsi error\n");
755141cc406Sopenharmony_ci      return status;
756141cc406Sopenharmony_ci    }
757141cc406Sopenharmony_ci    *busy = data[0];
758141cc406Sopenharmony_ci    *bytes_per_line = (data[1]) + (data[2] << 8);
759141cc406Sopenharmony_ci    *lines = (data[3]) + (data[4] << 8) + (data[5] << 16);
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci    DBG(20, "get_scan_status(%lu): %d, %d, %d  -> #%d\n",
762141cc406Sopenharmony_ci	(u_long) lenp, *busy, *bytes_per_line, *lines, retry);
763141cc406Sopenharmony_ci    DBG(20, "> %2x %2x %2x %2x %2x %2x\n",
764141cc406Sopenharmony_ci	    data[0], data[1], data[2], data[3], data[4], data[5]);
765141cc406Sopenharmony_ci    if (*busy != 0) {
766141cc406Sopenharmony_ci      retry++;
767141cc406Sopenharmony_ci      DBG(23, "get_scan_status:  busy, retry in %d...\n",
768141cc406Sopenharmony_ci	  M_GSS_WAIT * retry);
769141cc406Sopenharmony_ci      sleep(M_GSS_WAIT * retry);
770141cc406Sopenharmony_ci    }
771141cc406Sopenharmony_ci  } while ((*busy != 0) && (retry < 4));
772141cc406Sopenharmony_ci
773141cc406Sopenharmony_ci  if (*busy == 0) return status;
774141cc406Sopenharmony_ci  else return SANE_STATUS_IO_ERROR;
775141cc406Sopenharmony_ci}
776141cc406Sopenharmony_ci
777141cc406Sopenharmony_ci
778141cc406Sopenharmony_ci
779141cc406Sopenharmony_ci/********************************************************************/
780141cc406Sopenharmony_ci/* get scanlines from scanner                                       */
781141cc406Sopenharmony_ci/********************************************************************/
782141cc406Sopenharmony_cistatic SANE_Status
783141cc406Sopenharmony_ciread_scan_data(Microtek_Scanner *ms,
784141cc406Sopenharmony_ci	       int lines,
785141cc406Sopenharmony_ci	       uint8_t *buffer,
786141cc406Sopenharmony_ci	       size_t *bufsize)
787141cc406Sopenharmony_ci{
788141cc406Sopenharmony_ci  uint8_t comm[6] = { 0x08, 0, 0, 0, 0, 0 };
789141cc406Sopenharmony_ci
790141cc406Sopenharmony_ci  DBG(23, ".read_scan_data...\n");
791141cc406Sopenharmony_ci  comm[2] = (lines >> 16) & 0xFF;
792141cc406Sopenharmony_ci  comm[3] = (lines >> 8) & 0xFF;
793141cc406Sopenharmony_ci  comm[4] = (lines) & 0xFF;
794141cc406Sopenharmony_ci
795141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 6, buffer, bufsize);
796141cc406Sopenharmony_ci}
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_ci
799141cc406Sopenharmony_ci
800141cc406Sopenharmony_ci/********************************************************************/
801141cc406Sopenharmony_ci/* download color LUT to scanner (if it takes one)                  */
802141cc406Sopenharmony_ci/********************************************************************/
803141cc406Sopenharmony_cistatic SANE_Status
804141cc406Sopenharmony_cidownload_gamma(Microtek_Scanner *ms)
805141cc406Sopenharmony_ci{
806141cc406Sopenharmony_ci  uint8_t *data, *comm; /* commbytes[10] = { 0x55, 0, 0x27, 0, 0,
807141cc406Sopenharmony_ci						0, 0,    0, 0, 0 };*/
808141cc406Sopenharmony_ci  int i, pl;
809141cc406Sopenharmony_ci  int commsize;
810141cc406Sopenharmony_ci  int bit_depth = 8; /* hard-code for now, should match bpp XXXXXXX */
811141cc406Sopenharmony_ci  int max_entry;
812141cc406Sopenharmony_ci  SANE_Status status;
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci  DBG(23, ".download_gamma...\n");
815141cc406Sopenharmony_ci  /* skip if scanner doesn't take 'em */
816141cc406Sopenharmony_ci  if (!(ms->gamma_entries)) {
817141cc406Sopenharmony_ci    DBG(23, ".download_gamma:  no entries; skipping\n");
818141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
819141cc406Sopenharmony_ci  }
820141cc406Sopenharmony_ci  if ((ms->gamma_entry_size != 1) && (ms->gamma_entry_size != 2)) {
821141cc406Sopenharmony_ci    DBG(23, ".download_gamma:  entry size %d?!?!?\n", ms->gamma_entry_size);
822141cc406Sopenharmony_ci    return SANE_STATUS_INVAL; /* XXXXXXXxx */
823141cc406Sopenharmony_ci  }
824141cc406Sopenharmony_ci
825141cc406Sopenharmony_ci  max_entry = (1 << bit_depth) - 1;
826141cc406Sopenharmony_ci
827141cc406Sopenharmony_ci  DBG(23, ".download_gamma:  %d entries of %d bytes, max %d\n",
828141cc406Sopenharmony_ci      ms->gamma_entries, ms->gamma_entry_size, max_entry);
829141cc406Sopenharmony_ci  commsize = 10 + (ms->gamma_entries * ms->gamma_entry_size);
830141cc406Sopenharmony_ci  comm = calloc(commsize, sizeof(uint8_t));
831141cc406Sopenharmony_ci  if (comm == NULL) {
832141cc406Sopenharmony_ci    DBG(23, ".download_gamma:  couldn't allocate %d bytes for comm buffer!\n",
833141cc406Sopenharmony_ci	commsize);
834141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
835141cc406Sopenharmony_ci  }
836141cc406Sopenharmony_ci  data = comm + 10;
837141cc406Sopenharmony_ci
838141cc406Sopenharmony_ci  comm[0] = 0x55;
839141cc406Sopenharmony_ci  comm[1] = 0;
840141cc406Sopenharmony_ci  comm[2] = 0x27;
841141cc406Sopenharmony_ci  comm[3] = 0;
842141cc406Sopenharmony_ci  comm[4] = 0;
843141cc406Sopenharmony_ci  comm[5] = 0;
844141cc406Sopenharmony_ci  comm[6] = 0;
845141cc406Sopenharmony_ci  comm[7] = ((ms->gamma_entries * ms->gamma_entry_size) >> 8) & 0xFF;
846141cc406Sopenharmony_ci  comm[8] = (ms->gamma_entries * ms->gamma_entry_size) & 0xFF;
847141cc406Sopenharmony_ci  comm[9] = (ms->gamma_entry_size == 2) ? 1 : 0;
848141cc406Sopenharmony_ci
849141cc406Sopenharmony_ci  if (!(strcmp(ms->val[OPT_CUSTOM_GAMMA].s, M_TABLE))) {
850141cc406Sopenharmony_ci    /***** Gamma by TABLE *****/
851141cc406Sopenharmony_ci    int table_shift = (ms->gamma_bit_depth - bit_depth);
852141cc406Sopenharmony_ci
853141cc406Sopenharmony_ci    DBG(23, ".download_gamma: by table (%d bpe, %d shift)\n",
854141cc406Sopenharmony_ci	ms->gamma_bit_depth, table_shift);
855141cc406Sopenharmony_ci
856141cc406Sopenharmony_ci    if (ms->val[OPT_GAMMA_BIND].w == SANE_TRUE) {
857141cc406Sopenharmony_ci      for (i=0; i<ms->gamma_entries; i++) {
858141cc406Sopenharmony_ci	int val = ms->gray_lut[i] >> table_shift;
859141cc406Sopenharmony_ci	switch (ms->gamma_entry_size) {
860141cc406Sopenharmony_ci	case 1:
861141cc406Sopenharmony_ci	  data[i] = (uint8_t) val;
862141cc406Sopenharmony_ci	  break;
863141cc406Sopenharmony_ci	case 2:
864141cc406Sopenharmony_ci	  data[i*2] =  val & 0xFF;
865141cc406Sopenharmony_ci	  data[(i*2)+1] = (val>>8) & 0xFF;
866141cc406Sopenharmony_ci	  break;
867141cc406Sopenharmony_ci	}
868141cc406Sopenharmony_ci      }
869141cc406Sopenharmony_ci      status = sanei_scsi_cmd(ms->sfd, comm, commsize, 0, 0);
870141cc406Sopenharmony_ci    } else {
871141cc406Sopenharmony_ci      pl = 1;
872141cc406Sopenharmony_ci      do {
873141cc406Sopenharmony_ci	SANE_Int *pl_lut;
874141cc406Sopenharmony_ci	switch (pl) {
875141cc406Sopenharmony_ci	case 1: pl_lut = ms->red_lut;   break;
876141cc406Sopenharmony_ci	case 2: pl_lut = ms->green_lut; break;
877141cc406Sopenharmony_ci	case 3: pl_lut = ms->blue_lut;  break;
878141cc406Sopenharmony_ci	default:
879141cc406Sopenharmony_ci	  DBG(23, ".download_gamma:  uh, exceeded pl bound!\n");
880141cc406Sopenharmony_ci	  free(comm);
881141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL; /* XXXXXXXxx */
882141cc406Sopenharmony_ci	  break;
883141cc406Sopenharmony_ci	}
884141cc406Sopenharmony_ci	for (i=0; i<ms->gamma_entries; i++) {
885141cc406Sopenharmony_ci	  int val = pl_lut[i] >> table_shift;
886141cc406Sopenharmony_ci	  switch (ms->gamma_entry_size) {
887141cc406Sopenharmony_ci	  case 1:
888141cc406Sopenharmony_ci	    data[i] = (uint8_t) val;
889141cc406Sopenharmony_ci	    break;
890141cc406Sopenharmony_ci	  case 2:
891141cc406Sopenharmony_ci	    data[i*2] =  val & 0xFF;
892141cc406Sopenharmony_ci	    data[(i*2)+1] =  (val>>8) & 0xFF;
893141cc406Sopenharmony_ci	    break;
894141cc406Sopenharmony_ci	  }
895141cc406Sopenharmony_ci	}
896141cc406Sopenharmony_ci	/* XXXXXXX */
897141cc406Sopenharmony_ci	comm[9] = (comm[9] & 0x3F) | (pl << 6);
898141cc406Sopenharmony_ci	status = sanei_scsi_cmd(ms->sfd, comm, commsize, 0, 0);
899141cc406Sopenharmony_ci	pl++;
900141cc406Sopenharmony_ci      } while ((pl < 4) && (status == SANE_STATUS_GOOD));
901141cc406Sopenharmony_ci    }
902141cc406Sopenharmony_ci  } else if (!(strcmp(ms->val[OPT_CUSTOM_GAMMA].s, M_SCALAR))) {
903141cc406Sopenharmony_ci    /***** Gamma by SCALAR *****/
904141cc406Sopenharmony_ci    DBG(23, ".download_gamma: by scalar\n");
905141cc406Sopenharmony_ci    if (ms->val[OPT_GAMMA_BIND].w == SANE_TRUE) {
906141cc406Sopenharmony_ci      double gamma = SANE_UNFIX(ms->val[OPT_ANALOG_GAMMA].w);
907141cc406Sopenharmony_ci      for (i=0; i<ms->gamma_entries; i++) {
908141cc406Sopenharmony_ci	int val =  (max_entry *
909141cc406Sopenharmony_ci		    pow((double) i / ((double) ms->gamma_entries - 1.0),
910141cc406Sopenharmony_ci			1.0 / gamma));
911141cc406Sopenharmony_ci	switch (ms->gamma_entry_size) {
912141cc406Sopenharmony_ci	case 1:
913141cc406Sopenharmony_ci	  data[i] = (uint8_t) val;
914141cc406Sopenharmony_ci	  break;
915141cc406Sopenharmony_ci	case 2:
916141cc406Sopenharmony_ci	  data[i*2] = val & 0xFF;
917141cc406Sopenharmony_ci	  data[(i*2)+1] = (val>>8) & 0xFF;
918141cc406Sopenharmony_ci	  break;
919141cc406Sopenharmony_ci	}
920141cc406Sopenharmony_ci      }
921141cc406Sopenharmony_ci      status = sanei_scsi_cmd(ms->sfd, comm, commsize, 0, 0);
922141cc406Sopenharmony_ci    } else {
923141cc406Sopenharmony_ci      double gamma;
924141cc406Sopenharmony_ci      pl = 1;
925141cc406Sopenharmony_ci      do {
926141cc406Sopenharmony_ci	switch (pl) {
927141cc406Sopenharmony_ci	case 1: gamma = SANE_UNFIX(ms->val[OPT_ANALOG_GAMMA_R].w); break;
928141cc406Sopenharmony_ci	case 2: gamma = SANE_UNFIX(ms->val[OPT_ANALOG_GAMMA_G].w); break;
929141cc406Sopenharmony_ci	case 3: gamma = SANE_UNFIX(ms->val[OPT_ANALOG_GAMMA_B].w); break;
930141cc406Sopenharmony_ci	default: gamma = 1.0; break; /* should never happen */
931141cc406Sopenharmony_ci	}
932141cc406Sopenharmony_ci	for (i=0; i<ms->gamma_entries; i++) {
933141cc406Sopenharmony_ci	  int val =  (max_entry *
934141cc406Sopenharmony_ci		      pow((double) i / ((double) ms->gamma_entries - 1.0),
935141cc406Sopenharmony_ci			  1.0 / gamma));
936141cc406Sopenharmony_ci	  switch (ms->gamma_entry_size) {
937141cc406Sopenharmony_ci	    case 1:
938141cc406Sopenharmony_ci	      data[i] = (uint8_t) val;
939141cc406Sopenharmony_ci	      break;
940141cc406Sopenharmony_ci	  case 2:
941141cc406Sopenharmony_ci	    data[i*2] = val & 0xFF;
942141cc406Sopenharmony_ci	    data[(i*2)+1] = (val>>8) & 0xFF;
943141cc406Sopenharmony_ci	    break;
944141cc406Sopenharmony_ci	  }
945141cc406Sopenharmony_ci	}
946141cc406Sopenharmony_ci	comm[9] = (comm[9] & 0x3F) | (pl << 6);
947141cc406Sopenharmony_ci	status = sanei_scsi_cmd(ms->sfd, comm, commsize, 0, 0);
948141cc406Sopenharmony_ci	pl++;
949141cc406Sopenharmony_ci      } while ((pl < 4) && (status == SANE_STATUS_GOOD));
950141cc406Sopenharmony_ci    }
951141cc406Sopenharmony_ci  } else {
952141cc406Sopenharmony_ci    /***** No custom Gamma *****/
953141cc406Sopenharmony_ci    DBG(23, ".download_gamma: by default\n");
954141cc406Sopenharmony_ci    for (i=0; i<ms->gamma_entries; i++) {
955141cc406Sopenharmony_ci      /*      int val =  (((double) max_entry * (double) i /
956141cc406Sopenharmony_ci	      ((double) ms->gamma_entries - 1.0)) + 0.5);     ROUNDING????*/
957141cc406Sopenharmony_ci      int val =
958141cc406Sopenharmony_ci	(double) max_entry * (double) i /
959141cc406Sopenharmony_ci	((double) ms->gamma_entries - 1.0);
960141cc406Sopenharmony_ci      switch (ms->gamma_entry_size) {
961141cc406Sopenharmony_ci      case 1:
962141cc406Sopenharmony_ci	data[i] = (uint8_t) val;
963141cc406Sopenharmony_ci	break;
964141cc406Sopenharmony_ci      case 2:
965141cc406Sopenharmony_ci	data[i*2] = val & 0xFF;
966141cc406Sopenharmony_ci	data[(i*2)+1] = (val >> 8) & 0xFF;
967141cc406Sopenharmony_ci	break;
968141cc406Sopenharmony_ci      }
969141cc406Sopenharmony_ci    }
970141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd, comm, commsize, 0, 0);
971141cc406Sopenharmony_ci  }
972141cc406Sopenharmony_ci  free(comm);
973141cc406Sopenharmony_ci  return status;
974141cc406Sopenharmony_ci}
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci
977141cc406Sopenharmony_ci/********************************************************************/
978141cc406Sopenharmony_ci/* magic command to start calibration                               */
979141cc406Sopenharmony_ci/********************************************************************/
980141cc406Sopenharmony_cistatic SANE_Status
981141cc406Sopenharmony_cistart_calibration(Microtek_Scanner *ms)
982141cc406Sopenharmony_ci{
983141cc406Sopenharmony_ci  uint8_t comm[8] = { 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x0a };
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci  DBG(23, ".start_calibrate...\n");
986141cc406Sopenharmony_ci  if (DBG_LEVEL >= 192) {
987141cc406Sopenharmony_ci    int i;
988141cc406Sopenharmony_ci#if 0
989141cc406Sopenharmony_ci    fprintf(stderr, "STCal:");
990141cc406Sopenharmony_ci    for (i=0;i<8;i++) fprintf(stderr, "%2x ", comm[i]);
991141cc406Sopenharmony_ci    fprintf(stderr, "\n");
992141cc406Sopenharmony_ci#endif
993141cc406Sopenharmony_ci    MDBG_INIT("STCal:");
994141cc406Sopenharmony_ci    for (i=0;i<8;i++) MDBG_ADD("%2x ", comm[i]);
995141cc406Sopenharmony_ci    MDBG_FINISH(192);
996141cc406Sopenharmony_ci  }
997141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 8, 0, 0);
998141cc406Sopenharmony_ci}
999141cc406Sopenharmony_ci
1000141cc406Sopenharmony_ci
1001141cc406Sopenharmony_ci
1002141cc406Sopenharmony_ci/********************************************************************/
1003141cc406Sopenharmony_ci/* magic command to download calibration values                     */
1004141cc406Sopenharmony_ci/********************************************************************/
1005141cc406Sopenharmony_cistatic SANE_Status
1006141cc406Sopenharmony_cidownload_calibration(Microtek_Scanner *ms, uint8_t *comm,
1007141cc406Sopenharmony_ci		     uint8_t letter, int linewidth)
1008141cc406Sopenharmony_ci{
1009141cc406Sopenharmony_ci  DBG(23, ".download_calibration... %c %d\n", letter, linewidth);
1010141cc406Sopenharmony_ci
1011141cc406Sopenharmony_ci  comm[0] = 0x0c;
1012141cc406Sopenharmony_ci  comm[1] = 0x00;
1013141cc406Sopenharmony_ci  comm[2] = 0x00;
1014141cc406Sopenharmony_ci  comm[3] = (linewidth >> 8) & 0xFF;
1015141cc406Sopenharmony_ci  comm[4] = linewidth & 0xFF;
1016141cc406Sopenharmony_ci  comm[5] = 0x00;
1017141cc406Sopenharmony_ci
1018141cc406Sopenharmony_ci  comm[6] = 0x00;
1019141cc406Sopenharmony_ci  switch (letter) {
1020141cc406Sopenharmony_ci  case 'R': comm[7] = 0x40; break;
1021141cc406Sopenharmony_ci  case 'G': comm[7] = 0x80; break;
1022141cc406Sopenharmony_ci  case 'B': comm[7] = 0xc0; break;
1023141cc406Sopenharmony_ci  default: /* XXXXXXX */ break;
1024141cc406Sopenharmony_ci  }
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci  return sanei_scsi_cmd(ms->sfd, comm, 6 + linewidth, 0, 0);
1027141cc406Sopenharmony_ci}
1028141cc406Sopenharmony_ci
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci
1031141cc406Sopenharmony_ci/********************************************************************/
1032141cc406Sopenharmony_ci/********************************************************************/
1033141cc406Sopenharmony_ci/*                                                                  */
1034141cc406Sopenharmony_ci/* Myriad of internal functions                                     */
1035141cc406Sopenharmony_ci/*                                                                  */
1036141cc406Sopenharmony_ci/********************************************************************/
1037141cc406Sopenharmony_ci/********************************************************************/
1038141cc406Sopenharmony_ci
1039141cc406Sopenharmony_ci
1040141cc406Sopenharmony_ci
1041141cc406Sopenharmony_ci/********************************************************************/
1042141cc406Sopenharmony_ci/* Initialize the options registry                                  */
1043141cc406Sopenharmony_ci/********************************************************************/
1044141cc406Sopenharmony_cistatic SANE_Status
1045141cc406Sopenharmony_ciinit_options(Microtek_Scanner *ms)
1046141cc406Sopenharmony_ci{
1047141cc406Sopenharmony_ci  int i;
1048141cc406Sopenharmony_ci  SANE_Option_Descriptor *sod = ms->sod;
1049141cc406Sopenharmony_ci  Option_Value *val = ms->val;
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci  DBG(15, "init_options...\n");
1052141cc406Sopenharmony_ci
1053141cc406Sopenharmony_ci  memset(ms->sod, 0, sizeof(ms->sod));
1054141cc406Sopenharmony_ci  memset(ms->val, 0, sizeof(ms->val));
1055141cc406Sopenharmony_ci  /* default:  software selectable word options... */
1056141cc406Sopenharmony_ci  for (i=0; i<NUM_OPTIONS; i++) {
1057141cc406Sopenharmony_ci    sod[i].size = sizeof(SANE_Word);
1058141cc406Sopenharmony_ci    sod[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1059141cc406Sopenharmony_ci  }
1060141cc406Sopenharmony_ci
1061141cc406Sopenharmony_ci  sod[OPT_NUM_OPTS].name =   SANE_NAME_NUM_OPTIONS;
1062141cc406Sopenharmony_ci  sod[OPT_NUM_OPTS].title =  SANE_TITLE_NUM_OPTIONS;
1063141cc406Sopenharmony_ci  sod[OPT_NUM_OPTS].desc =   SANE_DESC_NUM_OPTIONS;
1064141cc406Sopenharmony_ci  sod[OPT_NUM_OPTS].type =   SANE_TYPE_INT;
1065141cc406Sopenharmony_ci  sod[OPT_NUM_OPTS].unit =   SANE_UNIT_NONE;
1066141cc406Sopenharmony_ci  sod[OPT_NUM_OPTS].size =   sizeof (SANE_Word);
1067141cc406Sopenharmony_ci  sod[OPT_NUM_OPTS].cap =    SANE_CAP_SOFT_DETECT;
1068141cc406Sopenharmony_ci  sod[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
1069141cc406Sopenharmony_ci
1070141cc406Sopenharmony_ci  /* The Scan Mode Group */
1071141cc406Sopenharmony_ci  sod[OPT_MODE_GROUP].name  = "";
1072141cc406Sopenharmony_ci  sod[OPT_MODE_GROUP].title = "Scan Mode";
1073141cc406Sopenharmony_ci  sod[OPT_MODE_GROUP].desc  = "";
1074141cc406Sopenharmony_ci  sod[OPT_MODE_GROUP].type  = SANE_TYPE_GROUP;
1075141cc406Sopenharmony_ci  sod[OPT_MODE_GROUP].cap   = 0;
1076141cc406Sopenharmony_ci  sod[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1077141cc406Sopenharmony_ci
1078141cc406Sopenharmony_ci  sod[OPT_MODE].name = SANE_NAME_SCAN_MODE;
1079141cc406Sopenharmony_ci  sod[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
1080141cc406Sopenharmony_ci  sod[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
1081141cc406Sopenharmony_ci  sod[OPT_MODE].type = SANE_TYPE_STRING;
1082141cc406Sopenharmony_ci  sod[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1083141cc406Sopenharmony_ci  {
1084141cc406Sopenharmony_ci    SANE_String_Const *mode_list;
1085141cc406Sopenharmony_ci    mode_list = (SANE_String_Const *) malloc(5 * sizeof(SANE_String_Const));
1086141cc406Sopenharmony_ci    if (mode_list == NULL) return SANE_STATUS_NO_MEM;
1087141cc406Sopenharmony_ci    i = 0;
1088141cc406Sopenharmony_ci    if (ms->dev->info.modes & MI_MODES_COLOR)    mode_list[i++] = M_COLOR;
1089141cc406Sopenharmony_ci    if (ms->dev->info.modes & MI_MODES_GRAY)     mode_list[i++] = M_GRAY;
1090141cc406Sopenharmony_ci    if (ms->dev->info.modes & MI_MODES_HALFTONE) mode_list[i++] = M_HALFTONE;
1091141cc406Sopenharmony_ci    if (ms->dev->info.modes & MI_MODES_LINEART)  mode_list[i++] = M_LINEART;
1092141cc406Sopenharmony_ci    mode_list[i] = NULL;
1093141cc406Sopenharmony_ci    sod[OPT_MODE].constraint.string_list = mode_list;
1094141cc406Sopenharmony_ci    sod[OPT_MODE].size                   = max_string_size(mode_list);
1095141cc406Sopenharmony_ci    val[OPT_MODE].s = strdup(mode_list[0]);
1096141cc406Sopenharmony_ci  }
1097141cc406Sopenharmony_ci
1098141cc406Sopenharmony_ci  sod[OPT_RESOLUTION].name  = SANE_NAME_SCAN_RESOLUTION;
1099141cc406Sopenharmony_ci  sod[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
1100141cc406Sopenharmony_ci  sod[OPT_RESOLUTION].desc  = SANE_DESC_SCAN_RESOLUTION;
1101141cc406Sopenharmony_ci  sod[OPT_RESOLUTION].type  = SANE_TYPE_FIXED;
1102141cc406Sopenharmony_ci  sod[OPT_RESOLUTION].unit  = SANE_UNIT_DPI;
1103141cc406Sopenharmony_ci  sod[OPT_RESOLUTION].constraint_type  = SANE_CONSTRAINT_RANGE;
1104141cc406Sopenharmony_ci  {
1105141cc406Sopenharmony_ci    SANE_Int maxres = ms->dev->info.base_resolution;
1106141cc406Sopenharmony_ci
1107141cc406Sopenharmony_ci    ms->res_range.max = SANE_FIX(maxres);
1108141cc406Sopenharmony_ci    ms->exp_res_range.max = SANE_FIX(2 * maxres);
1109141cc406Sopenharmony_ci    if (ms->dev->info.res_step & MI_RESSTEP_1PER) {
1110141cc406Sopenharmony_ci      DBG(23, "init_options:  quant yes\n");
1111141cc406Sopenharmony_ci      ms->res_range.min = SANE_FIX( maxres / 100 );
1112141cc406Sopenharmony_ci      ms->res_range.quant = ms->res_range.min;
1113141cc406Sopenharmony_ci      ms->exp_res_range.min = SANE_FIX(2 * maxres / 100);
1114141cc406Sopenharmony_ci      ms->exp_res_range.quant = ms->exp_res_range.min;
1115141cc406Sopenharmony_ci    } else {
1116141cc406Sopenharmony_ci      /* XXXXXXXXXXX */
1117141cc406Sopenharmony_ci      DBG(23, "init_options:  quant no\n");
1118141cc406Sopenharmony_ci      ms->res_range.quant = SANE_FIX( 0 );
1119141cc406Sopenharmony_ci    }
1120141cc406Sopenharmony_ci    sod[OPT_RESOLUTION].constraint.range = &(ms->res_range);
1121141cc406Sopenharmony_ci  }
1122141cc406Sopenharmony_ci  val[OPT_RESOLUTION].w     = SANE_FIX(100);
1123141cc406Sopenharmony_ci
1124141cc406Sopenharmony_ci  sod[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
1125141cc406Sopenharmony_ci  sod[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
1126141cc406Sopenharmony_ci  sod[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
1127141cc406Sopenharmony_ci  sod[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING;
1128141cc406Sopenharmony_ci  sod[OPT_HALFTONE_PATTERN].size = max_string_size(halftone_mode_list);
1129141cc406Sopenharmony_ci  sod[OPT_HALFTONE_PATTERN].cap  |= SANE_CAP_INACTIVE;
1130141cc406Sopenharmony_ci  sod[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1131141cc406Sopenharmony_ci  sod[OPT_HALFTONE_PATTERN].constraint.string_list = halftone_mode_list;
1132141cc406Sopenharmony_ci  val[OPT_HALFTONE_PATTERN].s = strdup(halftone_mode_list[0]);
1133141cc406Sopenharmony_ci
1134141cc406Sopenharmony_ci  sod[OPT_NEGATIVE].name  = SANE_NAME_NEGATIVE;
1135141cc406Sopenharmony_ci  sod[OPT_NEGATIVE].title = SANE_TITLE_NEGATIVE;
1136141cc406Sopenharmony_ci  sod[OPT_NEGATIVE].desc  = SANE_DESC_NEGATIVE;
1137141cc406Sopenharmony_ci  sod[OPT_NEGATIVE].type  = SANE_TYPE_BOOL;
1138141cc406Sopenharmony_ci  sod[OPT_NEGATIVE].cap   |=
1139141cc406Sopenharmony_ci    (ms->dev->info.modes & MI_MODES_NEGATIVE) ? 0 : SANE_CAP_INACTIVE;
1140141cc406Sopenharmony_ci  val[OPT_NEGATIVE].w     = SANE_FALSE;
1141141cc406Sopenharmony_ci
1142141cc406Sopenharmony_ci  sod[OPT_SPEED].name  = SANE_NAME_SCAN_SPEED;
1143141cc406Sopenharmony_ci  sod[OPT_SPEED].title = SANE_TITLE_SCAN_SPEED;
1144141cc406Sopenharmony_ci  /*  sod[OPT_SPEED].desc  = SANE_DESC_SCAN_SPEED;*/
1145141cc406Sopenharmony_ci  sod[OPT_SPEED].desc  = "Scan speed throttle -- higher values are *slower*.";
1146141cc406Sopenharmony_ci  sod[OPT_SPEED].type  = SANE_TYPE_INT;
1147141cc406Sopenharmony_ci  sod[OPT_SPEED].cap   |= SANE_CAP_ADVANCED;
1148141cc406Sopenharmony_ci  sod[OPT_SPEED].unit  = SANE_UNIT_NONE;
1149141cc406Sopenharmony_ci  sod[OPT_SPEED].size  = sizeof(SANE_Word);
1150141cc406Sopenharmony_ci  sod[OPT_SPEED].constraint_type = SANE_CONSTRAINT_RANGE;
1151141cc406Sopenharmony_ci  sod[OPT_SPEED].constraint.range = &speed_range;
1152141cc406Sopenharmony_ci  val[OPT_SPEED].w     = 1;
1153141cc406Sopenharmony_ci
1154141cc406Sopenharmony_ci  sod[OPT_SOURCE].name  = SANE_NAME_SCAN_SOURCE;
1155141cc406Sopenharmony_ci  sod[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
1156141cc406Sopenharmony_ci  sod[OPT_SOURCE].desc  = SANE_DESC_SCAN_SOURCE;
1157141cc406Sopenharmony_ci  sod[OPT_SOURCE].type  = SANE_TYPE_STRING;
1158141cc406Sopenharmony_ci  sod[OPT_SOURCE].unit  = SANE_UNIT_NONE;
1159141cc406Sopenharmony_ci  sod[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1160141cc406Sopenharmony_ci  {
1161141cc406Sopenharmony_ci    SANE_String_Const *source_list;
1162141cc406Sopenharmony_ci    source_list = (SANE_String_Const *) malloc(4 * sizeof(SANE_String_Const));
1163141cc406Sopenharmony_ci    if (source_list == NULL) return SANE_STATUS_NO_MEM;
1164141cc406Sopenharmony_ci    i = 0;
1165141cc406Sopenharmony_ci    source_list[i++] = M_OPAQUE;
1166141cc406Sopenharmony_ci    if (ms->dev->info.source_options & MI_SRC_HAS_TRANS)
1167141cc406Sopenharmony_ci      source_list[i++] = M_TRANS;
1168141cc406Sopenharmony_ci    if (ms->dev->info.source_options & MI_SRC_HAS_FEED)
1169141cc406Sopenharmony_ci      source_list[i++] = M_AUTOFEED;
1170141cc406Sopenharmony_ci    source_list[i] = NULL;
1171141cc406Sopenharmony_ci    sod[OPT_SOURCE].constraint.string_list = source_list;
1172141cc406Sopenharmony_ci    sod[OPT_SOURCE].size                   = max_string_size(source_list);
1173141cc406Sopenharmony_ci    if (i < 2)
1174141cc406Sopenharmony_ci      sod[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
1175141cc406Sopenharmony_ci    val[OPT_SOURCE].s = strdup(source_list[0]);
1176141cc406Sopenharmony_ci  }
1177141cc406Sopenharmony_ci
1178141cc406Sopenharmony_ci  sod[OPT_PREVIEW].name  = SANE_NAME_PREVIEW;
1179141cc406Sopenharmony_ci  sod[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
1180141cc406Sopenharmony_ci  sod[OPT_PREVIEW].desc  = SANE_DESC_PREVIEW;
1181141cc406Sopenharmony_ci  sod[OPT_PREVIEW].type  = SANE_TYPE_BOOL;
1182141cc406Sopenharmony_ci  sod[OPT_PREVIEW].unit  = SANE_UNIT_NONE;
1183141cc406Sopenharmony_ci  sod[OPT_PREVIEW].size  = sizeof(SANE_Word);
1184141cc406Sopenharmony_ci  val[OPT_PREVIEW].w     = SANE_FALSE;
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci
1187141cc406Sopenharmony_ci  sod[OPT_GEOMETRY_GROUP].name  = "";
1188141cc406Sopenharmony_ci  sod[OPT_GEOMETRY_GROUP].title = "Geometry";
1189141cc406Sopenharmony_ci  sod[OPT_GEOMETRY_GROUP].desc  = "";
1190141cc406Sopenharmony_ci  sod[OPT_GEOMETRY_GROUP].type  = SANE_TYPE_GROUP;
1191141cc406Sopenharmony_ci  sod[OPT_GEOMETRY_GROUP].cap   = SANE_CAP_ADVANCED;
1192141cc406Sopenharmony_ci  sod[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1193141cc406Sopenharmony_ci
1194141cc406Sopenharmony_ci
1195141cc406Sopenharmony_ci  sod[OPT_TL_X].name  = SANE_NAME_SCAN_TL_X;
1196141cc406Sopenharmony_ci  sod[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
1197141cc406Sopenharmony_ci  sod[OPT_TL_X].desc  = SANE_DESC_SCAN_TL_X;
1198141cc406Sopenharmony_ci  sod[OPT_TL_X].type  = SANE_TYPE_FIXED;
1199141cc406Sopenharmony_ci  sod[OPT_TL_X].unit  = SANE_UNIT_MM;
1200141cc406Sopenharmony_ci  sod[OPT_TL_X].size  = sizeof(SANE_Word);
1201141cc406Sopenharmony_ci  sod[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1202141cc406Sopenharmony_ci
1203141cc406Sopenharmony_ci  sod[OPT_TL_Y].name  = SANE_NAME_SCAN_TL_Y;
1204141cc406Sopenharmony_ci  sod[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
1205141cc406Sopenharmony_ci  sod[OPT_TL_Y].desc  = SANE_DESC_SCAN_TL_Y;
1206141cc406Sopenharmony_ci  sod[OPT_TL_Y].type  = SANE_TYPE_FIXED;
1207141cc406Sopenharmony_ci  sod[OPT_TL_Y].unit  = SANE_UNIT_MM;
1208141cc406Sopenharmony_ci  sod[OPT_TL_Y].size  = sizeof(SANE_Word);
1209141cc406Sopenharmony_ci  sod[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1210141cc406Sopenharmony_ci
1211141cc406Sopenharmony_ci  sod[OPT_BR_X].name  = SANE_NAME_SCAN_BR_X;
1212141cc406Sopenharmony_ci  sod[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
1213141cc406Sopenharmony_ci  sod[OPT_BR_X].desc  = SANE_DESC_SCAN_BR_X;
1214141cc406Sopenharmony_ci  sod[OPT_BR_X].type  = SANE_TYPE_FIXED;
1215141cc406Sopenharmony_ci  sod[OPT_BR_X].unit  = SANE_UNIT_MM;
1216141cc406Sopenharmony_ci  sod[OPT_BR_X].size  = sizeof(SANE_Word);
1217141cc406Sopenharmony_ci  sod[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_ci  sod[OPT_BR_Y].name  = SANE_NAME_SCAN_BR_Y;
1220141cc406Sopenharmony_ci  sod[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1221141cc406Sopenharmony_ci  sod[OPT_BR_Y].desc  = SANE_DESC_SCAN_BR_Y;
1222141cc406Sopenharmony_ci  sod[OPT_BR_Y].type  = SANE_TYPE_FIXED;
1223141cc406Sopenharmony_ci  sod[OPT_BR_Y].unit  = SANE_UNIT_MM;
1224141cc406Sopenharmony_ci  sod[OPT_BR_Y].size  = sizeof(SANE_Word);
1225141cc406Sopenharmony_ci  sod[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1226141cc406Sopenharmony_ci
1227141cc406Sopenharmony_ci  sod[OPT_TL_X].constraint.range =
1228141cc406Sopenharmony_ci    sod[OPT_BR_X].constraint.range = &(ms->dev->info.doc_x_range);
1229141cc406Sopenharmony_ci  sod[OPT_TL_Y].constraint.range =
1230141cc406Sopenharmony_ci    sod[OPT_BR_Y].constraint.range = &(ms->dev->info.doc_y_range);
1231141cc406Sopenharmony_ci
1232141cc406Sopenharmony_ci  /* set default scan region to be maximum size */
1233141cc406Sopenharmony_ci  val[OPT_TL_X].w     = sod[OPT_TL_X].constraint.range->min;
1234141cc406Sopenharmony_ci  val[OPT_TL_Y].w     = sod[OPT_TL_Y].constraint.range->min;
1235141cc406Sopenharmony_ci  val[OPT_BR_X].w     = sod[OPT_BR_X].constraint.range->max;
1236141cc406Sopenharmony_ci  val[OPT_BR_Y].w     = sod[OPT_BR_Y].constraint.range->max;
1237141cc406Sopenharmony_ci
1238141cc406Sopenharmony_ci  sod[OPT_ENHANCEMENT_GROUP].name  = "";
1239141cc406Sopenharmony_ci  sod[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
1240141cc406Sopenharmony_ci  sod[OPT_ENHANCEMENT_GROUP].desc  = "";
1241141cc406Sopenharmony_ci  sod[OPT_ENHANCEMENT_GROUP].type  = SANE_TYPE_GROUP;
1242141cc406Sopenharmony_ci  sod[OPT_ENHANCEMENT_GROUP].cap   = 0;
1243141cc406Sopenharmony_ci  sod[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1244141cc406Sopenharmony_ci
1245141cc406Sopenharmony_ci  sod[OPT_EXPOSURE].name  = "exposure";
1246141cc406Sopenharmony_ci  sod[OPT_EXPOSURE].title = "Exposure";
1247141cc406Sopenharmony_ci  sod[OPT_EXPOSURE].desc  = "Analog exposure control";
1248141cc406Sopenharmony_ci  sod[OPT_EXPOSURE].type  = SANE_TYPE_INT;
1249141cc406Sopenharmony_ci  sod[OPT_EXPOSURE].unit  = SANE_UNIT_PERCENT;
1250141cc406Sopenharmony_ci  sod[OPT_EXPOSURE].size  = sizeof(SANE_Word);
1251141cc406Sopenharmony_ci  sod[OPT_EXPOSURE].constraint_type = SANE_CONSTRAINT_RANGE;
1252141cc406Sopenharmony_ci  ms->exposure_range.min = ms->dev->info.min_exposure;
1253141cc406Sopenharmony_ci  ms->exposure_range.max = ms->dev->info.max_exposure;
1254141cc406Sopenharmony_ci  ms->exposure_range.quant = 3;
1255141cc406Sopenharmony_ci  sod[OPT_EXPOSURE].constraint.range      = &(ms->exposure_range);
1256141cc406Sopenharmony_ci  val[OPT_EXPOSURE].w     = 0;
1257141cc406Sopenharmony_ci
1258141cc406Sopenharmony_ci  sod[OPT_BRIGHTNESS].name  = SANE_NAME_BRIGHTNESS;
1259141cc406Sopenharmony_ci  sod[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
1260141cc406Sopenharmony_ci  sod[OPT_BRIGHTNESS].desc  = SANE_DESC_BRIGHTNESS;
1261141cc406Sopenharmony_ci  sod[OPT_BRIGHTNESS].type  = SANE_TYPE_INT;
1262141cc406Sopenharmony_ci  sod[OPT_BRIGHTNESS].unit  = SANE_UNIT_PERCENT;
1263141cc406Sopenharmony_ci  sod[OPT_BRIGHTNESS].size  = sizeof(SANE_Word);
1264141cc406Sopenharmony_ci  sod[OPT_BRIGHTNESS].cap   |=
1265141cc406Sopenharmony_ci    ((ms->dev->info.extra_cap & MI_EXCAP_OFF_CTL) ? 0: SANE_CAP_INACTIVE);
1266141cc406Sopenharmony_ci  sod[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
1267141cc406Sopenharmony_ci  sod[OPT_BRIGHTNESS].constraint.range      = &brightness_range;
1268141cc406Sopenharmony_ci  val[OPT_BRIGHTNESS].w     = 0;
1269141cc406Sopenharmony_ci
1270141cc406Sopenharmony_ci  sod[OPT_CONTRAST].name  = SANE_NAME_CONTRAST;
1271141cc406Sopenharmony_ci  sod[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
1272141cc406Sopenharmony_ci  sod[OPT_CONTRAST].desc  = SANE_DESC_CONTRAST;
1273141cc406Sopenharmony_ci  sod[OPT_CONTRAST].type  = SANE_TYPE_INT;
1274141cc406Sopenharmony_ci  sod[OPT_CONTRAST].unit  = SANE_UNIT_PERCENT;
1275141cc406Sopenharmony_ci  sod[OPT_CONTRAST].size  = sizeof(SANE_Word);
1276141cc406Sopenharmony_ci  sod[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
1277141cc406Sopenharmony_ci  ms->contrast_range.min = ms->dev->info.min_contrast;
1278141cc406Sopenharmony_ci  ms->contrast_range.max = ms->dev->info.max_contrast;
1279141cc406Sopenharmony_ci  ms->contrast_range.quant = 7;
1280141cc406Sopenharmony_ci  sod[OPT_CONTRAST].constraint.range      = &(ms->contrast_range);
1281141cc406Sopenharmony_ci  val[OPT_CONTRAST].w     = 0;
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci
1284141cc406Sopenharmony_ci  sod[OPT_HIGHLIGHT].name  = SANE_NAME_WHITE_LEVEL;
1285141cc406Sopenharmony_ci  sod[OPT_HIGHLIGHT].title = SANE_TITLE_WHITE_LEVEL;
1286141cc406Sopenharmony_ci  sod[OPT_HIGHLIGHT].desc  = SANE_DESC_WHITE_LEVEL;
1287141cc406Sopenharmony_ci  sod[OPT_HIGHLIGHT].type  = SANE_TYPE_INT;
1288141cc406Sopenharmony_ci  sod[OPT_HIGHLIGHT].unit  = SANE_UNIT_NONE;
1289141cc406Sopenharmony_ci  sod[OPT_HIGHLIGHT].size  = sizeof(SANE_Word);
1290141cc406Sopenharmony_ci  sod[OPT_HIGHLIGHT].constraint_type = SANE_CONSTRAINT_RANGE;
1291141cc406Sopenharmony_ci  sod[OPT_HIGHLIGHT].constraint.range      = &u8_range;
1292141cc406Sopenharmony_ci  val[OPT_HIGHLIGHT].w     = 255;
1293141cc406Sopenharmony_ci
1294141cc406Sopenharmony_ci  sod[OPT_SHADOW].name  = SANE_NAME_BLACK_LEVEL;
1295141cc406Sopenharmony_ci  sod[OPT_SHADOW].title = SANE_TITLE_BLACK_LEVEL;
1296141cc406Sopenharmony_ci  sod[OPT_SHADOW].desc  = SANE_DESC_BLACK_LEVEL;
1297141cc406Sopenharmony_ci  sod[OPT_SHADOW].type  = SANE_TYPE_INT;
1298141cc406Sopenharmony_ci  sod[OPT_SHADOW].unit  = SANE_UNIT_NONE;
1299141cc406Sopenharmony_ci  sod[OPT_SHADOW].size  = sizeof(SANE_Word);
1300141cc406Sopenharmony_ci  sod[OPT_SHADOW].constraint_type = SANE_CONSTRAINT_RANGE;
1301141cc406Sopenharmony_ci  sod[OPT_SHADOW].constraint.range      = &u8_range;
1302141cc406Sopenharmony_ci  val[OPT_SHADOW].w     = 0;
1303141cc406Sopenharmony_ci
1304141cc406Sopenharmony_ci  if (ms->dev->info.enhance_cap & MI_ENH_CAP_SHADOW) {
1305141cc406Sopenharmony_ci    sod[OPT_HIGHLIGHT].cap |= SANE_CAP_ADVANCED;
1306141cc406Sopenharmony_ci    sod[OPT_SHADOW].cap    |= SANE_CAP_ADVANCED;
1307141cc406Sopenharmony_ci  } else {
1308141cc406Sopenharmony_ci    sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
1309141cc406Sopenharmony_ci    sod[OPT_SHADOW].cap    |= SANE_CAP_INACTIVE;
1310141cc406Sopenharmony_ci  }
1311141cc406Sopenharmony_ci
1312141cc406Sopenharmony_ci  sod[OPT_MIDTONE].name  = "midtone";
1313141cc406Sopenharmony_ci  sod[OPT_MIDTONE].title = "Midtone Level";
1314141cc406Sopenharmony_ci  sod[OPT_MIDTONE].desc  = "Midtone Level";
1315141cc406Sopenharmony_ci  sod[OPT_MIDTONE].type  = SANE_TYPE_INT;
1316141cc406Sopenharmony_ci  sod[OPT_MIDTONE].unit  = SANE_UNIT_NONE;
1317141cc406Sopenharmony_ci  sod[OPT_MIDTONE].size  = sizeof(SANE_Word);
1318141cc406Sopenharmony_ci  sod[OPT_MIDTONE].constraint_type = SANE_CONSTRAINT_RANGE;
1319141cc406Sopenharmony_ci  sod[OPT_MIDTONE].constraint.range      = &u8_range;
1320141cc406Sopenharmony_ci  val[OPT_MIDTONE].w     = 128;
1321141cc406Sopenharmony_ci  if (ms->midtone_support) {
1322141cc406Sopenharmony_ci    sod[OPT_MIDTONE].cap   |= SANE_CAP_ADVANCED;
1323141cc406Sopenharmony_ci  } else {
1324141cc406Sopenharmony_ci    sod[OPT_MIDTONE].cap   |= SANE_CAP_INACTIVE;
1325141cc406Sopenharmony_ci  }
1326141cc406Sopenharmony_ci  /* XXXXXXXX is this supported by all scanners??
1327141cc406Sopenharmony_ci  if ((strcmp(M_COLOR, val[OPT_MODE].s)) &&
1328141cc406Sopenharmony_ci      (strcmp(M_GRAY, val[OPT_MODE].s))) {
1329141cc406Sopenharmony_ci    sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
1330141cc406Sopenharmony_ci    sod[OPT_SHADOW].cap    |= SANE_CAP_INACTIVE;
1331141cc406Sopenharmony_ci    sod[OPT_MIDTONE].cap   |= SANE_CAP_INACTIVE;
1332141cc406Sopenharmony_ci  }
1333141cc406Sopenharmony_ci  */
1334141cc406Sopenharmony_ci
1335141cc406Sopenharmony_ci  sod[OPT_GAMMA_GROUP].name  = "";
1336141cc406Sopenharmony_ci  sod[OPT_GAMMA_GROUP].title = "Gamma Control";
1337141cc406Sopenharmony_ci  sod[OPT_GAMMA_GROUP].desc  = "";
1338141cc406Sopenharmony_ci  sod[OPT_GAMMA_GROUP].type  = SANE_TYPE_GROUP;
1339141cc406Sopenharmony_ci  if (!(ms->gamma_entries))
1340141cc406Sopenharmony_ci    sod[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1341141cc406Sopenharmony_ci  sod[OPT_GAMMA_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1342141cc406Sopenharmony_ci
1343141cc406Sopenharmony_ci  sod[OPT_CUSTOM_GAMMA].name  = "gamma-mode";
1344141cc406Sopenharmony_ci  sod[OPT_CUSTOM_GAMMA].title = "Gamma Control Mode";
1345141cc406Sopenharmony_ci  sod[OPT_CUSTOM_GAMMA].desc  = "How to specify gamma correction, if at all";
1346141cc406Sopenharmony_ci  sod[OPT_CUSTOM_GAMMA].type  = SANE_TYPE_STRING;
1347141cc406Sopenharmony_ci  sod[OPT_CUSTOM_GAMMA].size  = max_string_size(gamma_mode_list);
1348141cc406Sopenharmony_ci  sod[OPT_CUSTOM_GAMMA].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1349141cc406Sopenharmony_ci  sod[OPT_CUSTOM_GAMMA].constraint.string_list = gamma_mode_list;
1350141cc406Sopenharmony_ci  if (!(ms->gamma_entries))
1351141cc406Sopenharmony_ci    sod[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1352141cc406Sopenharmony_ci  val[OPT_CUSTOM_GAMMA].s = strdup(gamma_mode_list[0]);
1353141cc406Sopenharmony_ci
1354141cc406Sopenharmony_ci  sod[OPT_GAMMA_BIND].name  = SANE_NAME_ANALOG_GAMMA_BIND;
1355141cc406Sopenharmony_ci  sod[OPT_GAMMA_BIND].title = SANE_TITLE_ANALOG_GAMMA_BIND;
1356141cc406Sopenharmony_ci  sod[OPT_GAMMA_BIND].desc  = SANE_DESC_ANALOG_GAMMA_BIND;
1357141cc406Sopenharmony_ci  sod[OPT_GAMMA_BIND].type  = SANE_TYPE_BOOL;
1358141cc406Sopenharmony_ci  sod[OPT_GAMMA_BIND].cap   |= SANE_CAP_INACTIVE;
1359141cc406Sopenharmony_ci  val[OPT_GAMMA_BIND].w     = SANE_TRUE;
1360141cc406Sopenharmony_ci
1361141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA].name  = SANE_NAME_ANALOG_GAMMA;
1362141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA].title = SANE_TITLE_ANALOG_GAMMA;
1363141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA].desc  = SANE_DESC_ANALOG_GAMMA;
1364141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA].type  = SANE_TYPE_FIXED;
1365141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA].unit  = SANE_UNIT_NONE;
1366141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA].size  = sizeof(SANE_Word);
1367141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA].cap   |= SANE_CAP_INACTIVE;
1368141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA].constraint_type = SANE_CONSTRAINT_RANGE;
1369141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA].constraint.range      = &analog_gamma_range;
1370141cc406Sopenharmony_ci  val[OPT_ANALOG_GAMMA].w     = SANE_FIX(1.0);
1371141cc406Sopenharmony_ci
1372141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_R].name  = SANE_NAME_ANALOG_GAMMA_R;
1373141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_R].title = SANE_TITLE_ANALOG_GAMMA_R;
1374141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_R].desc  = SANE_DESC_ANALOG_GAMMA_R;
1375141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_R].type  = SANE_TYPE_FIXED;
1376141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_R].unit  = SANE_UNIT_NONE;
1377141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_R].size  = sizeof(SANE_Word);
1378141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_R].cap   |= SANE_CAP_INACTIVE;
1379141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_R].constraint_type = SANE_CONSTRAINT_RANGE;
1380141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_R].constraint.range      = &analog_gamma_range;
1381141cc406Sopenharmony_ci  val[OPT_ANALOG_GAMMA_R].w     = SANE_FIX(1.0);
1382141cc406Sopenharmony_ci
1383141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_G].name  = SANE_NAME_ANALOG_GAMMA_G;
1384141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_G].title = SANE_TITLE_ANALOG_GAMMA_G;
1385141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_G].desc  = SANE_DESC_ANALOG_GAMMA_G;
1386141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_G].type  = SANE_TYPE_FIXED;
1387141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_G].unit  = SANE_UNIT_NONE;
1388141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_G].size  = sizeof(SANE_Word);
1389141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_G].cap   |= SANE_CAP_INACTIVE;
1390141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_G].constraint_type = SANE_CONSTRAINT_RANGE;
1391141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_G].constraint.range      = &analog_gamma_range;
1392141cc406Sopenharmony_ci  val[OPT_ANALOG_GAMMA_G].w     = SANE_FIX(1.0);
1393141cc406Sopenharmony_ci
1394141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_B].name  = SANE_NAME_ANALOG_GAMMA_B;
1395141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_B].title = SANE_TITLE_ANALOG_GAMMA_B;
1396141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_B].desc  = SANE_DESC_ANALOG_GAMMA_B;
1397141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_B].type  = SANE_TYPE_FIXED;
1398141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_B].unit  = SANE_UNIT_NONE;
1399141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_B].size  = sizeof(SANE_Word);
1400141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_B].cap   |= SANE_CAP_INACTIVE;
1401141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_B].constraint_type = SANE_CONSTRAINT_RANGE;
1402141cc406Sopenharmony_ci  sod[OPT_ANALOG_GAMMA_B].constraint.range      = &analog_gamma_range;
1403141cc406Sopenharmony_ci  val[OPT_ANALOG_GAMMA_B].w     = SANE_FIX(1.0);
1404141cc406Sopenharmony_ci
1405141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR].name  = SANE_NAME_GAMMA_VECTOR;
1406141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
1407141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR].desc  = SANE_DESC_GAMMA_VECTOR;
1408141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR].type  = SANE_TYPE_INT;
1409141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR].unit  = SANE_UNIT_NONE;
1410141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR].size  = ms->gamma_entries * sizeof(SANE_Word);
1411141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR].cap   |= SANE_CAP_INACTIVE;
1412141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
1413141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR].constraint.range      = &(ms->gamma_entry_range);
1414141cc406Sopenharmony_ci  val[OPT_GAMMA_VECTOR].wa     = ms->gray_lut;
1415141cc406Sopenharmony_ci
1416141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_R].name  = SANE_NAME_GAMMA_VECTOR_R;
1417141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
1418141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_R].desc  = SANE_DESC_GAMMA_VECTOR_R;
1419141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_R].type  = SANE_TYPE_INT;
1420141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_R].unit  = SANE_UNIT_NONE;
1421141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_R].size  = ms->gamma_entries * sizeof(SANE_Word);
1422141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_R].cap   |= SANE_CAP_INACTIVE;
1423141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
1424141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_R].constraint.range      = &(ms->gamma_entry_range);
1425141cc406Sopenharmony_ci  val[OPT_GAMMA_VECTOR_R].wa     = ms->red_lut;
1426141cc406Sopenharmony_ci
1427141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_G].name  = SANE_NAME_GAMMA_VECTOR_G;
1428141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
1429141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_G].desc  = SANE_DESC_GAMMA_VECTOR_G;
1430141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_G].type  = SANE_TYPE_INT;
1431141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_G].unit  = SANE_UNIT_NONE;
1432141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_G].size  = ms->gamma_entries * sizeof(SANE_Word);
1433141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_G].cap   |= SANE_CAP_INACTIVE;
1434141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
1435141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_G].constraint.range      = &(ms->gamma_entry_range);
1436141cc406Sopenharmony_ci  val[OPT_GAMMA_VECTOR_G].wa     = ms->green_lut;
1437141cc406Sopenharmony_ci
1438141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_B].name  = SANE_NAME_GAMMA_VECTOR_B;
1439141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
1440141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_B].desc  = SANE_DESC_GAMMA_VECTOR_B;
1441141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_B].type  = SANE_TYPE_INT;
1442141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_B].unit  = SANE_UNIT_NONE;
1443141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_B].size  = ms->gamma_entries * sizeof(SANE_Word);
1444141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_B].cap   |= SANE_CAP_INACTIVE;
1445141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
1446141cc406Sopenharmony_ci  sod[OPT_GAMMA_VECTOR_B].constraint.range      = &(ms->gamma_entry_range);
1447141cc406Sopenharmony_ci  val[OPT_GAMMA_VECTOR_B].wa     = ms->blue_lut;
1448141cc406Sopenharmony_ci
1449141cc406Sopenharmony_ci  sod[OPT_EXP_RES].name  = "exp_res";
1450141cc406Sopenharmony_ci  sod[OPT_EXP_RES].title = "Expanded Resolution";
1451141cc406Sopenharmony_ci  sod[OPT_EXP_RES].desc  = "Enable double-resolution scans";
1452141cc406Sopenharmony_ci  sod[OPT_EXP_RES].type  = SANE_TYPE_BOOL;
1453141cc406Sopenharmony_ci  sod[OPT_EXP_RES].cap   |= SANE_CAP_ADVANCED;
1454141cc406Sopenharmony_ci  if (!(ms->dev->info.expanded_resolution))
1455141cc406Sopenharmony_ci    sod[OPT_EXP_RES].cap |= SANE_CAP_INACTIVE;
1456141cc406Sopenharmony_ci  val[OPT_EXP_RES].w     = SANE_FALSE;
1457141cc406Sopenharmony_ci
1458141cc406Sopenharmony_ci  sod[OPT_CALIB_ONCE].name  = "calib_once";
1459141cc406Sopenharmony_ci  sod[OPT_CALIB_ONCE].title = "Calibrate Only Once";
1460141cc406Sopenharmony_ci  sod[OPT_CALIB_ONCE].desc  = "Avoid CCD calibration on every scan" \
1461141cc406Sopenharmony_ci    "(toggle off/on to cause calibration on next scan)";
1462141cc406Sopenharmony_ci  sod[OPT_CALIB_ONCE].type  = SANE_TYPE_BOOL;
1463141cc406Sopenharmony_ci  sod[OPT_CALIB_ONCE].cap   |= SANE_CAP_ADVANCED;
1464141cc406Sopenharmony_ci  if (!(ms->do_real_calib)) {
1465141cc406Sopenharmony_ci    sod[OPT_CALIB_ONCE].cap |= SANE_CAP_INACTIVE;
1466141cc406Sopenharmony_ci    val[OPT_CALIB_ONCE].w     = SANE_FALSE;
1467141cc406Sopenharmony_ci  } else
1468141cc406Sopenharmony_ci    val[OPT_CALIB_ONCE].w     = SANE_TRUE;
1469141cc406Sopenharmony_ci
1470141cc406Sopenharmony_ci  /*
1471141cc406Sopenharmony_ci  sod[OPT_].name  = SANE_NAME_;
1472141cc406Sopenharmony_ci  sod[OPT_].title = SANE_TITLE_;
1473141cc406Sopenharmony_ci  sod[OPT_].desc  = SANE_DESC_;
1474141cc406Sopenharmony_ci  sod[OPT_].type  = SANE_TYPE_;
1475141cc406Sopenharmony_ci  sod[OPT_].unit  = SANE_UNIT_NONE;
1476141cc406Sopenharmony_ci  sod[OPT_].size  = sizeof(SANE_Word);
1477141cc406Sopenharmony_ci  sod[OPT_].cap   = 0;
1478141cc406Sopenharmony_ci  sod[OPT_].constraint_type = SANE_CONSTRAINT_NONE;
1479141cc406Sopenharmony_ci  sod[OPT_].constraint      = ;
1480141cc406Sopenharmony_ci  val[OPT_].w     = ;
1481141cc406Sopenharmony_ci  */
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_ci  DBG(15, "init_options:  done.\n");
1484141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1485141cc406Sopenharmony_ci}
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci
1488141cc406Sopenharmony_ci/********************************************************************/
1489141cc406Sopenharmony_ci/* Parse an INQUIRY information block, as returned by scanner       */
1490141cc406Sopenharmony_ci/********************************************************************/
1491141cc406Sopenharmony_cistatic SANE_Status
1492141cc406Sopenharmony_ciparse_inquiry(Microtek_Info *mi, unsigned char *result)
1493141cc406Sopenharmony_ci{
1494141cc406Sopenharmony_ci#if 0
1495141cc406Sopenharmony_ci  unsigned char result[0x60] = {
1496141cc406Sopenharmony_ci    0x06,0x31,0x23,0x01,0x5b,0x00,0x00,0x00,0x41,0x47,0x46,0x41,0x20,0x20,0x20,0x20,
1497141cc406Sopenharmony_ci    0x53,0x74,0x75,0x64,0x69,0x6f,0x53,0x63,0x61,0x6e,0x20,0x49,0x49,0x20,0x20,0x20,
1498141cc406Sopenharmony_ci    0x32,0x2e,0x33,0x30,0x53,0x43,0x53,0x49,0x20,0x46,0x2f,0x57,0x56,0x33,0x2e,0x31,
1499141cc406Sopenharmony_ci    0x20,0x43,0x54,0x4c,0x35,0x33,0x38,0x30,0x03,0x4f,0x8c,0xc5,0x00,0xee,0x5b,0x43,
1500141cc406Sopenharmony_ci    0x01,0x01,0x02,0x00,0x00,0x03,0x00,0x01,0x00,0x4a,0x01,0x04,0x00,0x00,0x00,0x00,
1501141cc406Sopenharmony_ci    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff
1502141cc406Sopenharmony_ci  };
1503141cc406Sopenharmony_ci#endif
1504141cc406Sopenharmony_ci  DBG(15, "parse_inquiry...\n");
1505141cc406Sopenharmony_ci  snprintf(mi->vendor_id,      8 + 1, "%.*s",  8, (char *)&result[8]);
1506141cc406Sopenharmony_ci  snprintf(mi->model_name,    16 + 1, "%.*s", 16, (char *)&result[16]);
1507141cc406Sopenharmony_ci  snprintf(mi->revision_num,   4 + 1, "%.*s",  4, (char *)&result[32]);
1508141cc406Sopenharmony_ci  snprintf(mi->vendor_string, 20 + 1, "%.*s", 20, (char *)&result[36]);
1509141cc406Sopenharmony_ci
1510141cc406Sopenharmony_ci  mi->device_type                = (SANE_Byte)(result[0] & 0x1f);
1511141cc406Sopenharmony_ci  mi->SCSI_firmware_ver_major    = (SANE_Byte)((result[1] & 0xf0) >> 4);
1512141cc406Sopenharmony_ci  mi->SCSI_firmware_ver_minor    = (SANE_Byte)(result[1] & 0x0f);
1513141cc406Sopenharmony_ci  mi->scanner_firmware_ver_major = (SANE_Byte)((result[2] & 0xf0) >> 4);
1514141cc406Sopenharmony_ci  mi->scanner_firmware_ver_minor = (SANE_Byte)(result[2] & 0x0f);
1515141cc406Sopenharmony_ci  mi->response_data_format       = (SANE_Byte)(result[3]);
1516141cc406Sopenharmony_ci
1517141cc406Sopenharmony_ci  mi->res_step                   = (SANE_Byte)(result[56] & 0x03);
1518141cc406Sopenharmony_ci  mi->modes                      = (SANE_Byte)(result[57]);
1519141cc406Sopenharmony_ci  mi->pattern_count              = (SANE_Int)(result[58] & 0x7f);
1520141cc406Sopenharmony_ci  mi->pattern_dwnld              = (SANE_Byte)(result[58] & 0x80) > 0;
1521141cc406Sopenharmony_ci  mi->feed_type                  = (SANE_Byte)(result[59] & 0x0F);
1522141cc406Sopenharmony_ci  mi->compress_type              = (SANE_Byte)(result[59] & 0x30);
1523141cc406Sopenharmony_ci  mi->unit_type                  = (SANE_Byte)(result[59] & 0xC0);
1524141cc406Sopenharmony_ci
1525141cc406Sopenharmony_ci  mi->doc_size_code              = (SANE_Byte)result[60];
1526141cc406Sopenharmony_ci  /* we'll compute the max sizes after we know base resolution... */
1527141cc406Sopenharmony_ci
1528141cc406Sopenharmony_ci  /* why are these things set in two places (and probably wrong anyway)? */
1529141cc406Sopenharmony_ci  mi->cont_settings              = (SANE_Int)((result[61] & 0xf0) >> 4);
1530141cc406Sopenharmony_ci  if ((SANE_Int)(result[72]))
1531141cc406Sopenharmony_ci    mi->cont_settings            = (SANE_Int)(result[72]);
1532141cc406Sopenharmony_ci  mi->min_contrast = -42;
1533141cc406Sopenharmony_ci  mi->max_contrast = (mi->cont_settings * 7) - 49;
1534141cc406Sopenharmony_ci
1535141cc406Sopenharmony_ci  mi->exp_settings               = (SANE_Int)(result[61] & 0x0f);
1536141cc406Sopenharmony_ci  if ((SANE_Int)(result[73]))
1537141cc406Sopenharmony_ci    mi->exp_settings             = (SANE_Int)(result[73]);
1538141cc406Sopenharmony_ci  mi->min_exposure  = -18;
1539141cc406Sopenharmony_ci  mi->max_exposure  = (mi->exp_settings * 3) - 21;
1540141cc406Sopenharmony_ci#if 0
1541141cc406Sopenharmony_ci  mi->contrast_vals              = (SANE_Int)(result[72]);
1542141cc406Sopenharmony_ci  mi->min_contrast = -42;
1543141cc406Sopenharmony_ci  mi->max_contrast =  49;
1544141cc406Sopenharmony_ci  if (mi->contrast_vals)
1545141cc406Sopenharmony_ci    mi->max_contrast = (mi->contrast_vals * 7) - 49;
1546141cc406Sopenharmony_ci
1547141cc406Sopenharmony_ci  mi->exposure_vals              = (SANE_Int)(result[73]);
1548141cc406Sopenharmony_ci  mi->min_exposure  = -18;
1549141cc406Sopenharmony_ci  mi->max_exposure  =  21;
1550141cc406Sopenharmony_ci  if (mi->exposure_vals)
1551141cc406Sopenharmony_ci    mi->max_exposure  = (mi->exposure_vals * 3) - 21;
1552141cc406Sopenharmony_ci#endif
1553141cc406Sopenharmony_ci
1554141cc406Sopenharmony_ci  mi->model_code                 = (SANE_Byte)(result[62]);
1555141cc406Sopenharmony_ci  switch (mi->model_code) {
1556141cc406Sopenharmony_ci  case 0x16: /* the other ScanMaker 600ZS */
1557141cc406Sopenharmony_ci  case 0x50: /* ScanMaker II/IIXE */
1558141cc406Sopenharmony_ci  case 0x54: /* ScanMaker IISP    */
1559141cc406Sopenharmony_ci  case 0x55: /* ScanMaker IIER    */
1560141cc406Sopenharmony_ci  case 0x58: /* ScanMaker IIG     */
1561141cc406Sopenharmony_ci  case 0x5a: /* Agfa StudioScan (untested!)    */
1562141cc406Sopenharmony_ci  case 0x5f: /* ScanMaker E3      */
1563141cc406Sopenharmony_ci  case 0x56: /* ScanMaker A3t     */
1564141cc406Sopenharmony_ci  case 0x64: /* ScanMaker E2 (,Vobis RealScan) */
1565141cc406Sopenharmony_ci  case 0x65: /* Color PageWiz */
1566141cc406Sopenharmony_ci  case 0xC8: /* ScanMaker 600ZS */
1567141cc406Sopenharmony_ci    mi->base_resolution = 300;
1568141cc406Sopenharmony_ci    break;
1569141cc406Sopenharmony_ci  case 0x5b: /* Agfa StudioScan II/IIsi (untested!) */
1570141cc406Sopenharmony_ci    mi->base_resolution = 400;
1571141cc406Sopenharmony_ci    break;
1572141cc406Sopenharmony_ci  case 0x57: /* ScanMaker IIHR    */
1573141cc406Sopenharmony_ci  case 0x59: /* ScanMaker III     */
1574141cc406Sopenharmony_ci  case 0x5c: /* Agfa Arcus II     */
1575141cc406Sopenharmony_ci  case 0x5e: /* Agfa StudioStar   */
1576141cc406Sopenharmony_ci  case 0x63: /* ScanMaker E6      */
1577141cc406Sopenharmony_ci  case 0x66: /* ScanMaker E6 (new)*/
1578141cc406Sopenharmony_ci    mi->base_resolution = 600;
1579141cc406Sopenharmony_ci    break;
1580141cc406Sopenharmony_ci  case 0x51: /* ScanMaker 45t     */
1581141cc406Sopenharmony_ci  case 0x5d: /* Agfa DuoScan      */
1582141cc406Sopenharmony_ci    mi->base_resolution = 1000;
1583141cc406Sopenharmony_ci    break;
1584141cc406Sopenharmony_ci  case 0x52: /* ScanMaker 35t     */
1585141cc406Sopenharmony_ci    mi->base_resolution = 1828;
1586141cc406Sopenharmony_ci    break;
1587141cc406Sopenharmony_ci  case 0x62: /* ScanMaker 35t+, Polaroid 35/LE    */
1588141cc406Sopenharmony_ci    mi->base_resolution = 1950;
1589141cc406Sopenharmony_ci    break;
1590141cc406Sopenharmony_ci  default:
1591141cc406Sopenharmony_ci    mi->base_resolution = 300;
1592141cc406Sopenharmony_ci    DBG(15, "parse_inquiry:  Unknown base resolution for 0x%x!\n",
1593141cc406Sopenharmony_ci	mi->model_code);
1594141cc406Sopenharmony_ci    break;
1595141cc406Sopenharmony_ci  }
1596141cc406Sopenharmony_ci
1597141cc406Sopenharmony_ci  /* Our max_x,y is in pixels. `Some scanners think in 1/8", though.' */
1598141cc406Sopenharmony_ci  /* max pixel is, of course, total - 1                               */
1599141cc406Sopenharmony_ci  switch (mi->doc_size_code) {
1600141cc406Sopenharmony_ci  case 0x00:
1601141cc406Sopenharmony_ci    mi->max_x = 8.5 * mi->base_resolution - 1;
1602141cc406Sopenharmony_ci    mi->max_y = 14.0 * mi->base_resolution - 1;
1603141cc406Sopenharmony_ci    break;
1604141cc406Sopenharmony_ci  case 0x01:
1605141cc406Sopenharmony_ci    mi->max_x = 8.5 * mi->base_resolution - 1;
1606141cc406Sopenharmony_ci    mi->max_y = 11.0 * mi->base_resolution - 1;
1607141cc406Sopenharmony_ci    break;
1608141cc406Sopenharmony_ci  case 0x02:
1609141cc406Sopenharmony_ci    mi->max_x = 8.5 * mi->base_resolution - 1;
1610141cc406Sopenharmony_ci    mi->max_y = 11.69 * mi->base_resolution - 1;
1611141cc406Sopenharmony_ci    break;
1612141cc406Sopenharmony_ci  case 0x03:
1613141cc406Sopenharmony_ci    mi->max_x = 8.5 * mi->base_resolution - 1;
1614141cc406Sopenharmony_ci    mi->max_y = 13.0 * mi->base_resolution - 1;
1615141cc406Sopenharmony_ci    break;
1616141cc406Sopenharmony_ci  case 0x04:
1617141cc406Sopenharmony_ci    mi->max_x = 8.0 * mi->base_resolution - 1;
1618141cc406Sopenharmony_ci    mi->max_y = 10.0 * mi->base_resolution - 1;
1619141cc406Sopenharmony_ci    break;
1620141cc406Sopenharmony_ci  case 0x05:
1621141cc406Sopenharmony_ci    mi->max_x = 8.3 * mi->base_resolution - 1;
1622141cc406Sopenharmony_ci    mi->max_y = 14.0 * mi->base_resolution - 1;
1623141cc406Sopenharmony_ci    break;
1624141cc406Sopenharmony_ci  case 0x06:
1625141cc406Sopenharmony_ci    mi->max_x = 8.3 * mi->base_resolution - 1;
1626141cc406Sopenharmony_ci    mi->max_y = 13.5 * mi->base_resolution - 1;
1627141cc406Sopenharmony_ci    break;
1628141cc406Sopenharmony_ci  case 0x07:
1629141cc406Sopenharmony_ci    mi->max_x = 8.0 * mi->base_resolution - 1;
1630141cc406Sopenharmony_ci    mi->max_y = 14.0 * mi->base_resolution - 1;
1631141cc406Sopenharmony_ci    break;
1632141cc406Sopenharmony_ci  case 0x80:
1633141cc406Sopenharmony_ci    /* Slide format, size is mm */
1634141cc406Sopenharmony_ci    mi->max_x = (35.0 / MM_PER_INCH) * mi->base_resolution - 1;
1635141cc406Sopenharmony_ci    mi->max_y = (35.0 / MM_PER_INCH) * mi->base_resolution - 1;
1636141cc406Sopenharmony_ci    break;
1637141cc406Sopenharmony_ci  case 0x81:
1638141cc406Sopenharmony_ci    mi->max_x = 5.0 * mi->base_resolution - 1;
1639141cc406Sopenharmony_ci    mi->max_y = 5.0 * mi->base_resolution - 1;
1640141cc406Sopenharmony_ci    break;
1641141cc406Sopenharmony_ci  case 0x82:
1642141cc406Sopenharmony_ci    /* Slide format, size is mm */
1643141cc406Sopenharmony_ci    mi->max_x = (36.0 / MM_PER_INCH) * mi->base_resolution - 1;
1644141cc406Sopenharmony_ci    mi->max_y = (36.0 / MM_PER_INCH) * mi->base_resolution - 1;
1645141cc406Sopenharmony_ci    break;
1646141cc406Sopenharmony_ci  default:
1647141cc406Sopenharmony_ci    /* Undefined document format code */
1648141cc406Sopenharmony_ci      mi->max_x = mi->max_y = 0;
1649141cc406Sopenharmony_ci      DBG(15, "parse_inquiry:  Unknown doc_size_code!  0x%x\n",
1650141cc406Sopenharmony_ci	  mi->doc_size_code);
1651141cc406Sopenharmony_ci  }
1652141cc406Sopenharmony_ci
1653141cc406Sopenharmony_ci  /* create the proper range constraints, given the doc size */
1654141cc406Sopenharmony_ci  {
1655141cc406Sopenharmony_ci    /* we need base resolution in dots-per-millimeter... */
1656141cc406Sopenharmony_ci    float base_res_dpmm = (float) mi->base_resolution / MM_PER_INCH;
1657141cc406Sopenharmony_ci    mi->doc_x_range.min = SANE_FIX(0);
1658141cc406Sopenharmony_ci    mi->doc_x_range.max = SANE_FIX((float)mi->max_x / base_res_dpmm);
1659141cc406Sopenharmony_ci    mi->doc_x_range.quant = SANE_FIX(0);
1660141cc406Sopenharmony_ci    mi->doc_y_range.min = SANE_FIX(0);
1661141cc406Sopenharmony_ci    mi->doc_y_range.max = SANE_FIX((float)mi->max_y / base_res_dpmm);
1662141cc406Sopenharmony_ci    mi->doc_y_range.quant = SANE_FIX(0);
1663141cc406Sopenharmony_ci  }
1664141cc406Sopenharmony_ci
1665141cc406Sopenharmony_ci  mi->source_options             = (SANE_Byte)(result[63]);
1666141cc406Sopenharmony_ci
1667141cc406Sopenharmony_ci  mi->expanded_resolution        = (result[64] & 0x01);
1668141cc406Sopenharmony_ci  /* my E6 reports exp-res capability incorrectly */
1669141cc406Sopenharmony_ci  if ((mi->model_code == 0x66) || (mi->model_code == 0x63)) {
1670141cc406Sopenharmony_ci    mi->expanded_resolution = 0xFF;
1671141cc406Sopenharmony_ci    DBG(4, "parse_inquiry:  E6 falsely denies expanded resolution.\n");
1672141cc406Sopenharmony_ci  }
1673141cc406Sopenharmony_ci  /* the StudioScan II(si) does the expanded-mode aspect correction
1674141cc406Sopenharmony_ci     within the scanner... (do others too?) */
1675141cc406Sopenharmony_ci  if (mi->model_code == 0x5b) {
1676141cc406Sopenharmony_ci    DBG(4, "parse_inquiry:  does expanded-mode expansion internally.\n");
1677141cc406Sopenharmony_ci    mi->does_expansion = 1;
1678141cc406Sopenharmony_ci  } else
1679141cc406Sopenharmony_ci    mi->does_expansion = 0;
1680141cc406Sopenharmony_ci
1681141cc406Sopenharmony_ci  mi->enhance_cap                = (result[65] & 0x03);
1682141cc406Sopenharmony_ci
1683141cc406Sopenharmony_ci  /*
1684141cc406Sopenharmony_ci  switch (result[66] & 0x0F) {
1685141cc406Sopenharmony_ci  case 0x00: mi->max_lookup_size =     0; break;
1686141cc406Sopenharmony_ci  case 0x01: mi->max_lookup_size =   256; break;
1687141cc406Sopenharmony_ci  case 0x03: mi->max_lookup_size =  1024; break;
1688141cc406Sopenharmony_ci  case 0x05: mi->max_lookup_size =  4096; break;
1689141cc406Sopenharmony_ci  case 0x09: mi->max_lookup_size = 65536; break;
1690141cc406Sopenharmony_ci  default:
1691141cc406Sopenharmony_ci    mi->max_lookup_size = 0;
1692141cc406Sopenharmony_ci    DBG(15, "parse_inquiry:  Unknown gamma LUT size!  0x%x\n",
1693141cc406Sopenharmony_ci	result[66]);
1694141cc406Sopenharmony_ci  }
1695141cc406Sopenharmony_ci  */
1696141cc406Sopenharmony_ci
1697141cc406Sopenharmony_ci  /* This is not how the vague documentation specifies this register.
1698141cc406Sopenharmony_ci     We're going to take it literally here -- i.e. if the bit is
1699141cc406Sopenharmony_ci     set, the scanner supports the value, otherwise it doesn't.
1700141cc406Sopenharmony_ci     (The docs say all lower values are always supported.  This is
1701141cc406Sopenharmony_ci     not the case for the StudioScan IIsi, at least, which only
1702141cc406Sopenharmony_ci     specifies 0x02==1024-byte table, and only supports that, too.)
1703141cc406Sopenharmony_ci
1704141cc406Sopenharmony_ci     All-in-all, it doesn't matter, since we take the largest
1705141cc406Sopenharmony_ci     allowed LUT size anyway.
1706141cc406Sopenharmony_ci  */
1707141cc406Sopenharmony_ci  if (result[66] & 0x08)
1708141cc406Sopenharmony_ci    mi->max_lookup_size = 65536;
1709141cc406Sopenharmony_ci  else if (result[66] & 0x04)
1710141cc406Sopenharmony_ci    mi->max_lookup_size = 4096;
1711141cc406Sopenharmony_ci  else if (result[66] & 0x02)
1712141cc406Sopenharmony_ci    mi->max_lookup_size = 1024;
1713141cc406Sopenharmony_ci  else if (result[66] & 0x01)
1714141cc406Sopenharmony_ci    mi->max_lookup_size = 256;
1715141cc406Sopenharmony_ci  else
1716141cc406Sopenharmony_ci    mi->max_lookup_size = 0;
1717141cc406Sopenharmony_ci
1718141cc406Sopenharmony_ci  /* my E6 reports incorrectly */
1719141cc406Sopenharmony_ci  if ((mi->model_code == 0x66) || (mi->model_code == 0x63)) {
1720141cc406Sopenharmony_ci    mi->max_lookup_size = 1024;
1721141cc406Sopenharmony_ci    DBG(4, "parse_inquiry:  E6 falsely denies 1024-byte LUT.\n");
1722141cc406Sopenharmony_ci  }
1723141cc406Sopenharmony_ci
1724141cc406Sopenharmony_ci  /*
1725141cc406Sopenharmony_ci  switch (result[66] >> 5) {
1726141cc406Sopenharmony_ci  case 0x00: mi->max_gamma_val =   255;  mi->gamma_size = 1;  break;
1727141cc406Sopenharmony_ci  case 0x01: mi->max_gamma_val =  1023;  mi->gamma_size = 2;  break;
1728141cc406Sopenharmony_ci  case 0x02: mi->max_gamma_val =  4095;  mi->gamma_size = 2;  break;
1729141cc406Sopenharmony_ci  case 0x03: mi->max_gamma_val = 65535;  mi->gamma_size = 2;  break;
1730141cc406Sopenharmony_ci  default:
1731141cc406Sopenharmony_ci    mi->max_gamma_val =     0;  mi->gamma_size = 0;
1732141cc406Sopenharmony_ci    DBG(15, "parse_inquiry:  Unknown gamma max val!  0x%x\n",
1733141cc406Sopenharmony_ci	result[66]);
1734141cc406Sopenharmony_ci  }
1735141cc406Sopenharmony_ci  */
1736141cc406Sopenharmony_ci  switch (result[66] >> 5) {
1737141cc406Sopenharmony_ci  case 0x00: mi->max_gamma_bit_depth =  8;  mi->gamma_size = 1;  break;
1738141cc406Sopenharmony_ci  case 0x01: mi->max_gamma_bit_depth = 10;  mi->gamma_size = 2;  break;
1739141cc406Sopenharmony_ci  case 0x02: mi->max_gamma_bit_depth = 12;  mi->gamma_size = 2;  break;
1740141cc406Sopenharmony_ci  case 0x03: mi->max_gamma_bit_depth = 16;  mi->gamma_size = 2;  break;
1741141cc406Sopenharmony_ci  default:
1742141cc406Sopenharmony_ci    mi->max_gamma_bit_depth =  0;  mi->gamma_size = 0;
1743141cc406Sopenharmony_ci    DBG(15, "parse_inquiry:  Unknown gamma max val!  0x%x\n",
1744141cc406Sopenharmony_ci	result[66]);
1745141cc406Sopenharmony_ci  }
1746141cc406Sopenharmony_ci
1747141cc406Sopenharmony_ci  mi->fast_color_preview         = (SANE_Byte)(result[67] & 0x01);
1748141cc406Sopenharmony_ci  mi->xfer_format_select         = (SANE_Byte)(result[68] & 0x01);
1749141cc406Sopenharmony_ci  mi->color_sequence             = (SANE_Byte)(result[69] & 0x7f);
1750141cc406Sopenharmony_ci  mi->does_3pass                 = (SANE_Byte)(!(result[69] & 0x80));
1751141cc406Sopenharmony_ci  mi->does_mode1                 = (SANE_Byte)(result[71] & 0x01);
1752141cc406Sopenharmony_ci
1753141cc406Sopenharmony_ci  mi->bit_formats                = (SANE_Byte)(result[74] & 0x0F);
1754141cc406Sopenharmony_ci  mi->extra_cap                  = (SANE_Byte)(result[75] & 0x07);
1755141cc406Sopenharmony_ci
1756141cc406Sopenharmony_ci  /* XXXXXX a quick hack to disable any [pre/real]cal stuff for
1757141cc406Sopenharmony_ci     anything but an E6... */
1758141cc406Sopenharmony_ci  if (!((mi->model_code == 0x66) || (mi->model_code == 0x63))) {
1759141cc406Sopenharmony_ci    mi->extra_cap &= ~MI_EXCAP_DIS_RECAL;
1760141cc406Sopenharmony_ci    DBG(4, "parse_inquiry:  Not an E6 -- pretend recal cannot be disabled.\n");
1761141cc406Sopenharmony_ci  }
1762141cc406Sopenharmony_ci
1763141cc406Sopenharmony_ci  /* The E2 lies... */
1764141cc406Sopenharmony_ci  if (mi->model_code == 0x64) {
1765141cc406Sopenharmony_ci    DBG(4, "parse_inquiry:  The E2 lies about it's 3-pass heritage.\n");
1766141cc406Sopenharmony_ci    mi->does_3pass = 1;
1767141cc406Sopenharmony_ci    mi->modes &= ~MI_MODES_ONEPASS;
1768141cc406Sopenharmony_ci  }
1769141cc406Sopenharmony_ci
1770141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1771141cc406Sopenharmony_ci}
1772141cc406Sopenharmony_ci
1773141cc406Sopenharmony_ci
1774141cc406Sopenharmony_ci
1775141cc406Sopenharmony_ci/********************************************************************/
1776141cc406Sopenharmony_ci/* Dump all we know about scanner to stderr                         */
1777141cc406Sopenharmony_ci/********************************************************************/
1778141cc406Sopenharmony_cistatic SANE_Status
1779141cc406Sopenharmony_cidump_inquiry(Microtek_Info *mi, unsigned char *result)
1780141cc406Sopenharmony_ci{
1781141cc406Sopenharmony_ci  int i;
1782141cc406Sopenharmony_ci
1783141cc406Sopenharmony_ci  DBG(15, "dump_inquiry...\n");
1784141cc406Sopenharmony_ci  DBG(1, " === SANE/Microtek backend v%d.%d.%d ===\n",
1785141cc406Sopenharmony_ci	  MICROTEK_MAJOR, MICROTEK_MINOR, MICROTEK_PATCH);
1786141cc406Sopenharmony_ci  DBG(1, "========== Scanner Inquiry Block ========mm\n");
1787141cc406Sopenharmony_ci  for (i=0; i<96; ) {
1788141cc406Sopenharmony_ci    if (!(i % 16)) MDBG_INIT("");
1789141cc406Sopenharmony_ci    MDBG_ADD("%02x ", (int)result[i++]);
1790141cc406Sopenharmony_ci    if (!(i % 16)) MDBG_FINISH(1);
1791141cc406Sopenharmony_ci  }
1792141cc406Sopenharmony_ci  DBG(1, "========== Scanner Inquiry Report ==========\n");
1793141cc406Sopenharmony_ci  DBG(1, "===== Scanner ID...\n");
1794141cc406Sopenharmony_ci  DBG(1, "Device Type Code: 0x%02x\n", mi->device_type);
1795141cc406Sopenharmony_ci  DBG(1, "Model Code: 0x%02x\n", mi->model_code);
1796141cc406Sopenharmony_ci  DBG(1, "Vendor Name: '%s'   Model Name: '%s'\n",
1797141cc406Sopenharmony_ci	  mi->vendor_id, mi->model_name);
1798141cc406Sopenharmony_ci  DBG(1, "Vendor Specific String: '%s'\n", mi->vendor_string);
1799141cc406Sopenharmony_ci  DBG(1, "Firmware Rev: '%s'\n", mi->revision_num);
1800141cc406Sopenharmony_ci  DBG(1,
1801141cc406Sopenharmony_ci	  "SCSI F/W version: %1d.%1d     Scanner F/W version: %1d.%1d\n",
1802141cc406Sopenharmony_ci	  mi->SCSI_firmware_ver_major, mi->SCSI_firmware_ver_minor,
1803141cc406Sopenharmony_ci	  mi->scanner_firmware_ver_major, mi->scanner_firmware_ver_minor);
1804141cc406Sopenharmony_ci  DBG(1, "Response data format: 0x%02x\n", mi->response_data_format);
1805141cc406Sopenharmony_ci
1806141cc406Sopenharmony_ci  DBG(1, "===== Imaging Capabilities...\n");
1807141cc406Sopenharmony_ci  DBG(1, "Modes:  %s%s%s%s%s%s%s\n",
1808141cc406Sopenharmony_ci	  (mi->modes & MI_MODES_LINEART) ? "Lineart " : "",
1809141cc406Sopenharmony_ci	  (mi->modes & MI_MODES_HALFTONE) ? "Halftone " : "",
1810141cc406Sopenharmony_ci	  (mi->modes & MI_MODES_GRAY) ? "Gray " : "",
1811141cc406Sopenharmony_ci	  (mi->modes & MI_MODES_COLOR) ? "Color " : "",
1812141cc406Sopenharmony_ci	  (mi->modes & MI_MODES_TRANSMSV) ? "(X-msv) " : "",
1813141cc406Sopenharmony_ci	  (mi->modes & MI_MODES_ONEPASS) ? "(OnePass) " : "",
1814141cc406Sopenharmony_ci	  (mi->modes & MI_MODES_NEGATIVE) ? "(Negative) " : "");
1815141cc406Sopenharmony_ci  DBG(1,
1816141cc406Sopenharmony_ci	  "Resolution Step Sizes: %s%s    Expanded Resolution Support? %s%s\n",
1817141cc406Sopenharmony_ci	  (mi->res_step & MI_RESSTEP_1PER) ? "1% " : "",
1818141cc406Sopenharmony_ci	  (mi->res_step & MI_RESSTEP_5PER) ? "5%" : "",
1819141cc406Sopenharmony_ci	  (mi->expanded_resolution) ? "yes" : "no",
1820141cc406Sopenharmony_ci	  (mi->expanded_resolution == 0xFF) ? "(but says no)" : "");
1821141cc406Sopenharmony_ci  DBG(1, "Supported Bits Per Sample: %s8 %s%s%s\n",
1822141cc406Sopenharmony_ci	  (mi->bit_formats & MI_FMT_CAP_4BPP) ? "4 " : "",
1823141cc406Sopenharmony_ci	  (mi->bit_formats & MI_FMT_CAP_10BPP) ? "10 " : "",
1824141cc406Sopenharmony_ci	  (mi->bit_formats & MI_FMT_CAP_12BPP) ? "12 " : "",
1825141cc406Sopenharmony_ci	  (mi->bit_formats & MI_FMT_CAP_16BPP) ? "16 " : "");
1826141cc406Sopenharmony_ci  DBG(1, "Max. document size code: 0x%02x\n",
1827141cc406Sopenharmony_ci	  mi->doc_size_code);
1828141cc406Sopenharmony_ci  DBG(1, "Max. document size:  %d x %d pixels\n",
1829141cc406Sopenharmony_ci	  mi->max_x, mi->max_y);
1830141cc406Sopenharmony_ci  DBG(1, "Frame units:  %s%s\n",
1831141cc406Sopenharmony_ci	  (mi->unit_type & MI_UNIT_PIXELS) ? "pixels  " : "",
1832141cc406Sopenharmony_ci	  (mi->unit_type & MI_UNIT_8TH_INCH) ? "1/8\"'s " : "");
1833141cc406Sopenharmony_ci  DBG(1, "# of built-in halftones: %d   Downloadable patterns? %s\n",
1834141cc406Sopenharmony_ci	  mi->pattern_count, (mi->pattern_dwnld) ? "Yes" : "No");
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_ci  DBG(1, "Data Compression: %s%s\n",
1837141cc406Sopenharmony_ci	  (mi->compress_type & MI_COMPRSS_HUFF) ? "huffman " : "",
1838141cc406Sopenharmony_ci	  (mi->compress_type & MI_COMPRSS_RD) ? "read-data " : "");
1839141cc406Sopenharmony_ci  DBG(1, "Contrast Settings: %d   Exposure Settings: %d\n",
1840141cc406Sopenharmony_ci	  mi->cont_settings, mi->exp_settings);
1841141cc406Sopenharmony_ci  DBG(1, "Adjustable Shadow/Highlight? %s   Adjustable Midtone? %s\n",
1842141cc406Sopenharmony_ci	  (mi->enhance_cap & MI_ENH_CAP_SHADOW) ? "yes" : "no ",
1843141cc406Sopenharmony_ci	  (mi->enhance_cap & MI_ENH_CAP_MIDTONE) ? "yes" : "no ");
1844141cc406Sopenharmony_ci  DBG(1, "Digital brightness/offset? %s\n",
1845141cc406Sopenharmony_ci	  (mi->extra_cap & MI_EXCAP_OFF_CTL) ? "yes" : "no");
1846141cc406Sopenharmony_ci  /*
1847141cc406Sopenharmony_ci  fprintf(stderr,
1848141cc406Sopenharmony_ci	  "Gamma Table Size: %d entries of %d bytes (max. value: %d)\n",
1849141cc406Sopenharmony_ci	  mi->max_lookup_size, mi->gamma_size, mi->max_gamma_val);
1850141cc406Sopenharmony_ci  */
1851141cc406Sopenharmony_ci  DBG(1,
1852141cc406Sopenharmony_ci	  "Gamma Table Size: %d entries of %d bytes (max. depth: %d)\n",
1853141cc406Sopenharmony_ci	  mi->max_lookup_size, mi->gamma_size, mi->max_gamma_bit_depth);
1854141cc406Sopenharmony_ci
1855141cc406Sopenharmony_ci  DBG(1, "===== Source Options...\n");
1856141cc406Sopenharmony_ci  DBG(1, "Feed type:  %s%s   ADF support? %s\n",
1857141cc406Sopenharmony_ci	  (mi->feed_type & MI_FEED_FLATBED) ? "flatbed " : "",
1858141cc406Sopenharmony_ci	  (mi->feed_type & MI_FEED_EDGEFEED) ? "edge-feed " : "",
1859141cc406Sopenharmony_ci	  (mi->feed_type & MI_FEED_AUTOSUPP) ? "yes" : "no");
1860141cc406Sopenharmony_ci  DBG(1, "Document Feeder Support? %s   Feeder Backtracking? %s\n",
1861141cc406Sopenharmony_ci	  (mi->source_options & MI_SRC_FEED_SUPP) ? "yes" : "no ",
1862141cc406Sopenharmony_ci	  (mi->source_options & MI_SRC_FEED_BT) ? "yes" : "no ");
1863141cc406Sopenharmony_ci  DBG(1, "Feeder Installed? %s          Feeder Ready? %s\n",
1864141cc406Sopenharmony_ci	  (mi->source_options & MI_SRC_HAS_FEED) ? "yes" : "no ",
1865141cc406Sopenharmony_ci	  (mi->source_options & MI_SRC_FEED_RDY) ? "yes" : "no ");
1866141cc406Sopenharmony_ci  DBG(1, "Transparency Adapter Installed? %s\n",
1867141cc406Sopenharmony_ci	  (mi->source_options & MI_SRC_HAS_TRANS) ? "yes" : "no ");
1868141cc406Sopenharmony_ci  /* GET_TRANS GET_FEED XXXXXXXXX */
1869141cc406Sopenharmony_ci  /* mt_SWslct ???? XXXXXXXXXXX */
1870141cc406Sopenharmony_ci  /*#define DOC_ON_FLATBED 0x00
1871141cc406Sopenharmony_ci    #define DOC_IN_FEEDER  0x01
1872141cc406Sopenharmony_ci    #define TRANSPARENCY   0x10
1873141cc406Sopenharmony_ci    */
1874141cc406Sopenharmony_ci  DBG(1, "Fast Color Prescan? %s\n",
1875141cc406Sopenharmony_ci	  (mi->fast_color_preview) ? "yes" : "no");
1876141cc406Sopenharmony_ci  DBG(1, "Selectable Transfer Format? %s\n",
1877141cc406Sopenharmony_ci	  (mi->xfer_format_select) ? "yes" : "no");
1878141cc406Sopenharmony_ci  MDBG_INIT("Color Transfer Sequence: ");
1879141cc406Sopenharmony_ci  switch (mi->color_sequence) {
1880141cc406Sopenharmony_ci  case MI_COLSEQ_PLANE:
1881141cc406Sopenharmony_ci    MDBG_ADD("plane-by-plane (3-pass)"); break;
1882141cc406Sopenharmony_ci  case MI_COLSEQ_PIXEL:
1883141cc406Sopenharmony_ci    MDBG_ADD("pixel-by-pixel RGB"); break;
1884141cc406Sopenharmony_ci  case MI_COLSEQ_RGB:
1885141cc406Sopenharmony_ci    MDBG_ADD("line-by-line, R-G-B sequence"); break;
1886141cc406Sopenharmony_ci  case MI_COLSEQ_NONRGB:
1887141cc406Sopenharmony_ci    MDBG_ADD("line-by-line, non-sequential with headers"); break;
1888141cc406Sopenharmony_ci  case MI_COLSEQ_2PIXEL:
1889141cc406Sopenharmony_ci    MDBG_ADD("2pixel-by-2pixel RRGGBB"); break;
1890141cc406Sopenharmony_ci  default:
1891141cc406Sopenharmony_ci    MDBG_ADD("UNKNOWN CODE (0x%02x)", mi->color_sequence);
1892141cc406Sopenharmony_ci  }
1893141cc406Sopenharmony_ci  MDBG_FINISH(1);
1894141cc406Sopenharmony_ci  /*  if (mi->modes & MI_MODES_ONEPASS) XXXXXXXXXXX */
1895141cc406Sopenharmony_ci  DBG(1, "Three pass scan support? %s\n",
1896141cc406Sopenharmony_ci	  (mi->does_3pass ? "yes" : "no"));
1897141cc406Sopenharmony_ci  DBG(1, "ModeSelect-1 and ModeSense-1 Support? %s\n",
1898141cc406Sopenharmony_ci	  (mi->does_mode1) ? "yes" : "no");
1899141cc406Sopenharmony_ci  DBG(1, "Can Disable Linearization Table? %s\n",
1900141cc406Sopenharmony_ci	  (mi->extra_cap & MI_EXCAP_DIS_LNTBL) ? "yes" : "no");
1901141cc406Sopenharmony_ci  DBG(1, "Can Disable Start-of-Scan Recalibration? %s\n",
1902141cc406Sopenharmony_ci	  (mi->extra_cap & MI_EXCAP_DIS_RECAL) ? "yes" : "no");
1903141cc406Sopenharmony_ci
1904141cc406Sopenharmony_ci  DBG(1, "Internal expanded expansion? %s\n",
1905141cc406Sopenharmony_ci	  mi->does_expansion ? "yes" : "no");
1906141cc406Sopenharmony_ci  /*
1907141cc406Sopenharmony_ci    fprintf(stderr, "cntr_vals = %d, min_cntr = %d, max_cntr = %d\n",
1908141cc406Sopenharmony_ci    cntr_vals, min_cntr, max_cntr);
1909141cc406Sopenharmony_ci    fprintf(stderr, "exp_vals = %d, min_exp = %d, max_exp = %d\n",
1910141cc406Sopenharmony_ci    exp_vals, min_exp, max_exp);
1911141cc406Sopenharmony_ci    */
1912141cc406Sopenharmony_ci  DBG(1, "====== End of Scanner Inquiry Report =======\n");
1913141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1914141cc406Sopenharmony_ci}
1915141cc406Sopenharmony_ci
1916141cc406Sopenharmony_ci
1917141cc406Sopenharmony_ci/********************************************************************/
1918141cc406Sopenharmony_ci/* Dump all we know about some unknown scanner to stderr            */
1919141cc406Sopenharmony_ci/********************************************************************/
1920141cc406Sopenharmony_cistatic SANE_Status
1921141cc406Sopenharmony_cidump_suspect_inquiry(unsigned char *result)
1922141cc406Sopenharmony_ci{
1923141cc406Sopenharmony_ci  int i;
1924141cc406Sopenharmony_ci  char vendor_id[9], model_name[17], revision_num[5];
1925141cc406Sopenharmony_ci  SANE_Byte device_type, model_code;
1926141cc406Sopenharmony_ci  SANE_Byte SCSI_firmware_ver_major, SCSI_firmware_ver_minor;
1927141cc406Sopenharmony_ci  SANE_Byte scanner_firmware_ver_major, scanner_firmware_ver_minor;
1928141cc406Sopenharmony_ci  SANE_Byte response_data_format;
1929141cc406Sopenharmony_ci
1930141cc406Sopenharmony_ci  DBG(15, "dump_suspect_inquiry...\n");
1931141cc406Sopenharmony_ci  DBG(1, " === SANE/Microtek backend v%d.%d.%d ===\n",
1932141cc406Sopenharmony_ci	  MICROTEK_MAJOR, MICROTEK_MINOR, MICROTEK_PATCH);
1933141cc406Sopenharmony_ci  DBG(1, "========== Scanner Inquiry Block ========mm\n");
1934141cc406Sopenharmony_ci  for (i=0; i<96; ) {
1935141cc406Sopenharmony_ci    if (!(i % 16)) MDBG_INIT("");
1936141cc406Sopenharmony_ci    MDBG_ADD("%02x ", (int)result[i++]);
1937141cc406Sopenharmony_ci    if (!(i % 16)) MDBG_FINISH(1);
1938141cc406Sopenharmony_ci  }
1939141cc406Sopenharmony_ci#if 0
1940141cc406Sopenharmony_ci  for (i=0; i<96; i++) {
1941141cc406Sopenharmony_ci    if (!(i % 16) && (i)) fprintf(stderr, "\n");
1942141cc406Sopenharmony_ci    fprintf(stderr, "%02x ", (int)result[i]);
1943141cc406Sopenharmony_ci  }
1944141cc406Sopenharmony_ci  fprintf(stderr, "\n\n");
1945141cc406Sopenharmony_ci#endif
1946141cc406Sopenharmony_ci  snprintf(vendor_id,     8 + 1, "%.*s",  8, (char *)&result[8]);
1947141cc406Sopenharmony_ci  snprintf(model_name,   16 + 1, "%.*s", 16, (char *)&result[16]);
1948141cc406Sopenharmony_ci  snprintf(revision_num,  4 + 1, "%.*s",  4, (char *)&result[32]);
1949141cc406Sopenharmony_ci  device_type                = (SANE_Byte)(result[0] & 0x1f);
1950141cc406Sopenharmony_ci  SCSI_firmware_ver_major    = (SANE_Byte)((result[1] & 0xf0) >> 4);
1951141cc406Sopenharmony_ci  SCSI_firmware_ver_minor    = (SANE_Byte)(result[1] & 0x0f);
1952141cc406Sopenharmony_ci  scanner_firmware_ver_major = (SANE_Byte)((result[2] & 0xf0) >> 4);
1953141cc406Sopenharmony_ci  scanner_firmware_ver_minor = (SANE_Byte)(result[2] & 0x0f);
1954141cc406Sopenharmony_ci  response_data_format       = (SANE_Byte)(result[3]);
1955141cc406Sopenharmony_ci  model_code                 = (SANE_Byte)(result[62]);
1956141cc406Sopenharmony_ci
1957141cc406Sopenharmony_ci  DBG(1, "========== Scanner Inquiry Report ==========\n");
1958141cc406Sopenharmony_ci  DBG(1, "===== Scanner ID...\n");
1959141cc406Sopenharmony_ci  DBG(1, "Device Type Code: 0x%02x\n", device_type);
1960141cc406Sopenharmony_ci  DBG(1, "Model Code: 0x%02x\n", model_code);
1961141cc406Sopenharmony_ci  DBG(1, "Vendor Name: '%s'   Model Name: '%s'\n",
1962141cc406Sopenharmony_ci	  vendor_id, model_name);
1963141cc406Sopenharmony_ci  DBG(1, "Firmware Rev: '%s'\n", revision_num);
1964141cc406Sopenharmony_ci  DBG(1,
1965141cc406Sopenharmony_ci	  "SCSI F/W version: %1d.%1d     Scanner F/W version: %1d.%1d\n",
1966141cc406Sopenharmony_ci	  SCSI_firmware_ver_major, SCSI_firmware_ver_minor,
1967141cc406Sopenharmony_ci	  scanner_firmware_ver_major, scanner_firmware_ver_minor);
1968141cc406Sopenharmony_ci  DBG(1, "Response data format: 0x%02x\n", response_data_format);
1969141cc406Sopenharmony_ci  DBG(1, "====== End of Scanner Inquiry Report =======\n");
1970141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1971141cc406Sopenharmony_ci}
1972141cc406Sopenharmony_ci
1973141cc406Sopenharmony_ci
1974141cc406Sopenharmony_ci/********************************************************************/
1975141cc406Sopenharmony_ci/* Determine if device is a Microtek Scanner (from INQUIRY info)    */
1976141cc406Sopenharmony_ci/********************************************************************/
1977141cc406Sopenharmony_cistatic SANE_Status
1978141cc406Sopenharmony_ciid_microtek(uint8_t *result, char **model_string)
1979141cc406Sopenharmony_ci{
1980141cc406Sopenharmony_ci  SANE_Byte device_type, response_data_format;
1981141cc406Sopenharmony_ci  int forcewarn = 0;
1982141cc406Sopenharmony_ci
1983141cc406Sopenharmony_ci  DBG(15, "id_microtek...\n");
1984141cc406Sopenharmony_ci  /* check device type first... */
1985141cc406Sopenharmony_ci  device_type = (SANE_Byte)(result[0] & 0x1f);
1986141cc406Sopenharmony_ci  if (device_type != 0x06) {
1987141cc406Sopenharmony_ci    DBG(15, "id_microtek:  not even a scanner:  dev_type = %d\n",
1988141cc406Sopenharmony_ci	device_type);
1989141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1990141cc406Sopenharmony_ci  }
1991141cc406Sopenharmony_ci  if (!(strncmp("MICROTEK", (char *)&(result[8]), 8)) ||
1992141cc406Sopenharmony_ci      !(strncmp("MII SC31", (char *)&(result[8]), 8)) ||  /* the IISP */
1993141cc406Sopenharmony_ci      !(strncmp("MII SC21", (char *)&(result[8]), 8)) ||  /* the 600ZS */
1994141cc406Sopenharmony_ci      !(strncmp("MII SC23", (char *)&(result[8]), 8)) ||  /* the other 600ZS */
1995141cc406Sopenharmony_ci      !(strncmp("MII SC25", (char *)&(result[8]), 8)) ||  /* some other 600GS */
1996141cc406Sopenharmony_ci      !(strncmp("AGFA    ", (char *)&(result[8]), 8)) ||  /* Arcus II */
1997141cc406Sopenharmony_ci      !(strncmp("Microtek", (char *)&(result[8]), 8)) ||  /* some 35t+'s */
1998141cc406Sopenharmony_ci      !(strncmp("Polaroid", (char *)&(result[8]), 8)) ||  /* SprintScan 35LE */
1999141cc406Sopenharmony_ci      !(strncmp("        ", (char *)&(result[8]), 8)) ) {
2000141cc406Sopenharmony_ci    switch (result[62]) {
2001141cc406Sopenharmony_ci    case 0x16 :
2002141cc406Sopenharmony_ci      *model_string = "ScanMaker 600ZS";    break;
2003141cc406Sopenharmony_ci    case 0x50 :
2004141cc406Sopenharmony_ci      *model_string = "ScanMaker II/IIXE";  break;
2005141cc406Sopenharmony_ci    case 0x51 :
2006141cc406Sopenharmony_ci      *model_string = "ScanMaker 45t";      break;
2007141cc406Sopenharmony_ci    case 0x52 :
2008141cc406Sopenharmony_ci      *model_string = "ScanMaker 35t";      break;
2009141cc406Sopenharmony_ci    case 0x54 :
2010141cc406Sopenharmony_ci      *model_string = "ScanMaker IISP";     break;
2011141cc406Sopenharmony_ci    case 0x55 :
2012141cc406Sopenharmony_ci      *model_string = "ScanMaker IIER";     break;
2013141cc406Sopenharmony_ci    case 0x56 :
2014141cc406Sopenharmony_ci      *model_string = "ScanMaker A3t";      break;
2015141cc406Sopenharmony_ci    case 0x57 :
2016141cc406Sopenharmony_ci      *model_string = "ScanMaker IIHR";     break;
2017141cc406Sopenharmony_ci    case 0x58 :
2018141cc406Sopenharmony_ci      *model_string = "ScanMaker IIG";      break;
2019141cc406Sopenharmony_ci    case 0x59 :
2020141cc406Sopenharmony_ci      *model_string = "ScanMaker III";      break;
2021141cc406Sopenharmony_ci    case 0x5A :
2022141cc406Sopenharmony_ci      *model_string = "Agfa StudioScan";    break;
2023141cc406Sopenharmony_ci    case 0x5B :
2024141cc406Sopenharmony_ci      *model_string = "Agfa StudioScan II"; break;
2025141cc406Sopenharmony_ci    case 0x5C :
2026141cc406Sopenharmony_ci      *model_string = "Agfa Arcus II";      break;
2027141cc406Sopenharmony_ci    case 0x5f :
2028141cc406Sopenharmony_ci      *model_string = "ScanMaker E3";       break;
2029141cc406Sopenharmony_ci    case 0x62 :
2030141cc406Sopenharmony_ci      if (!(strncmp("Polaroid", (char *)&(result[8]), 8)))
2031141cc406Sopenharmony_ci	*model_string = "Polaroid SprintScan 35/LE";
2032141cc406Sopenharmony_ci      else
2033141cc406Sopenharmony_ci	*model_string = "ScanMaker 35t+";
2034141cc406Sopenharmony_ci      break;
2035141cc406Sopenharmony_ci    case 0x63 :
2036141cc406Sopenharmony_ci    case 0x66 :
2037141cc406Sopenharmony_ci      *model_string = "ScanMaker E6";       break;
2038141cc406Sopenharmony_ci    case 0x64 : /* and "Vobis RealScan" */
2039141cc406Sopenharmony_ci      *model_string = "ScanMaker E2";       break;
2040141cc406Sopenharmony_ci    case 0x65:
2041141cc406Sopenharmony_ci      *model_string = "Color PageWiz";      break;
2042141cc406Sopenharmony_ci    case 0xC8:
2043141cc406Sopenharmony_ci      *model_string = "ScanMaker 600ZS";    break;
2044141cc406Sopenharmony_ci      /* the follow are listed in the docs, but are otherwise a mystery... */
2045141cc406Sopenharmony_ci    case 0x5D:
2046141cc406Sopenharmony_ci      *model_string = "Agfa DuoScan";  forcewarn = 1; break;
2047141cc406Sopenharmony_ci    case 0x5E:
2048141cc406Sopenharmony_ci      *model_string = "SS3";      forcewarn = 1; break;
2049141cc406Sopenharmony_ci    case 0x60:
2050141cc406Sopenharmony_ci      *model_string = "HR1";      forcewarn = 1; break;
2051141cc406Sopenharmony_ci    case 0x61:
2052141cc406Sopenharmony_ci      *model_string = "45T+";     forcewarn = 1; break;
2053141cc406Sopenharmony_ci    case 0x67:
2054141cc406Sopenharmony_ci      *model_string = "TR3";      forcewarn = 1; break;
2055141cc406Sopenharmony_ci    default :
2056141cc406Sopenharmony_ci      /* this might be a newer scanner, which uses the SCSI II command set. */
2057141cc406Sopenharmony_ci      /* that's unfortunate, but we'll warn the user anyway....             */
2058141cc406Sopenharmony_ci      response_data_format = (SANE_Byte)(result[3]);
2059141cc406Sopenharmony_ci      if (response_data_format == 0x02) {
2060141cc406Sopenharmony_ci	DBG(15, "id_microtek:  (uses new SCSI II command set)\n");
2061141cc406Sopenharmony_ci	if (DBG_LEVEL >= 15) {
2062141cc406Sopenharmony_ci	  DBG(1, "\n");
2063141cc406Sopenharmony_ci	  DBG(1, "\n");
2064141cc406Sopenharmony_ci	  DBG(1, "\n");
2065141cc406Sopenharmony_ci	  DBG(1, "========== Congratulations! ==========\n");
2066141cc406Sopenharmony_ci	  DBG(1, "You appear to be the proud owner of a \n");
2067141cc406Sopenharmony_ci	  DBG(1, "brand-new Microtek scanner, which uses\n");
2068141cc406Sopenharmony_ci	  DBG(1, "a new SCSI II command set.            \n");
2069141cc406Sopenharmony_ci	  DBG(1, "\n");
2070141cc406Sopenharmony_ci	  DBG(1, "Try the `microtek2' backend instead.  \n");
2071141cc406Sopenharmony_ci	  DBG(1, "\n");
2072141cc406Sopenharmony_ci	  DBG(1, "\n");
2073141cc406Sopenharmony_ci	  DBG(1, "\n");
2074141cc406Sopenharmony_ci	}
2075141cc406Sopenharmony_ci      }
2076141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2077141cc406Sopenharmony_ci    }
2078141cc406Sopenharmony_ci    if (forcewarn) {
2079141cc406Sopenharmony_ci      /* force debugging on, to encourage user to send in a report */
2080141cc406Sopenharmony_ci#ifndef NDEBUG
2081141cc406Sopenharmony_ci      DBG_LEVEL = 1;
2082141cc406Sopenharmony_ci#endif
2083141cc406Sopenharmony_ci      DBG(1, "\n");
2084141cc406Sopenharmony_ci      DBG(1, "\n");
2085141cc406Sopenharmony_ci      DBG(1, "\n");
2086141cc406Sopenharmony_ci      DBG(1, "========== Congratulations! ==========\n");
2087141cc406Sopenharmony_ci      DBG(1, "Your scanner appears to be supported  \n");
2088141cc406Sopenharmony_ci      DBG(1, "by the microtek backend.  However, it \n");
2089141cc406Sopenharmony_ci      DBG(1, "has never been tried before, and some \n");
2090141cc406Sopenharmony_ci      DBG(1, "parameters are bound to be wrong.     \n");
2091141cc406Sopenharmony_ci      DBG(1, "\n");
2092141cc406Sopenharmony_ci      DBG(1, "Please send the scanner inquiry log in\n");
2093141cc406Sopenharmony_ci      DBG(1, "its entirety to mtek-bugs@mir.com and \n");
2094141cc406Sopenharmony_ci      DBG(1, "include a description of the scanner, \n");
2095141cc406Sopenharmony_ci      DBG(1, "including the base optical resolution.\n");
2096141cc406Sopenharmony_ci      DBG(1, "\n");
2097141cc406Sopenharmony_ci      DBG(1, "You'll find complete instructions for \n");
2098141cc406Sopenharmony_ci      DBG(1, "submitting an error/debug log in the  \n");
2099141cc406Sopenharmony_ci      DBG(1, "'sane-microtek' man-page.             \n");
2100141cc406Sopenharmony_ci      DBG(1, "\n");
2101141cc406Sopenharmony_ci      DBG(1, "\n");
2102141cc406Sopenharmony_ci      DBG(1, "\n");
2103141cc406Sopenharmony_ci    }
2104141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
2105141cc406Sopenharmony_ci  }
2106141cc406Sopenharmony_ci  DBG(15, "id_microtek:  not microtek:  %d, %d, %d\n",
2107141cc406Sopenharmony_ci      strncmp("MICROTEK", (char *)&(result[8]), 8),
2108141cc406Sopenharmony_ci      strncmp("        ", (char *)&(result[8]), 8),
2109141cc406Sopenharmony_ci      result[62]);
2110141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
2111141cc406Sopenharmony_ci}
2112141cc406Sopenharmony_ci
2113141cc406Sopenharmony_ci
2114141cc406Sopenharmony_ci
2115141cc406Sopenharmony_ci/********************************************************************/
2116141cc406Sopenharmony_ci/* Try to attach a device as a Microtek scanner                     */
2117141cc406Sopenharmony_ci/********************************************************************/
2118141cc406Sopenharmony_cistatic SANE_Status
2119141cc406Sopenharmony_ciattach_scanner(const char *devicename, Microtek_Device **devp)
2120141cc406Sopenharmony_ci{
2121141cc406Sopenharmony_ci  Microtek_Device *dev;
2122141cc406Sopenharmony_ci  int sfd;
2123141cc406Sopenharmony_ci  size_t size;
2124141cc406Sopenharmony_ci  unsigned char result[0x60];
2125141cc406Sopenharmony_ci  SANE_Status status;
2126141cc406Sopenharmony_ci  char *model_string;
2127141cc406Sopenharmony_ci  uint8_t inquiry[] = { 0x12, 0, 0, 0, 0x60, 0 };
2128141cc406Sopenharmony_ci
2129141cc406Sopenharmony_ci  DBG(15,"attach_scanner:  %s\n", devicename);
2130141cc406Sopenharmony_ci  /* check if device is already known... */
2131141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next) {
2132141cc406Sopenharmony_ci    if (strcmp(dev->sane.name, devicename) == 0) {
2133141cc406Sopenharmony_ci      if (devp) *devp = dev;
2134141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2135141cc406Sopenharmony_ci    }
2136141cc406Sopenharmony_ci  }
2137141cc406Sopenharmony_ci
2138141cc406Sopenharmony_ci  /* open scsi device... */
2139141cc406Sopenharmony_ci  DBG(20, "attach_scanner:  opening %s\n", devicename);
2140141cc406Sopenharmony_ci  if (sanei_scsi_open(devicename, &sfd, sense_handler, NULL) != 0) {
2141141cc406Sopenharmony_ci    DBG(20, "attach_scanner:  open failed\n");
2142141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
2143141cc406Sopenharmony_ci  }
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_ci  /* say hello... */
2146141cc406Sopenharmony_ci  DBG(20, "attach_scanner:  sending INQUIRY\n");
2147141cc406Sopenharmony_ci  size = sizeof(result);
2148141cc406Sopenharmony_ci  status = sanei_scsi_cmd(sfd, inquiry, sizeof(inquiry), result, &size);
2149141cc406Sopenharmony_ci  sanei_scsi_close (sfd);
2150141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD || size != 0x60) {
2151141cc406Sopenharmony_ci    DBG(20, "attach_scanner:  inquiry failed (%s)\n", sane_strstatus (status));
2152141cc406Sopenharmony_ci    return status;
2153141cc406Sopenharmony_ci  }
2154141cc406Sopenharmony_ci
2155141cc406Sopenharmony_ci  if (id_microtek(result, &model_string) != SANE_STATUS_GOOD) {
2156141cc406Sopenharmony_ci      DBG(15, "attach_scanner:  device doesn't look like a Microtek scanner.");
2157141cc406Sopenharmony_ci      if (DBG_LEVEL >= 5) dump_suspect_inquiry(result);
2158141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
2159141cc406Sopenharmony_ci  }
2160141cc406Sopenharmony_ci
2161141cc406Sopenharmony_ci  dev=malloc(sizeof(*dev));
2162141cc406Sopenharmony_ci  if (!dev) return SANE_STATUS_NO_MEM;
2163141cc406Sopenharmony_ci  memset(dev, 0, sizeof(*dev));
2164141cc406Sopenharmony_ci
2165141cc406Sopenharmony_ci  parse_inquiry(&(dev->info), result);
2166141cc406Sopenharmony_ci  if (DBG_LEVEL > 0) dump_inquiry(&(dev->info), result);
2167141cc406Sopenharmony_ci
2168141cc406Sopenharmony_ci  /* initialize dev structure */
2169141cc406Sopenharmony_ci  dev->sane.name   = strdup(devicename);
2170141cc406Sopenharmony_ci  dev->sane.vendor = "Microtek";
2171141cc406Sopenharmony_ci  dev->sane.model  = strdup(model_string);
2172141cc406Sopenharmony_ci  dev->sane.type   = "flatbed scanner";
2173141cc406Sopenharmony_ci
2174141cc406Sopenharmony_ci  /* link into device list... */
2175141cc406Sopenharmony_ci  ++num_devices;
2176141cc406Sopenharmony_ci  dev->next = first_dev;
2177141cc406Sopenharmony_ci  first_dev = dev;
2178141cc406Sopenharmony_ci  if (devp) *devp = dev;
2179141cc406Sopenharmony_ci
2180141cc406Sopenharmony_ci  DBG(15, "attach_scanner:  happy.\n");
2181141cc406Sopenharmony_ci
2182141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2183141cc406Sopenharmony_ci}
2184141cc406Sopenharmony_ci
2185141cc406Sopenharmony_ci
2186141cc406Sopenharmony_ci/********************************************************************/
2187141cc406Sopenharmony_ci/* Attach a scanner (convenience wrapper for find_scanners...)      */
2188141cc406Sopenharmony_ci/********************************************************************/
2189141cc406Sopenharmony_cistatic SANE_Status
2190141cc406Sopenharmony_ciattach_one (const char *dev)
2191141cc406Sopenharmony_ci{
2192141cc406Sopenharmony_ci  attach_scanner (dev, 0);
2193141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2194141cc406Sopenharmony_ci}
2195141cc406Sopenharmony_ci
2196141cc406Sopenharmony_ci
2197141cc406Sopenharmony_ci
2198141cc406Sopenharmony_ci
2199141cc406Sopenharmony_ci/********************************************************************/
2200141cc406Sopenharmony_ci/* End a scan, and clean up afterwards                              */
2201141cc406Sopenharmony_ci/********************************************************************/
2202141cc406Sopenharmony_cistatic SANE_Status end_scan(Microtek_Scanner *s, SANE_Status ostat)
2203141cc406Sopenharmony_ci{
2204141cc406Sopenharmony_ci  SANE_Status status;
2205141cc406Sopenharmony_ci
2206141cc406Sopenharmony_ci  DBG(15, "end_scan...\n");
2207141cc406Sopenharmony_ci  if (s->scanning) {
2208141cc406Sopenharmony_ci    s->scanning = SANE_FALSE;
2209141cc406Sopenharmony_ci    /* stop the scanner */
2210141cc406Sopenharmony_ci    if (s->scan_started) {
2211141cc406Sopenharmony_ci      status = stop_scan(s);
2212141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
2213141cc406Sopenharmony_ci	DBG(23, "end_scan:  OY! on stop_scan\n");
2214141cc406Sopenharmony_ci      s->scan_started = SANE_FALSE;
2215141cc406Sopenharmony_ci    }
2216141cc406Sopenharmony_ci    /* close the SCSI device */
2217141cc406Sopenharmony_ci    if (s->sfd != -1) {
2218141cc406Sopenharmony_ci      sanei_scsi_close(s->sfd);
2219141cc406Sopenharmony_ci      s->sfd = -1;
2220141cc406Sopenharmony_ci    }
2221141cc406Sopenharmony_ci    /* free the buffers we malloc'ed */
2222141cc406Sopenharmony_ci    if (s->scsi_buffer != NULL) {
2223141cc406Sopenharmony_ci      free(s->scsi_buffer);
2224141cc406Sopenharmony_ci      s->scsi_buffer = NULL;
2225141cc406Sopenharmony_ci    }
2226141cc406Sopenharmony_ci    if (s->rb != NULL) {
2227141cc406Sopenharmony_ci      ring_free(s->rb);
2228141cc406Sopenharmony_ci      s->rb = NULL;
2229141cc406Sopenharmony_ci    }
2230141cc406Sopenharmony_ci  }
2231141cc406Sopenharmony_ci  /* if this -was- pass 3, or cancel, then we must be done */
2232141cc406Sopenharmony_ci  if ((s->this_pass == 3) || (s->cancel))
2233141cc406Sopenharmony_ci    s->this_pass = 0;
2234141cc406Sopenharmony_ci  return ostat;
2235141cc406Sopenharmony_ci}
2236141cc406Sopenharmony_ci
2237141cc406Sopenharmony_ci
2238141cc406Sopenharmony_ci
2239141cc406Sopenharmony_ci/********************************************************************/
2240141cc406Sopenharmony_ci/********************************************************************/
2241141cc406Sopenharmony_ci/***** Scan-time operations                                     *****/
2242141cc406Sopenharmony_ci/********************************************************************/
2243141cc406Sopenharmony_ci/********************************************************************/
2244141cc406Sopenharmony_ci
2245141cc406Sopenharmony_ci
2246141cc406Sopenharmony_ci/* number of lines of calibration data returned by scanner */
2247141cc406Sopenharmony_ci#define STRIPS 12  /* well, that's what it seems to be for the E6 */
2248141cc406Sopenharmony_ci
2249141cc406Sopenharmony_ci
2250141cc406Sopenharmony_ci/* simple comparison for the qsort below */
2251141cc406Sopenharmony_ci
2252141cc406Sopenharmony_cistatic int comparo(const void *a, const void *b)
2253141cc406Sopenharmony_ci{
2254141cc406Sopenharmony_ci  return (*(const int *)a - *(const int *)b);
2255141cc406Sopenharmony_ci}
2256141cc406Sopenharmony_ci
2257141cc406Sopenharmony_ci
2258141cc406Sopenharmony_ci/* extract values from scanlines and sort */
2259141cc406Sopenharmony_ci
2260141cc406Sopenharmony_cistatic void sort_values(int *result, uint8_t *scanline[], int pix)
2261141cc406Sopenharmony_ci{
2262141cc406Sopenharmony_ci  int i;
2263141cc406Sopenharmony_ci  for (i=0; i<STRIPS; i++) result[i] = (scanline[i])[pix];
2264141cc406Sopenharmony_ci  qsort(result, STRIPS, sizeof(result[0]), comparo);
2265141cc406Sopenharmony_ci}
2266141cc406Sopenharmony_ci
2267141cc406Sopenharmony_ci
2268141cc406Sopenharmony_ci/********************************************************************/
2269141cc406Sopenharmony_ci/* Calculate the calibration data.                                  */
2270141cc406Sopenharmony_ci/*  This seems to be, for each pixel of each R/G/B ccd, the average */
2271141cc406Sopenharmony_ci/*  of the STRIPS# values read by the scanner, presumably off some  */
2272141cc406Sopenharmony_ci/*  blank spot under the cover.                                     */
2273141cc406Sopenharmony_ci/*  The raw scanner data does indeed resemble the intensity profile */
2274141cc406Sopenharmony_ci/*  of a lamp.                                                      */
2275141cc406Sopenharmony_ci/*  The sort is used to calc the median, which is used to remove    */
2276141cc406Sopenharmony_ci/*  outliers in the data; maybe from dust under the cover?          */
2277141cc406Sopenharmony_ci/********************************************************************/
2278141cc406Sopenharmony_ci
2279141cc406Sopenharmony_ci
2280141cc406Sopenharmony_cistatic void calc_calibration(uint8_t *caldata, uint8_t *scanline[],
2281141cc406Sopenharmony_ci			     int pixels)
2282141cc406Sopenharmony_ci{
2283141cc406Sopenharmony_ci  int i,j;
2284141cc406Sopenharmony_ci  int sorted[STRIPS];
2285141cc406Sopenharmony_ci
2286141cc406Sopenharmony_ci  DBG(23, ".calc_calibration...\n");
2287141cc406Sopenharmony_ci  for (i=0; i<pixels; i++) {
2288141cc406Sopenharmony_ci    int q1, q3;
2289141cc406Sopenharmony_ci    int bot, top;
2290141cc406Sopenharmony_ci    int sum = 0;
2291141cc406Sopenharmony_ci    int count = 0;
2292141cc406Sopenharmony_ci
2293141cc406Sopenharmony_ci    sort_values(sorted, scanline, i);
2294141cc406Sopenharmony_ci    q1 = sorted[STRIPS / 4];       /* first quartile */
2295141cc406Sopenharmony_ci    q3 = sorted[STRIPS * 3 / 4];   /* third quartile */
2296141cc406Sopenharmony_ci    bot = q1 - 3 * (q3 - q1) / 2;  /* quick'n'easy bounds */
2297141cc406Sopenharmony_ci    top = q3 + 3 * (q3 - q1) / 2;
2298141cc406Sopenharmony_ci
2299141cc406Sopenharmony_ci    for (j=0; j<STRIPS; j++) {
2300141cc406Sopenharmony_ci      if ((sorted[j] >= bot) && (sorted[j] <= top)) {
2301141cc406Sopenharmony_ci	sum += sorted[j];
2302141cc406Sopenharmony_ci	count++;
2303141cc406Sopenharmony_ci      }
2304141cc406Sopenharmony_ci    }
2305141cc406Sopenharmony_ci    if (count)
2306141cc406Sopenharmony_ci      caldata[i] = (sum + (count / 2)) / count;
2307141cc406Sopenharmony_ci    else {
2308141cc406Sopenharmony_ci      DBG(23, "zero: i=%d b/t=%d/%d ", i, bot, top);
2309141cc406Sopenharmony_ci      if (DBG_LEVEL >= 23) {
2310141cc406Sopenharmony_ci	MDBG_INIT("");
2311141cc406Sopenharmony_ci	for (j=0; j<STRIPS; j++) MDBG_ADD(" %3d", sorted[j]);
2312141cc406Sopenharmony_ci	MDBG_FINISH(23);
2313141cc406Sopenharmony_ci      }
2314141cc406Sopenharmony_ci      caldata[i] = 0;
2315141cc406Sopenharmony_ci    }
2316141cc406Sopenharmony_ci  }
2317141cc406Sopenharmony_ci}
2318141cc406Sopenharmony_ci
2319141cc406Sopenharmony_ci
2320141cc406Sopenharmony_ci
2321141cc406Sopenharmony_ci/********************************************************************/
2322141cc406Sopenharmony_ci/* Calibrate scanner CCD, the "real" way.                           */
2323141cc406Sopenharmony_ci/*  This stuff is not documented in the command set, but this is    */
2324141cc406Sopenharmony_ci/*  what Microtek's TWAIN driver seems to do, more or less, on an   */
2325141cc406Sopenharmony_ci/*  E6 at least.  What other scanners will do this???               */
2326141cc406Sopenharmony_ci/********************************************************************/
2327141cc406Sopenharmony_ci
2328141cc406Sopenharmony_ci
2329141cc406Sopenharmony_cistatic SANE_Status do_real_calibrate(Microtek_Scanner *s)
2330141cc406Sopenharmony_ci{
2331141cc406Sopenharmony_ci  SANE_Status status, statusA;
2332141cc406Sopenharmony_ci  SANE_Int busy, linewidth, lines;
2333141cc406Sopenharmony_ci  size_t buffsize;
2334141cc406Sopenharmony_ci  uint8_t *input, *scanline[STRIPS], *combuff;
2335141cc406Sopenharmony_ci  uint8_t letter;
2336141cc406Sopenharmony_ci  int i, spot;
2337141cc406Sopenharmony_ci  int nmax, ntoget, nleft;
2338141cc406Sopenharmony_ci
2339141cc406Sopenharmony_ci  DBG(10, "do_real_calibrate...\n");
2340141cc406Sopenharmony_ci
2341141cc406Sopenharmony_ci  /* tell scanner to read it's little chart */
2342141cc406Sopenharmony_ci  if ((status = start_calibration(s)) != SANE_STATUS_GOOD) return status;
2343141cc406Sopenharmony_ci  if ((status = get_scan_status(s, &busy, &linewidth, &lines))
2344141cc406Sopenharmony_ci      != SANE_STATUS_GOOD) {
2345141cc406Sopenharmony_ci    DBG(23, "do_real_cal:  get_scan_status failed!\n");
2346141cc406Sopenharmony_ci    return status;
2347141cc406Sopenharmony_ci  }
2348141cc406Sopenharmony_ci  /* make room for data in and data out */
2349141cc406Sopenharmony_ci  input = calloc(STRIPS * 3 * linewidth, sizeof(input[0]));
2350141cc406Sopenharmony_ci  combuff = calloc(linewidth + 6, sizeof(combuff[0]));
2351141cc406Sopenharmony_ci  if ((input == NULL) || (combuff == NULL)) {
2352141cc406Sopenharmony_ci    DBG(23, "do_real_cal:  bad calloc %p %p\n",
2353141cc406Sopenharmony_ci        (void *) input, (void *) combuff);
2354141cc406Sopenharmony_ci    free(input);
2355141cc406Sopenharmony_ci    free(combuff);
2356141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2357141cc406Sopenharmony_ci  }
2358141cc406Sopenharmony_ci  /* read STRIPS lines of R, G, B ccd data */
2359141cc406Sopenharmony_ci  nmax = SCSI_BUFF_SIZE / (3 * linewidth);
2360141cc406Sopenharmony_ci  DBG(23, "do_real_cal:  getting data (max=%d)\n", nmax);
2361141cc406Sopenharmony_ci  for (nleft = STRIPS, spot=0;
2362141cc406Sopenharmony_ci       nleft > 0;
2363141cc406Sopenharmony_ci       nleft -= ntoget, spot += buffsize) {
2364141cc406Sopenharmony_ci    ntoget = (nleft > nmax) ? nmax : nleft;
2365141cc406Sopenharmony_ci    buffsize = ntoget * 3 * linewidth;
2366141cc406Sopenharmony_ci    DBG(23, "...nleft %d  toget %d  size %lu  spot %d  input+spot %p\n",
2367141cc406Sopenharmony_ci        nleft, ntoget, (u_long) buffsize, spot, (void *) (input+spot));
2368141cc406Sopenharmony_ci    if ((statusA = read_scan_data(s, ntoget, input+spot, &buffsize))
2369141cc406Sopenharmony_ci	!= SANE_STATUS_GOOD) {
2370141cc406Sopenharmony_ci      DBG(23, "...read scan failed\n");
2371141cc406Sopenharmony_ci      break;
2372141cc406Sopenharmony_ci    }
2373141cc406Sopenharmony_ci  }
2374141cc406Sopenharmony_ci  status = stop_scan(s);
2375141cc406Sopenharmony_ci  if ((statusA != SANE_STATUS_GOOD) || (status != SANE_STATUS_GOOD)) {
2376141cc406Sopenharmony_ci    free(input);
2377141cc406Sopenharmony_ci    free(combuff);
2378141cc406Sopenharmony_ci    return ((statusA != SANE_STATUS_GOOD) ? statusA : status);
2379141cc406Sopenharmony_ci  }
2380141cc406Sopenharmony_ci  /* calculate calibration data for each element and download */
2381141cc406Sopenharmony_ci  for (letter = 'R'; letter != 'X'; ) {
2382141cc406Sopenharmony_ci    DBG(23, "do_real_calibrate:  working on %c\n", letter);
2383141cc406Sopenharmony_ci    for (spot=0, i=0; spot < linewidth * STRIPS * 3; spot += linewidth) {
2384141cc406Sopenharmony_ci      if (input[spot+1] == letter) {
2385141cc406Sopenharmony_ci	DBG(23, "   found %d (at %d)\n", i, spot);
2386141cc406Sopenharmony_ci	if (i >= STRIPS) {
2387141cc406Sopenharmony_ci	  DBG(23, "WHOA!!!  %i have already been found!\n", i);
2388141cc406Sopenharmony_ci	  break;
2389141cc406Sopenharmony_ci	}
2390141cc406Sopenharmony_ci	scanline[i] = &(input[spot+2]);
2391141cc406Sopenharmony_ci	i++;
2392141cc406Sopenharmony_ci      }
2393141cc406Sopenharmony_ci    }
2394141cc406Sopenharmony_ci    calc_calibration(combuff + 8, scanline, linewidth - 2);
2395141cc406Sopenharmony_ci    if ((status = download_calibration(s, combuff, letter, linewidth))
2396141cc406Sopenharmony_ci	!= SANE_STATUS_GOOD) {
2397141cc406Sopenharmony_ci      DBG(23, "...download_calibration failed\n");
2398141cc406Sopenharmony_ci      free(input);
2399141cc406Sopenharmony_ci      free(combuff);
2400141cc406Sopenharmony_ci      return status;
2401141cc406Sopenharmony_ci    }
2402141cc406Sopenharmony_ci    switch (letter) {
2403141cc406Sopenharmony_ci    case 'R': letter = 'G'; break;
2404141cc406Sopenharmony_ci    case 'G': letter = 'B'; break;
2405141cc406Sopenharmony_ci    case 'B':
2406141cc406Sopenharmony_ci    default:  letter = 'X'; break;
2407141cc406Sopenharmony_ci    }
2408141cc406Sopenharmony_ci  }
2409141cc406Sopenharmony_ci  /* clean up */
2410141cc406Sopenharmony_ci  free(input);
2411141cc406Sopenharmony_ci  free(combuff);
2412141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2413141cc406Sopenharmony_ci}
2414141cc406Sopenharmony_ci
2415141cc406Sopenharmony_ci
2416141cc406Sopenharmony_ci
2417141cc406Sopenharmony_ci
2418141cc406Sopenharmony_ci/********************************************************************/
2419141cc406Sopenharmony_ci/* Cause scanner to calibrate, but don't really scan anything       */
2420141cc406Sopenharmony_ci/*           (i.e. do everything but read data)                     */
2421141cc406Sopenharmony_ci/********************************************************************/
2422141cc406Sopenharmony_cistatic SANE_Status do_precalibrate(SANE_Handle handle)
2423141cc406Sopenharmony_ci{
2424141cc406Sopenharmony_ci  Microtek_Scanner *s = handle;
2425141cc406Sopenharmony_ci  SANE_Status status, statusA;
2426141cc406Sopenharmony_ci  SANE_Int busy, linewidth, lines;
2427141cc406Sopenharmony_ci
2428141cc406Sopenharmony_ci  DBG(10, "do_precalibrate...\n");
2429141cc406Sopenharmony_ci
2430141cc406Sopenharmony_ci  if ((status = wait_ready(s)) != SANE_STATUS_GOOD) return status;
2431141cc406Sopenharmony_ci  {
2432141cc406Sopenharmony_ci    SANE_Int y1 = s->y1;
2433141cc406Sopenharmony_ci    SANE_Int y2 = s->y2;
2434141cc406Sopenharmony_ci    /* some small range, but large enough to cause the scanner
2435141cc406Sopenharmony_ci       to think it'll scan *something*... */
2436141cc406Sopenharmony_ci    s->y1 = 0;
2437141cc406Sopenharmony_ci    s->y2 =
2438141cc406Sopenharmony_ci      (s->resolution > s->dev->info.base_resolution) ?
2439141cc406Sopenharmony_ci      4 : 4 * s->dev->info.base_resolution / s->resolution;
2440141cc406Sopenharmony_ci    status = scanning_frame(s);
2441141cc406Sopenharmony_ci    s->y1 = y1;
2442141cc406Sopenharmony_ci    s->y2 = y2;
2443141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) return status;
2444141cc406Sopenharmony_ci  }
2445141cc406Sopenharmony_ci
2446141cc406Sopenharmony_ci  if (s->dev->info.source_options &
2447141cc406Sopenharmony_ci      (MI_SRC_FEED_BT | MI_SRC_HAS_TRANS |
2448141cc406Sopenharmony_ci       MI_SRC_FEED_SUPP | MI_SRC_HAS_FEED)) { /* ZZZZZZZZZZZ */
2449141cc406Sopenharmony_ci    if ((status = accessory(s)) != SANE_STATUS_GOOD) return status;
2450141cc406Sopenharmony_ci  }
2451141cc406Sopenharmony_ci  if ((status = mode_select(s)) != SANE_STATUS_GOOD) return status;
2452141cc406Sopenharmony_ci  /* why would we even try if this were not true?... */
2453141cc406Sopenharmony_ci  /*if (s->dev->info.extra_cap & MI_EXCAP_DIS_RECAL) */
2454141cc406Sopenharmony_ci  {
2455141cc406Sopenharmony_ci    SANE_Bool allow_calibrate = s->allow_calibrate;
2456141cc406Sopenharmony_ci    s->allow_calibrate = SANE_TRUE;
2457141cc406Sopenharmony_ci    status = mode_select_1(s);
2458141cc406Sopenharmony_ci    s->allow_calibrate = allow_calibrate;
2459141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) return status;
2460141cc406Sopenharmony_ci  }
2461141cc406Sopenharmony_ci
2462141cc406Sopenharmony_ci  if ((status = wait_ready(s)) != SANE_STATUS_GOOD) return status;
2463141cc406Sopenharmony_ci  if ((status = start_scan(s))     != SANE_STATUS_GOOD) return status;
2464141cc406Sopenharmony_ci  if ((statusA = get_scan_status(s, &busy,
2465141cc406Sopenharmony_ci				&linewidth, &lines)) != SANE_STATUS_GOOD) {
2466141cc406Sopenharmony_ci    DBG(10, "do_precalibrate:  get_scan_status fails\n");
2467141cc406Sopenharmony_ci  }
2468141cc406Sopenharmony_ci  if ((status = stop_scan(s)) != SANE_STATUS_GOOD) return status;
2469141cc406Sopenharmony_ci  if ((status = wait_ready(s)) != SANE_STATUS_GOOD) return status;
2470141cc406Sopenharmony_ci  DBG(10, "do_precalibrate done.\n");
2471141cc406Sopenharmony_ci  if (statusA != SANE_STATUS_GOOD)
2472141cc406Sopenharmony_ci    return statusA;
2473141cc406Sopenharmony_ci  else
2474141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
2475141cc406Sopenharmony_ci}
2476141cc406Sopenharmony_ci
2477141cc406Sopenharmony_ci
2478141cc406Sopenharmony_ci/********************************************************************/
2479141cc406Sopenharmony_ci/* Calibrate scanner, if necessary; record results               */
2480141cc406Sopenharmony_ci/********************************************************************/
2481141cc406Sopenharmony_cistatic SANE_Status finagle_precal(SANE_Handle handle)
2482141cc406Sopenharmony_ci{
2483141cc406Sopenharmony_ci  Microtek_Scanner *s = handle;
2484141cc406Sopenharmony_ci  SANE_Status status;
2485141cc406Sopenharmony_ci  int match;
2486141cc406Sopenharmony_ci
2487141cc406Sopenharmony_ci  /* try to check if scanner has been reset  */
2488141cc406Sopenharmony_ci  /* if so, calibrate it
2489141cc406Sopenharmony_ci     (either for real, or via a fake scan, with calibration */
2490141cc406Sopenharmony_ci  /* (but only bother if you *could* disable calibration) */
2491141cc406Sopenharmony_ci  DBG(23, "finagle_precal...\n");
2492141cc406Sopenharmony_ci  if ((s->do_clever_precal) || (s->do_real_calib)) {
2493141cc406Sopenharmony_ci    if ((status = compare_mode_sense(s, &match)) != SANE_STATUS_GOOD)
2494141cc406Sopenharmony_ci      return status;
2495141cc406Sopenharmony_ci    if (((s->do_real_calib) && (!s->calib_once)) || /* user want recal */
2496141cc406Sopenharmony_ci	(!match) ||                             /* or, possible reset  */
2497141cc406Sopenharmony_ci	((s->mode == MS_MODE_COLOR) &&          /* or, other weirdness */
2498141cc406Sopenharmony_ci	 (s->precal_record < MS_PRECAL_COLOR)) ||
2499141cc406Sopenharmony_ci	((s->mode == MS_MODE_COLOR) &&
2500141cc406Sopenharmony_ci	 (s->expandedresolution) &&
2501141cc406Sopenharmony_ci	 (s->precal_record < MS_PRECAL_EXP_COLOR))) {
2502141cc406Sopenharmony_ci      DBG(23, "finagle_precal:  must precalibrate!\n");
2503141cc406Sopenharmony_ci      s->precal_record = MS_PRECAL_NONE;
2504141cc406Sopenharmony_ci      if (s->do_real_calib) {    /* do a real calibration if allowed */
2505141cc406Sopenharmony_ci	if ((status = do_real_calibrate(s)) != SANE_STATUS_GOOD)
2506141cc406Sopenharmony_ci	  return status;
2507141cc406Sopenharmony_ci      } else if (s->do_clever_precal) {/* otherwise do the fake-scan version */
2508141cc406Sopenharmony_ci	if ((status = do_precalibrate(s)) != SANE_STATUS_GOOD)
2509141cc406Sopenharmony_ci	  return status;
2510141cc406Sopenharmony_ci      }
2511141cc406Sopenharmony_ci      if (s->mode == MS_MODE_COLOR) {
2512141cc406Sopenharmony_ci	if (s->expandedresolution)
2513141cc406Sopenharmony_ci	  s->precal_record = MS_PRECAL_EXP_COLOR;
2514141cc406Sopenharmony_ci	else
2515141cc406Sopenharmony_ci	  s->precal_record = MS_PRECAL_COLOR;
2516141cc406Sopenharmony_ci      } else
2517141cc406Sopenharmony_ci	s->precal_record = MS_PRECAL_GRAY;
2518141cc406Sopenharmony_ci    } else
2519141cc406Sopenharmony_ci      DBG(23, "finagle_precal:  no precalibrate necessary.\n");
2520141cc406Sopenharmony_ci  }
2521141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2522141cc406Sopenharmony_ci}
2523141cc406Sopenharmony_ci
2524141cc406Sopenharmony_ci
2525141cc406Sopenharmony_ci
2526141cc406Sopenharmony_ci/********************************************************************/
2527141cc406Sopenharmony_ci/* Set pass-dependent parameters (for 3-pass color scans)           */
2528141cc406Sopenharmony_ci/********************************************************************/
2529141cc406Sopenharmony_cistatic void
2530141cc406Sopenharmony_ciset_pass_parameters (SANE_Handle handle)
2531141cc406Sopenharmony_ci{
2532141cc406Sopenharmony_ci  Microtek_Scanner *s = handle;
2533141cc406Sopenharmony_ci
2534141cc406Sopenharmony_ci  if (s->threepasscolor) {
2535141cc406Sopenharmony_ci    s->this_pass += 1;
2536141cc406Sopenharmony_ci    DBG(23, "set_pass_parameters:  three-pass, on %d\n", s->this_pass);
2537141cc406Sopenharmony_ci    switch (s->this_pass) {
2538141cc406Sopenharmony_ci    case 1:
2539141cc406Sopenharmony_ci      s->filter = MS_FILT_RED;
2540141cc406Sopenharmony_ci      s->params.format = SANE_FRAME_RED;
2541141cc406Sopenharmony_ci      s->params.last_frame = SANE_FALSE;
2542141cc406Sopenharmony_ci      break;
2543141cc406Sopenharmony_ci    case 2:
2544141cc406Sopenharmony_ci      s->filter = MS_FILT_GREEN;
2545141cc406Sopenharmony_ci      s->params.format = SANE_FRAME_GREEN;
2546141cc406Sopenharmony_ci      s->params.last_frame = SANE_FALSE;
2547141cc406Sopenharmony_ci      break;
2548141cc406Sopenharmony_ci    case 3:
2549141cc406Sopenharmony_ci      s->filter = MS_FILT_BLUE;
2550141cc406Sopenharmony_ci      s->params.format = SANE_FRAME_BLUE;
2551141cc406Sopenharmony_ci      s->params.last_frame = SANE_TRUE;
2552141cc406Sopenharmony_ci      break;
2553141cc406Sopenharmony_ci    default:
2554141cc406Sopenharmony_ci      s->filter = MS_FILT_CLEAR;
2555141cc406Sopenharmony_ci      DBG(23, "set_pass_parameters:  What?!? pass %d = filter?\n",
2556141cc406Sopenharmony_ci	  s->this_pass);
2557141cc406Sopenharmony_ci      break;
2558141cc406Sopenharmony_ci    }
2559141cc406Sopenharmony_ci  } else
2560141cc406Sopenharmony_ci    s->this_pass = 0;
2561141cc406Sopenharmony_ci}
2562141cc406Sopenharmony_ci
2563141cc406Sopenharmony_ci
2564141cc406Sopenharmony_ci
2565141cc406Sopenharmony_ci/********************************************************************/
2566141cc406Sopenharmony_ci/********************************************************************/
2567141cc406Sopenharmony_ci/***** Packing functions                                        *****/
2568141cc406Sopenharmony_ci/*****    ...process raw scanner bytes, and shove into          *****/
2569141cc406Sopenharmony_ci/*****        the ring buffer                                   *****/
2570141cc406Sopenharmony_ci/********************************************************************/
2571141cc406Sopenharmony_ci/********************************************************************/
2572141cc406Sopenharmony_ci
2573141cc406Sopenharmony_ci
2574141cc406Sopenharmony_ci/********************************************************************/
2575141cc406Sopenharmony_ci/* Process flat (byte-by-byte) data                                 */
2576141cc406Sopenharmony_ci/********************************************************************/
2577141cc406Sopenharmony_cistatic SANE_Status pack_flat_data(Microtek_Scanner *s, size_t nlines)
2578141cc406Sopenharmony_ci{
2579141cc406Sopenharmony_ci  SANE_Status status;
2580141cc406Sopenharmony_ci  ring_buffer *rb = s->rb;
2581141cc406Sopenharmony_ci  size_t nbytes = nlines * rb->bpl;
2582141cc406Sopenharmony_ci
2583141cc406Sopenharmony_ci  size_t start = (rb->head_complete + rb->complete_count) % rb->size;
2584141cc406Sopenharmony_ci  size_t max_xfer =
2585141cc406Sopenharmony_ci    (start < rb->head_complete) ?
2586141cc406Sopenharmony_ci    (rb->head_complete - start) :
2587141cc406Sopenharmony_ci    (rb->size - start + rb->head_complete);
2588141cc406Sopenharmony_ci  size_t length = MIN(nbytes, max_xfer);
2589141cc406Sopenharmony_ci
2590141cc406Sopenharmony_ci  if (nbytes > max_xfer) {
2591141cc406Sopenharmony_ci    DBG(23, "pack_flat: must expand ring, %lu + %lu\n",
2592141cc406Sopenharmony_ci	(u_long)rb->size, (u_long)(nbytes - max_xfer));
2593141cc406Sopenharmony_ci    status = ring_expand(rb, (nbytes - max_xfer));
2594141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) return status;
2595141cc406Sopenharmony_ci  }
2596141cc406Sopenharmony_ci
2597141cc406Sopenharmony_ci  if (s->doexpansion) {
2598141cc406Sopenharmony_ci    unsigned int line, bit;
2599141cc406Sopenharmony_ci    SANE_Byte *sb, *db, byte;
2600141cc406Sopenharmony_ci
2601141cc406Sopenharmony_ci    size_t pos;
2602141cc406Sopenharmony_ci
2603141cc406Sopenharmony_ci    sb = s->scsi_buffer;
2604141cc406Sopenharmony_ci    db = rb->base;
2605141cc406Sopenharmony_ci    pos = start;
2606141cc406Sopenharmony_ci
2607141cc406Sopenharmony_ci    if (!(s->multibit)) {
2608141cc406Sopenharmony_ci      for (line=0; line<nlines; line++) {
2609141cc406Sopenharmony_ci	size_t i;
2610141cc406Sopenharmony_ci	double x1, x2, n1, n2;
2611141cc406Sopenharmony_ci	for (i = 0, x1 = 0.0, x2 = s->exp_aspect, n1 = 0.0, n2 = floor(x2);
2612141cc406Sopenharmony_ci	     i < rb->bpl;
2613141cc406Sopenharmony_ci	     i++) {
2614141cc406Sopenharmony_ci	  byte = 0;
2615141cc406Sopenharmony_ci	  for (bit=0;
2616141cc406Sopenharmony_ci	       bit < 8;
2617141cc406Sopenharmony_ci	       bit++, x1 = x2, n1 = n2, x2 += s->exp_aspect, n2 = floor(x2)) {
2618141cc406Sopenharmony_ci	    /* #define getbit(byte, index) (((byte)>>(index))&1) */
2619141cc406Sopenharmony_ci	    byte |=
2620141cc406Sopenharmony_ci	      ((
2621141cc406Sopenharmony_ci		(x2 == n2) ?
2622141cc406Sopenharmony_ci		(((sb[(int)n1 / 8])>>(7 - ((int)n1) % 8))&1) :
2623141cc406Sopenharmony_ci		(((double)(((sb[(int)n1/8])>>(7-(int)n1%8))&1) * (n2 - x1) +
2624141cc406Sopenharmony_ci		  (double)(((sb[(int)n2/8])>>(7-(int)n2%8))&1) * (x2 - n2)
2625141cc406Sopenharmony_ci		  ) / s->exp_aspect)
2626141cc406Sopenharmony_ci		) > 0.5) << (7 - bit);
2627141cc406Sopenharmony_ci	  }
2628141cc406Sopenharmony_ci	  db[pos] = byte;
2629141cc406Sopenharmony_ci	  if (++pos >= rb->size) pos = 0;
2630141cc406Sopenharmony_ci	}
2631141cc406Sopenharmony_ci	sb += s->pixel_bpl;
2632141cc406Sopenharmony_ci      }
2633141cc406Sopenharmony_ci    } else { /* multibit scan (8 is assumed!) */
2634141cc406Sopenharmony_ci      for (line=0; line<nlines; line++) {
2635141cc406Sopenharmony_ci	double x1, x2, n1, n2;
2636141cc406Sopenharmony_ci	int i;
2637141cc406Sopenharmony_ci	for (i = 0, x1 = 0.0, x2 = s->exp_aspect, n1 = 0.0, n2 = floor(x2);
2638141cc406Sopenharmony_ci	     i < s->dest_ppl;
2639141cc406Sopenharmony_ci	     i++, x1 = x2, n1 = n2, x2 += s->exp_aspect, n2 = floor(x2)) {
2640141cc406Sopenharmony_ci	  db[pos] =
2641141cc406Sopenharmony_ci	    (x2 == n2) ?
2642141cc406Sopenharmony_ci	    sb[(int)n1] :
2643141cc406Sopenharmony_ci	    (int)(((double)sb[(int)n1] * (n2 - x1) +
2644141cc406Sopenharmony_ci		   (double)sb[(int)n2] * (x2 - n2)) / s->exp_aspect);
2645141cc406Sopenharmony_ci	  if (++pos >= rb->size) pos = 0;
2646141cc406Sopenharmony_ci	}
2647141cc406Sopenharmony_ci	sb += s->pixel_bpl;
2648141cc406Sopenharmony_ci      }
2649141cc406Sopenharmony_ci    }
2650141cc406Sopenharmony_ci  } else {
2651141cc406Sopenharmony_ci    /* adjust for rollover!!! */
2652141cc406Sopenharmony_ci    if ((start + length) < rb->size) {
2653141cc406Sopenharmony_ci      memcpy(rb->base + start, s->scsi_buffer, length);
2654141cc406Sopenharmony_ci    } else {
2655141cc406Sopenharmony_ci      size_t chunk1 = rb->size - start;
2656141cc406Sopenharmony_ci      size_t chunk2 = length - chunk1;
2657141cc406Sopenharmony_ci      memcpy(rb->base + start, s->scsi_buffer, chunk1);
2658141cc406Sopenharmony_ci      memcpy(rb->base, s->scsi_buffer + chunk1, chunk2);
2659141cc406Sopenharmony_ci    }
2660141cc406Sopenharmony_ci  }
2661141cc406Sopenharmony_ci  rb->complete_count += length;
2662141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2663141cc406Sopenharmony_ci}
2664141cc406Sopenharmony_ci
2665141cc406Sopenharmony_ci
2666141cc406Sopenharmony_ci/********************************************************************/
2667141cc406Sopenharmony_ci/* Process sequential R-G-B scan lines (who uses this??? )          */
2668141cc406Sopenharmony_ci/********************************************************************/
2669141cc406Sopenharmony_cistatic SANE_Status
2670141cc406Sopenharmony_cipack_seqrgb_data (Microtek_Scanner *s, size_t nlines)
2671141cc406Sopenharmony_ci{
2672141cc406Sopenharmony_ci  ring_buffer *rb = s->rb;
2673141cc406Sopenharmony_ci  unsigned int seg;
2674141cc406Sopenharmony_ci  SANE_Byte *db = rb->base;
2675141cc406Sopenharmony_ci  SANE_Byte *sb = s->scsi_buffer;
2676141cc406Sopenharmony_ci  size_t completed;
2677141cc406Sopenharmony_ci  size_t spot;
2678141cc406Sopenharmony_ci  SANE_Byte id;
2679141cc406Sopenharmony_ci
2680141cc406Sopenharmony_ci  {
2681141cc406Sopenharmony_ci    size_t ar, ag, ab; /* allowed additions */
2682141cc406Sopenharmony_ci    size_t dr, dg, db; /* additions which will occur */
2683141cc406Sopenharmony_ci    SANE_Status status;
2684141cc406Sopenharmony_ci
2685141cc406Sopenharmony_ci    dr = dg = db = nlines * rb->bpl;
2686141cc406Sopenharmony_ci    ar = rb->size - (rb->complete_count + rb->red_extra * 3);
2687141cc406Sopenharmony_ci    ag = rb->size - (rb->complete_count + rb->green_extra * 3);
2688141cc406Sopenharmony_ci    ab = rb->size - (rb->complete_count + rb->blue_extra * 3);
2689141cc406Sopenharmony_ci    DBG(23, "pack_seq:  dr/ar: %lu/%lu  dg/ag: %lu/%lu  db/ab: %lu/%lu\n",
2690141cc406Sopenharmony_ci	(u_long)dr, (u_long)ar,
2691141cc406Sopenharmony_ci	(u_long)dg, (u_long)ag,
2692141cc406Sopenharmony_ci	(u_long)db, (u_long)ab);
2693141cc406Sopenharmony_ci    if ((dr > ar) ||
2694141cc406Sopenharmony_ci	(dg > ag) ||
2695141cc406Sopenharmony_ci	(db > ab)) {
2696141cc406Sopenharmony_ci      size_t increase = 0;
2697141cc406Sopenharmony_ci      if (dr > ar) increase = (dr - ar);
2698141cc406Sopenharmony_ci      if (dg > ag) increase = MAX(increase, (dg - ag));
2699141cc406Sopenharmony_ci      if (db > ab) increase = MAX(increase, (db - ab));
2700141cc406Sopenharmony_ci      DBG(23, "pack_seq: must expand ring, %lu + %lu\n",
2701141cc406Sopenharmony_ci	  (u_long)rb->size, (u_long)increase);
2702141cc406Sopenharmony_ci      status = ring_expand(rb, increase);
2703141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD) return status;
2704141cc406Sopenharmony_ci    }
2705141cc406Sopenharmony_ci  }
2706141cc406Sopenharmony_ci
2707141cc406Sopenharmony_ci  for (seg = 0, id = 0; seg < nlines * 3; seg++, id = (id+1)%3) {
2708141cc406Sopenharmony_ci    switch (id) {
2709141cc406Sopenharmony_ci    case 0: spot = rb->tail_red;  break;
2710141cc406Sopenharmony_ci    case 1: spot = rb->tail_green;  break;
2711141cc406Sopenharmony_ci    case 2: spot = rb->tail_blue;  break;
2712141cc406Sopenharmony_ci    default:
2713141cc406Sopenharmony_ci      DBG(18, "pack_seq:  missing scanline RGB header!\n");
2714141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2715141cc406Sopenharmony_ci    }
2716141cc406Sopenharmony_ci
2717141cc406Sopenharmony_ci    if (s->doexpansion) {
2718141cc406Sopenharmony_ci      int i;
2719141cc406Sopenharmony_ci      double x1, x2, n1, n2;
2720141cc406Sopenharmony_ci      for (i = 0, x1 = 0.0, x2 = s->exp_aspect, n1 = 0.0, n2 = floor(x2);
2721141cc406Sopenharmony_ci	   i < s->dest_ppl;
2722141cc406Sopenharmony_ci	   i++, x1 = x2, n1 = n2, x2 += s->exp_aspect, n2 = floor(x2)) {
2723141cc406Sopenharmony_ci	db[spot] =
2724141cc406Sopenharmony_ci	  (x2 == n2) ?
2725141cc406Sopenharmony_ci	  sb[(int)n1] :
2726141cc406Sopenharmony_ci	  (int)(((double)sb[(int)n1] * (n2 - x1) +
2727141cc406Sopenharmony_ci		 (double)sb[(int)n2] * (x2 - n2)) / s->exp_aspect);
2728141cc406Sopenharmony_ci	if ((spot += 3) >= rb->size) spot -= rb->size;
2729141cc406Sopenharmony_ci      }
2730141cc406Sopenharmony_ci      sb += s->ppl;
2731141cc406Sopenharmony_ci    } else {
2732141cc406Sopenharmony_ci      size_t i;
2733141cc406Sopenharmony_ci      for (i=0; i < rb->ppl; i++) {
2734141cc406Sopenharmony_ci	db[spot] = *sb;
2735141cc406Sopenharmony_ci	sb++;
2736141cc406Sopenharmony_ci	if ((spot += 3) >= rb->size) spot -= rb->size;
2737141cc406Sopenharmony_ci      }
2738141cc406Sopenharmony_ci    }
2739141cc406Sopenharmony_ci
2740141cc406Sopenharmony_ci    switch (id) {
2741141cc406Sopenharmony_ci    case 0: rb->tail_red   = spot; rb->red_extra   += rb->ppl; break;
2742141cc406Sopenharmony_ci    case 1: rb->tail_green = spot; rb->green_extra += rb->ppl; break;
2743141cc406Sopenharmony_ci    case 2: rb->tail_blue  = spot; rb->blue_extra  += rb->ppl; break;
2744141cc406Sopenharmony_ci    }
2745141cc406Sopenharmony_ci  }
2746141cc406Sopenharmony_ci
2747141cc406Sopenharmony_ci  completed = MIN(rb->red_extra, MIN(rb->green_extra, rb->blue_extra));
2748141cc406Sopenharmony_ci  rb->complete_count += completed * 3;  /* 3 complete bytes per pixel! */
2749141cc406Sopenharmony_ci  rb->red_extra   -= completed;
2750141cc406Sopenharmony_ci  rb->green_extra -= completed;
2751141cc406Sopenharmony_ci  rb->blue_extra  -= completed;
2752141cc406Sopenharmony_ci
2753141cc406Sopenharmony_ci  DBG(18, "pack_seq:  extra r: %lu  g: %lu  b: %lu\n",
2754141cc406Sopenharmony_ci      (u_long)rb->red_extra,
2755141cc406Sopenharmony_ci      (u_long)rb->green_extra,
2756141cc406Sopenharmony_ci      (u_long)rb->blue_extra);
2757141cc406Sopenharmony_ci  DBG(18, "pack_seq:  completed: %lu  complete: %lu\n",
2758141cc406Sopenharmony_ci      (u_long)completed, (u_long)rb->complete_count);
2759141cc406Sopenharmony_ci
2760141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2761141cc406Sopenharmony_ci}
2762141cc406Sopenharmony_ci
2763141cc406Sopenharmony_ci
2764141cc406Sopenharmony_ci/********************************************************************/
2765141cc406Sopenharmony_ci/* Process non-sequential R,G, and B scan-lines                     */
2766141cc406Sopenharmony_ci/********************************************************************/
2767141cc406Sopenharmony_cistatic SANE_Status
2768141cc406Sopenharmony_cipack_goofyrgb_data(Microtek_Scanner *s, size_t nlines)
2769141cc406Sopenharmony_ci{
2770141cc406Sopenharmony_ci  ring_buffer *rb = s->rb;
2771141cc406Sopenharmony_ci  unsigned int seg; /* , i;*/
2772141cc406Sopenharmony_ci  SANE_Byte *db;
2773141cc406Sopenharmony_ci  SANE_Byte *sb = s->scsi_buffer;
2774141cc406Sopenharmony_ci  size_t completed;
2775141cc406Sopenharmony_ci  size_t spot;
2776141cc406Sopenharmony_ci  SANE_Byte id;
2777141cc406Sopenharmony_ci
2778141cc406Sopenharmony_ci  /* prescan to decide if ring should be expanded */
2779141cc406Sopenharmony_ci  {
2780141cc406Sopenharmony_ci    size_t ar, ag, ab; /* allowed additions */
2781141cc406Sopenharmony_ci    size_t dr, dg, db; /* additions which will occur */
2782141cc406Sopenharmony_ci    SANE_Status status;
2783141cc406Sopenharmony_ci    SANE_Byte *pt;
2784141cc406Sopenharmony_ci
2785141cc406Sopenharmony_ci    for (dr = dg = db = 0, seg = 0, pt = s->scsi_buffer + 1;
2786141cc406Sopenharmony_ci	 seg < nlines * 3;
2787141cc406Sopenharmony_ci	 seg++, pt += s->ppl + 2) {
2788141cc406Sopenharmony_ci      switch (*pt) {
2789141cc406Sopenharmony_ci      case 'R': dr += rb->bpl;  break;
2790141cc406Sopenharmony_ci      case 'G': dg += rb->bpl;  break;
2791141cc406Sopenharmony_ci      case 'B': db += rb->bpl;  break;
2792141cc406Sopenharmony_ci      }
2793141cc406Sopenharmony_ci    }
2794141cc406Sopenharmony_ci    ar = rb->size - (rb->complete_count + rb->red_extra * 3);
2795141cc406Sopenharmony_ci    ag = rb->size - (rb->complete_count + rb->green_extra * 3);
2796141cc406Sopenharmony_ci    ab = rb->size - (rb->complete_count + rb->blue_extra * 3);
2797141cc406Sopenharmony_ci    DBG(23, "pack_goofy:  dr/ar: %lu/%lu  dg/ag: %lu/%lu  db/ab: %lu/%lu\n",
2798141cc406Sopenharmony_ci	(u_long)dr, (u_long)ar,
2799141cc406Sopenharmony_ci	(u_long)dg, (u_long)ag,
2800141cc406Sopenharmony_ci	(u_long)db, (u_long)ab);
2801141cc406Sopenharmony_ci    /* >, or >= ???????? */
2802141cc406Sopenharmony_ci    if ((dr > ar) ||
2803141cc406Sopenharmony_ci	(dg > ag) ||
2804141cc406Sopenharmony_ci	(db > ab)) {
2805141cc406Sopenharmony_ci      size_t increase = 0;
2806141cc406Sopenharmony_ci      if (dr > ar) increase = (dr - ar);
2807141cc406Sopenharmony_ci      if (dg > ag) increase = MAX(increase, (dg - ag));
2808141cc406Sopenharmony_ci      if (db > ab) increase = MAX(increase, (db - ab));
2809141cc406Sopenharmony_ci      DBG(23, "pack_goofy: must expand ring, %lu + %lu\n",
2810141cc406Sopenharmony_ci	  (u_long)rb->size, (u_long)increase);
2811141cc406Sopenharmony_ci      status = ring_expand(rb, increase);
2812141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD) return status;
2813141cc406Sopenharmony_ci    }
2814141cc406Sopenharmony_ci  }
2815141cc406Sopenharmony_ci
2816141cc406Sopenharmony_ci  db = rb->base;
2817141cc406Sopenharmony_ci  for (seg = 0; seg < nlines * 3; seg++) {
2818141cc406Sopenharmony_ci    sb++; /* skip first byte in line (two byte header) */
2819141cc406Sopenharmony_ci    id = *sb;
2820141cc406Sopenharmony_ci    switch (id) {
2821141cc406Sopenharmony_ci    case 'R': spot = rb->tail_red;  break;
2822141cc406Sopenharmony_ci    case 'G': spot = rb->tail_green;  break;
2823141cc406Sopenharmony_ci    case 'B': spot = rb->tail_blue;  break;
2824141cc406Sopenharmony_ci    default:
2825141cc406Sopenharmony_ci      DBG(18, "pack_goofy:  missing scanline RGB header!\n");
2826141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2827141cc406Sopenharmony_ci    }
2828141cc406Sopenharmony_ci    sb++; /* skip the other header byte */
2829141cc406Sopenharmony_ci
2830141cc406Sopenharmony_ci    if (s->doexpansion) {
2831141cc406Sopenharmony_ci      int i;
2832141cc406Sopenharmony_ci      double x1, x2, n1, n2;
2833141cc406Sopenharmony_ci      for (i = 0, x1 = 0.0, x2 = s->exp_aspect, n1 = 0.0, n2 = floor(x2);
2834141cc406Sopenharmony_ci	   i < s->dest_ppl;
2835141cc406Sopenharmony_ci	   i++, x1 = x2, n1 = n2, x2 += s->exp_aspect, n2 = floor(x2)) {
2836141cc406Sopenharmony_ci	db[spot] =
2837141cc406Sopenharmony_ci	  (x2 == n2) ?
2838141cc406Sopenharmony_ci	  sb[(int)n1] :
2839141cc406Sopenharmony_ci	  (int)(((double)sb[(int)n1] * (n2 - x1) +
2840141cc406Sopenharmony_ci		 (double)sb[(int)n2] * (x2 - n2)) / s->exp_aspect);
2841141cc406Sopenharmony_ci	if ((spot += 3) >= rb->size) spot -= rb->size;
2842141cc406Sopenharmony_ci      }
2843141cc406Sopenharmony_ci      sb += s->ppl;
2844141cc406Sopenharmony_ci    } else {
2845141cc406Sopenharmony_ci      unsigned int i;
2846141cc406Sopenharmony_ci      for (i=0; i < rb->ppl; i++) {
2847141cc406Sopenharmony_ci	db[spot] = *sb;
2848141cc406Sopenharmony_ci	sb++;
2849141cc406Sopenharmony_ci	if ((spot += 3) >= rb->size) spot -= rb->size;
2850141cc406Sopenharmony_ci      }
2851141cc406Sopenharmony_ci    }
2852141cc406Sopenharmony_ci    switch (id) {
2853141cc406Sopenharmony_ci    case 'R': rb->tail_red   = spot; rb->red_extra   += rb->ppl; break;
2854141cc406Sopenharmony_ci    case 'G': rb->tail_green = spot; rb->green_extra += rb->ppl; break;
2855141cc406Sopenharmony_ci    case 'B': rb->tail_blue  = spot; rb->blue_extra  += rb->ppl; break;
2856141cc406Sopenharmony_ci    }
2857141cc406Sopenharmony_ci  }
2858141cc406Sopenharmony_ci
2859141cc406Sopenharmony_ci  completed = MIN(rb->red_extra, MIN(rb->green_extra, rb->blue_extra));
2860141cc406Sopenharmony_ci  rb->complete_count += completed * 3;  /* 3 complete bytes per pixel! */
2861141cc406Sopenharmony_ci  rb->red_extra   -= completed;
2862141cc406Sopenharmony_ci  rb->green_extra -= completed;
2863141cc406Sopenharmony_ci  rb->blue_extra  -= completed;
2864141cc406Sopenharmony_ci
2865141cc406Sopenharmony_ci  DBG(18, "pack_goofy:  extra r: %lu  g: %lu  b: %lu\n",
2866141cc406Sopenharmony_ci      (u_long)rb->red_extra,
2867141cc406Sopenharmony_ci      (u_long)rb->green_extra,
2868141cc406Sopenharmony_ci      (u_long)rb->blue_extra);
2869141cc406Sopenharmony_ci  DBG(18, "pack_goofy:  completed: %lu  complete: %lu\n",
2870141cc406Sopenharmony_ci      (u_long)completed, (u_long)rb->complete_count);
2871141cc406Sopenharmony_ci
2872141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2873141cc406Sopenharmony_ci}
2874141cc406Sopenharmony_ci
2875141cc406Sopenharmony_ci
2876141cc406Sopenharmony_ci
2877141cc406Sopenharmony_ci/********************************************************************/
2878141cc406Sopenharmony_ci/* Process R1R2-G1G2-B1B2 double pixels (AGFA StudioStar)           */
2879141cc406Sopenharmony_ci/********************************************************************/
2880141cc406Sopenharmony_ci
2881141cc406Sopenharmony_cistatic SANE_Status
2882141cc406Sopenharmony_cipack_seq2r2g2b_data(Microtek_Scanner *s, size_t nlines)
2883141cc406Sopenharmony_ci{
2884141cc406Sopenharmony_ci  SANE_Status status;
2885141cc406Sopenharmony_ci  ring_buffer *rb = s->rb;
2886141cc406Sopenharmony_ci  size_t nbytes = nlines * rb->bpl;
2887141cc406Sopenharmony_ci
2888141cc406Sopenharmony_ci  size_t start = (rb->head_complete + rb->complete_count) % rb->size;
2889141cc406Sopenharmony_ci  size_t max_xfer =
2890141cc406Sopenharmony_ci    (start < rb->head_complete) ?
2891141cc406Sopenharmony_ci    (rb->head_complete - start) :
2892141cc406Sopenharmony_ci    (rb->size - start + rb->head_complete);
2893141cc406Sopenharmony_ci  size_t length = MIN(nbytes, max_xfer);
2894141cc406Sopenharmony_ci
2895141cc406Sopenharmony_ci  if (nbytes > max_xfer) {
2896141cc406Sopenharmony_ci    DBG(23, "pack_2r2g2b: must expand ring, %lu + %lu\n",
2897141cc406Sopenharmony_ci	(u_long)rb->size, (u_long)(nbytes - max_xfer));
2898141cc406Sopenharmony_ci    status = ring_expand(rb, (nbytes - max_xfer));
2899141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) return status;
2900141cc406Sopenharmony_ci  }
2901141cc406Sopenharmony_ci  {
2902141cc406Sopenharmony_ci    unsigned int line;
2903141cc406Sopenharmony_ci    int p;
2904141cc406Sopenharmony_ci    size_t pos = start;
2905141cc406Sopenharmony_ci    SANE_Byte *sb = s->scsi_buffer;
2906141cc406Sopenharmony_ci    SANE_Byte *db = rb->base;
2907141cc406Sopenharmony_ci
2908141cc406Sopenharmony_ci    for (line = 0; line < nlines; line++) {
2909141cc406Sopenharmony_ci      for (p = 0; p < s->dest_ppl; p += 2){
2910141cc406Sopenharmony_ci	/* first pixel */
2911141cc406Sopenharmony_ci	db[pos] = sb[0];
2912141cc406Sopenharmony_ci	if (++pos >= rb->size) pos = 0; /* watch out for ringbuff end? */
2913141cc406Sopenharmony_ci	db[pos] = sb[2];
2914141cc406Sopenharmony_ci	if (++pos >= rb->size) pos = 0;
2915141cc406Sopenharmony_ci	db[pos] = sb[4];
2916141cc406Sopenharmony_ci	if (++pos >= rb->size) pos = 0;
2917141cc406Sopenharmony_ci	/* second pixel */
2918141cc406Sopenharmony_ci	db[pos] = sb[1];
2919141cc406Sopenharmony_ci	if (++pos >= rb->size) pos = 0;
2920141cc406Sopenharmony_ci	db[pos] = sb[3];
2921141cc406Sopenharmony_ci	if (++pos >= rb->size) pos = 0;
2922141cc406Sopenharmony_ci	db[pos] = sb[5];
2923141cc406Sopenharmony_ci	if (++pos >= rb->size) pos = 0;
2924141cc406Sopenharmony_ci	sb += 6;
2925141cc406Sopenharmony_ci      }
2926141cc406Sopenharmony_ci    }
2927141cc406Sopenharmony_ci  }
2928141cc406Sopenharmony_ci  rb->complete_count += length;
2929141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2930141cc406Sopenharmony_ci}
2931141cc406Sopenharmony_ci
2932141cc406Sopenharmony_ci
2933141cc406Sopenharmony_ci
2934141cc406Sopenharmony_ci/********************************************************************/
2935141cc406Sopenharmony_ci/********************************************************************/
2936141cc406Sopenharmony_ci/***** the basic scanning chunks for sane_read()                *****/
2937141cc406Sopenharmony_ci/********************************************************************/
2938141cc406Sopenharmony_ci/********************************************************************/
2939141cc406Sopenharmony_ci
2940141cc406Sopenharmony_ci
2941141cc406Sopenharmony_ci/********************************************************************/
2942141cc406Sopenharmony_ci/* Request bytes from scanner (and put in scsi_buffer)              */
2943141cc406Sopenharmony_ci/********************************************************************/
2944141cc406Sopenharmony_cistatic SANE_Status
2945141cc406Sopenharmony_ciread_from_scanner (Microtek_Scanner *s, int *nlines)
2946141cc406Sopenharmony_ci{
2947141cc406Sopenharmony_ci  SANE_Status status;
2948141cc406Sopenharmony_ci  SANE_Int busy, linewidth, remaining;
2949141cc406Sopenharmony_ci  size_t buffsize;
2950141cc406Sopenharmony_ci
2951141cc406Sopenharmony_ci  DBG(23, "read_from_scanner...\n");
2952141cc406Sopenharmony_ci  if (s->unscanned_lines > 0) {
2953141cc406Sopenharmony_ci    status = get_scan_status(s, &busy, &linewidth, &remaining);
2954141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) {
2955141cc406Sopenharmony_ci      DBG(18, "read_from_scanner:  bad get_scan_status!\n");
2956141cc406Sopenharmony_ci      return status;
2957141cc406Sopenharmony_ci    }
2958141cc406Sopenharmony_ci    DBG(18, "read_from_scanner: gss busy, linewidth, remaining:  %d, %d, %d\n",
2959141cc406Sopenharmony_ci	busy, linewidth, remaining);
2960141cc406Sopenharmony_ci  } else {
2961141cc406Sopenharmony_ci    DBG(18, "read_from_scanner: no gss/no unscanned\n");
2962141cc406Sopenharmony_ci    remaining = 0;
2963141cc406Sopenharmony_ci  }
2964141cc406Sopenharmony_ci
2965141cc406Sopenharmony_ci  *nlines = MIN(remaining, s->max_scsi_lines);
2966141cc406Sopenharmony_ci  DBG(18, "sane_read:  max_scsi: %d, rem: %d, nlines: %d\n",
2967141cc406Sopenharmony_ci      s->max_scsi_lines, remaining, *nlines);
2968141cc406Sopenharmony_ci
2969141cc406Sopenharmony_ci  /* grab them bytes! (only if the scanner still has bytes to give...) */
2970141cc406Sopenharmony_ci  if (*nlines > 0) {
2971141cc406Sopenharmony_ci    buffsize = *nlines * (s->pixel_bpl + s->header_bpl);/* == "* linewidth" */
2972141cc406Sopenharmony_ci    status = read_scan_data(s, *nlines, s->scsi_buffer, &buffsize);
2973141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD) {
2974141cc406Sopenharmony_ci      DBG(18, "sane_read:  bad read_scan_data!\n");
2975141cc406Sopenharmony_ci      return status;
2976141cc406Sopenharmony_ci    }
2977141cc406Sopenharmony_ci    s->unscanned_lines -= *nlines;
2978141cc406Sopenharmony_ci    DBG(18, "sane_read:  buffsize: %lu,  unscanned: %d\n",
2979141cc406Sopenharmony_ci        (u_long) buffsize, s->unscanned_lines);
2980141cc406Sopenharmony_ci  }
2981141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2982141cc406Sopenharmony_ci}
2983141cc406Sopenharmony_ci
2984141cc406Sopenharmony_ci
2985141cc406Sopenharmony_ci
2986141cc406Sopenharmony_ci/********************************************************************/
2987141cc406Sopenharmony_ci/* Process scanner bytes, and shove in ring_buffer                  */
2988141cc406Sopenharmony_ci/********************************************************************/
2989141cc406Sopenharmony_cistatic SANE_Status
2990141cc406Sopenharmony_cipack_into_ring(Microtek_Scanner *s, int nlines)
2991141cc406Sopenharmony_ci{
2992141cc406Sopenharmony_ci  SANE_Status status;
2993141cc406Sopenharmony_ci
2994141cc406Sopenharmony_ci  DBG(23, "pack_into_ring...\n");
2995141cc406Sopenharmony_ci  switch (s->line_format) {
2996141cc406Sopenharmony_ci  case MS_LNFMT_FLAT:
2997141cc406Sopenharmony_ci    status = pack_flat_data(s, nlines);  break;
2998141cc406Sopenharmony_ci  case MS_LNFMT_SEQ_RGB:
2999141cc406Sopenharmony_ci    status = pack_seqrgb_data(s, nlines); break;
3000141cc406Sopenharmony_ci  case MS_LNFMT_GOOFY_RGB:
3001141cc406Sopenharmony_ci    status = pack_goofyrgb_data(s, nlines); break;
3002141cc406Sopenharmony_ci  case MS_LNFMT_SEQ_2R2G2B:
3003141cc406Sopenharmony_ci    status = pack_seq2r2g2b_data(s, nlines); break;
3004141cc406Sopenharmony_ci  default:
3005141cc406Sopenharmony_ci    status = SANE_STATUS_JAMMED;
3006141cc406Sopenharmony_ci  }
3007141cc406Sopenharmony_ci  return status;
3008141cc406Sopenharmony_ci}
3009141cc406Sopenharmony_ci
3010141cc406Sopenharmony_ci
3011141cc406Sopenharmony_ci
3012141cc406Sopenharmony_ci/********************************************************************/
3013141cc406Sopenharmony_ci/* Pack processed image bytes into frontend destination buffer      */
3014141cc406Sopenharmony_ci/********************************************************************/
3015141cc406Sopenharmony_cistatic SANE_Int
3016141cc406Sopenharmony_cipack_into_dest(SANE_Byte *dest_buffer, size_t dest_length, ring_buffer *rb)
3017141cc406Sopenharmony_ci{
3018141cc406Sopenharmony_ci  size_t ret_length = MIN(rb->complete_count, dest_length);
3019141cc406Sopenharmony_ci
3020141cc406Sopenharmony_ci  DBG(23, "pack_into_dest...\n");
3021141cc406Sopenharmony_ci  DBG(23, "pack_into_dest:  rl: %lu  sz: %lu  hc: %lu\n",
3022141cc406Sopenharmony_ci      (u_long)ret_length, (u_long)rb->size, (u_long)rb->head_complete);
3023141cc406Sopenharmony_ci  /* adjust for rollover!!! */
3024141cc406Sopenharmony_ci  if ((rb->head_complete + ret_length) < rb->size) {
3025141cc406Sopenharmony_ci    memcpy(dest_buffer, rb->base + rb->head_complete, ret_length);
3026141cc406Sopenharmony_ci    rb->head_complete += ret_length;
3027141cc406Sopenharmony_ci  } else {
3028141cc406Sopenharmony_ci    size_t chunk1  = rb->size - rb->head_complete;
3029141cc406Sopenharmony_ci    size_t chunk2 = ret_length - chunk1;
3030141cc406Sopenharmony_ci    memcpy(dest_buffer, rb->base + rb->head_complete, chunk1);
3031141cc406Sopenharmony_ci    memcpy(dest_buffer + chunk1, rb->base, chunk2);
3032141cc406Sopenharmony_ci    rb->head_complete = chunk2;
3033141cc406Sopenharmony_ci  }
3034141cc406Sopenharmony_ci  rb->complete_count -= ret_length;
3035141cc406Sopenharmony_ci  return ret_length;
3036141cc406Sopenharmony_ci}
3037141cc406Sopenharmony_ci
3038141cc406Sopenharmony_ci
3039141cc406Sopenharmony_ci
3040141cc406Sopenharmony_ci/********************************************************************/
3041141cc406Sopenharmony_ci/********************************************************************/
3042141cc406Sopenharmony_ci/****** "Registered" SANE API Functions *****************************/
3043141cc406Sopenharmony_ci/********************************************************************/
3044141cc406Sopenharmony_ci/********************************************************************/
3045141cc406Sopenharmony_ci
3046141cc406Sopenharmony_ci
3047141cc406Sopenharmony_ci/********************************************************************/
3048141cc406Sopenharmony_ci/* sane_init()                                                      */
3049141cc406Sopenharmony_ci/********************************************************************/
3050141cc406Sopenharmony_ciSANE_Status
3051141cc406Sopenharmony_cisane_init(SANE_Int *version_code, SANE_Auth_Callback authorize)
3052141cc406Sopenharmony_ci{
3053141cc406Sopenharmony_ci  char dev_name[PATH_MAX];
3054141cc406Sopenharmony_ci  size_t len;
3055141cc406Sopenharmony_ci  FILE *fp;
3056141cc406Sopenharmony_ci
3057141cc406Sopenharmony_ci  (void) authorize;
3058141cc406Sopenharmony_ci  DBG_INIT();
3059141cc406Sopenharmony_ci  DBG(1, "sane_init:  MICROTEK says hello! (v%d.%d.%d)\n",
3060141cc406Sopenharmony_ci      MICROTEK_MAJOR, MICROTEK_MINOR, MICROTEK_PATCH);
3061141cc406Sopenharmony_ci  /* return the SANE version we got compiled under */
3062141cc406Sopenharmony_ci  if (version_code)
3063141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
3064141cc406Sopenharmony_ci
3065141cc406Sopenharmony_ci  /* parse config file */
3066141cc406Sopenharmony_ci  fp = sanei_config_open (MICROTEK_CONFIG_FILE);
3067141cc406Sopenharmony_ci  if (!fp) {
3068141cc406Sopenharmony_ci    /* default to /dev/scanner instead of insisting on config file */
3069141cc406Sopenharmony_ci    DBG(1, "sane_init:  missing config file '%s'\n", MICROTEK_CONFIG_FILE);
3070141cc406Sopenharmony_ci    attach_scanner("/dev/scanner", 0);
3071141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
3072141cc406Sopenharmony_ci  }
3073141cc406Sopenharmony_ci  while (sanei_config_read(dev_name, sizeof (dev_name), fp)) {
3074141cc406Sopenharmony_ci    DBG(23, "sane_init:  config-> %s\n", dev_name);
3075141cc406Sopenharmony_ci    if (dev_name[0] == '#') continue;	/* ignore comments */
3076141cc406Sopenharmony_ci    if (!(strncmp("noprecal", dev_name, 8))) {
3077141cc406Sopenharmony_ci      DBG(23,
3078141cc406Sopenharmony_ci	  "sane_init:  Clever Precalibration will be forcibly disabled...\n");
3079141cc406Sopenharmony_ci      inhibit_clever_precal = SANE_TRUE;
3080141cc406Sopenharmony_ci      continue;
3081141cc406Sopenharmony_ci    }
3082141cc406Sopenharmony_ci    if (!(strncmp("norealcal", dev_name, 9))) {
3083141cc406Sopenharmony_ci      DBG(23,
3084141cc406Sopenharmony_ci	  "sane_init:  Real calibration will be forcibly disabled...\n");
3085141cc406Sopenharmony_ci      inhibit_real_calib = SANE_TRUE;
3086141cc406Sopenharmony_ci      continue;
3087141cc406Sopenharmony_ci    }
3088141cc406Sopenharmony_ci    len = strlen (dev_name);
3089141cc406Sopenharmony_ci    if (!len) continue;			/* ignore empty lines */
3090141cc406Sopenharmony_ci    sanei_config_attach_matching_devices (dev_name, attach_one);
3091141cc406Sopenharmony_ci    }
3092141cc406Sopenharmony_ci  fclose (fp);
3093141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3094141cc406Sopenharmony_ci}
3095141cc406Sopenharmony_ci
3096141cc406Sopenharmony_ci
3097141cc406Sopenharmony_ci
3098141cc406Sopenharmony_ci/********************************************************************/
3099141cc406Sopenharmony_ci/* sane_get_devices                                                 */
3100141cc406Sopenharmony_ci/********************************************************************/
3101141cc406Sopenharmony_ciSANE_Status
3102141cc406Sopenharmony_cisane_get_devices(const SANE_Device ***device_list,
3103141cc406Sopenharmony_ci		 SANE_Bool local_only)
3104141cc406Sopenharmony_ci{
3105141cc406Sopenharmony_ci  Microtek_Device *dev;
3106141cc406Sopenharmony_ci  int i;
3107141cc406Sopenharmony_ci
3108141cc406Sopenharmony_ci  (void) local_only;
3109141cc406Sopenharmony_ci  DBG(10, "sane_get_devices\n");
3110141cc406Sopenharmony_ci  /* we keep an internal copy */
3111141cc406Sopenharmony_ci  if (devlist)
3112141cc406Sopenharmony_ci    free(devlist);  /* hmm, free it if we want a new one, I guess.  YYYYY*/
3113141cc406Sopenharmony_ci
3114141cc406Sopenharmony_ci  devlist = malloc((num_devices + 1) * sizeof(devlist[0]));
3115141cc406Sopenharmony_ci  if (!devlist) return SANE_STATUS_NO_MEM;
3116141cc406Sopenharmony_ci
3117141cc406Sopenharmony_ci  for (i=0, dev=first_dev; i < num_devices; dev = dev->next)
3118141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
3119141cc406Sopenharmony_ci  devlist[i++] = 0;
3120141cc406Sopenharmony_ci
3121141cc406Sopenharmony_ci  *device_list = devlist;
3122141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3123141cc406Sopenharmony_ci}
3124141cc406Sopenharmony_ci
3125141cc406Sopenharmony_ci
3126141cc406Sopenharmony_ci
3127141cc406Sopenharmony_ci/********************************************************************/
3128141cc406Sopenharmony_ci/* sane_open                                                        */
3129141cc406Sopenharmony_ci/********************************************************************/
3130141cc406Sopenharmony_ciSANE_Status
3131141cc406Sopenharmony_cisane_open(SANE_String_Const devicename,
3132141cc406Sopenharmony_ci	  SANE_Handle *handle)
3133141cc406Sopenharmony_ci{
3134141cc406Sopenharmony_ci  Microtek_Scanner *scanner;
3135141cc406Sopenharmony_ci  Microtek_Device *dev;
3136141cc406Sopenharmony_ci  SANE_Status status;
3137141cc406Sopenharmony_ci
3138141cc406Sopenharmony_ci  DBG(10, "sane_open\n");
3139141cc406Sopenharmony_ci  /* find device... */
3140141cc406Sopenharmony_ci  DBG(23, "sane_open:  find device...\n");
3141141cc406Sopenharmony_ci  if (devicename[0]) {
3142141cc406Sopenharmony_ci    for (dev = first_dev; dev; dev = dev->next) {
3143141cc406Sopenharmony_ci      if (strcmp(dev->sane.name, devicename) == 0)
3144141cc406Sopenharmony_ci	break;
3145141cc406Sopenharmony_ci    }
3146141cc406Sopenharmony_ci    if (!dev) {  /* not in list, try manually... */
3147141cc406Sopenharmony_ci      status = attach_scanner(devicename, &dev);
3148141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD) return status;
3149141cc406Sopenharmony_ci    }
3150141cc406Sopenharmony_ci  } else {  /* no device specified, so use first */
3151141cc406Sopenharmony_ci    dev = first_dev;
3152141cc406Sopenharmony_ci  }
3153141cc406Sopenharmony_ci  if (!dev) return SANE_STATUS_INVAL;
3154141cc406Sopenharmony_ci
3155141cc406Sopenharmony_ci  /* create a scanner... */
3156141cc406Sopenharmony_ci  DBG(23, "sane_open:  create scanner...\n");
3157141cc406Sopenharmony_ci  scanner = malloc(sizeof(*scanner));
3158141cc406Sopenharmony_ci  if (!scanner) return SANE_STATUS_NO_MEM;
3159141cc406Sopenharmony_ci  memset(scanner, 0, sizeof(*scanner));
3160141cc406Sopenharmony_ci
3161141cc406Sopenharmony_ci  /* initialize scanner dependent stuff */
3162141cc406Sopenharmony_ci  DBG(23, "sane_open:  initialize scanner dependent stuff...\n");
3163141cc406Sopenharmony_ci  /* ZZZZZZZZZZZZZZ */
3164141cc406Sopenharmony_ci  scanner->unit_type =
3165141cc406Sopenharmony_ci    (dev->info.unit_type & MI_UNIT_PIXELS) ? MS_UNIT_PIXELS : MS_UNIT_18INCH;
3166141cc406Sopenharmony_ci  scanner->res_type =
3167141cc406Sopenharmony_ci    (dev->info.res_step & MI_RESSTEP_1PER) ? MS_RES_1PER : MS_RES_5PER;
3168141cc406Sopenharmony_ci  scanner->midtone_support =
3169141cc406Sopenharmony_ci    (dev->info.enhance_cap & MI_ENH_CAP_MIDTONE) ? SANE_TRUE : SANE_FALSE;
3170141cc406Sopenharmony_ci  scanner->paper_length =
3171141cc406Sopenharmony_ci    (scanner->unit_type == MS_UNIT_PIXELS) ?
3172141cc406Sopenharmony_ci    dev->info.max_y :
3173141cc406Sopenharmony_ci    (SANE_Int)((double)dev->info.max_y * 8.0 /
3174141cc406Sopenharmony_ci	       (double)dev->info.base_resolution);
3175141cc406Sopenharmony_ci  /*
3176141cc406Sopenharmony_ci    (SANE_Int)(SANE_UNFIX(dev->info.max_y) * dev->info.base_resolution) :
3177141cc406Sopenharmony_ci    (SANE_Int)(SANE_UNFIX(dev->info.max_y) * 8);
3178141cc406Sopenharmony_ci    ZZZZZZZ */
3179141cc406Sopenharmony_ci  scanner->bright_r = 0;
3180141cc406Sopenharmony_ci  scanner->bright_g = 0;
3181141cc406Sopenharmony_ci  scanner->bright_b = 0;
3182141cc406Sopenharmony_ci
3183141cc406Sopenharmony_ci  /* calibration shenanigans */
3184141cc406Sopenharmony_ci  if ((dev->info.extra_cap & MI_EXCAP_DIS_RECAL) &&
3185141cc406Sopenharmony_ci      (!(inhibit_real_calib))) {
3186141cc406Sopenharmony_ci    DBG(23, "sane_open:  Real calibration enabled.\n");
3187141cc406Sopenharmony_ci    scanner->allow_calibrate = SANE_FALSE;
3188141cc406Sopenharmony_ci    scanner->do_real_calib = SANE_TRUE;
3189141cc406Sopenharmony_ci    scanner->do_clever_precal = SANE_FALSE;
3190141cc406Sopenharmony_ci  } else if ((dev->info.extra_cap & MI_EXCAP_DIS_RECAL) &&
3191141cc406Sopenharmony_ci	     (!(inhibit_clever_precal))) {
3192141cc406Sopenharmony_ci    DBG(23, "sane_open:  Clever precalibration enabled.\n");
3193141cc406Sopenharmony_ci    scanner->allow_calibrate = SANE_FALSE;
3194141cc406Sopenharmony_ci    scanner->do_real_calib = SANE_FALSE;
3195141cc406Sopenharmony_ci    scanner->do_clever_precal = SANE_TRUE;
3196141cc406Sopenharmony_ci  } else {
3197141cc406Sopenharmony_ci    DBG(23, "sane_open:  All calibration routines disabled.\n");
3198141cc406Sopenharmony_ci    scanner->allow_calibrate = SANE_TRUE;
3199141cc406Sopenharmony_ci    scanner->do_real_calib = SANE_FALSE;
3200141cc406Sopenharmony_ci    scanner->do_clever_precal = SANE_FALSE;
3201141cc406Sopenharmony_ci  }
3202141cc406Sopenharmony_ci
3203141cc406Sopenharmony_ci  scanner->onepass = (dev->info.modes & MI_MODES_ONEPASS);
3204141cc406Sopenharmony_ci  scanner->allowbacktrack = SANE_TRUE;  /* ??? XXXXXXX */
3205141cc406Sopenharmony_ci  scanner->reversecolors = SANE_FALSE;
3206141cc406Sopenharmony_ci  scanner->fastprescan = SANE_FALSE;
3207141cc406Sopenharmony_ci  scanner->bits_per_color = 8;
3208141cc406Sopenharmony_ci
3209141cc406Sopenharmony_ci  /* init gamma tables */
3210141cc406Sopenharmony_ci  if (dev->info.max_lookup_size) {
3211141cc406Sopenharmony_ci    int j, v, max_entry;
3212141cc406Sopenharmony_ci    DBG(23, "sane_open:  init gamma tables...\n");
3213141cc406Sopenharmony_ci    scanner->gamma_entries = dev->info.max_lookup_size;
3214141cc406Sopenharmony_ci    scanner->gamma_entry_size = dev->info.gamma_size;
3215141cc406Sopenharmony_ci    scanner->gamma_bit_depth = dev->info.max_gamma_bit_depth;
3216141cc406Sopenharmony_ci    max_entry = (1 << scanner->gamma_bit_depth) - 1;
3217141cc406Sopenharmony_ci    scanner->gamma_entry_range.min = 0;
3218141cc406Sopenharmony_ci    scanner->gamma_entry_range.max = max_entry;
3219141cc406Sopenharmony_ci    scanner->gamma_entry_range.quant = 1;
3220141cc406Sopenharmony_ci
3221141cc406Sopenharmony_ci    scanner->gray_lut  = calloc(scanner->gamma_entries,
3222141cc406Sopenharmony_ci			       sizeof(scanner->gray_lut[0]));
3223141cc406Sopenharmony_ci    scanner->red_lut   = calloc(scanner->gamma_entries,
3224141cc406Sopenharmony_ci			       sizeof(scanner->red_lut[0]));
3225141cc406Sopenharmony_ci    scanner->green_lut = calloc(scanner->gamma_entries,
3226141cc406Sopenharmony_ci			       sizeof(scanner->green_lut[0]));
3227141cc406Sopenharmony_ci    scanner->blue_lut  = calloc(scanner->gamma_entries,
3228141cc406Sopenharmony_ci			       sizeof(scanner->blue_lut[0]));
3229141cc406Sopenharmony_ci    if ((scanner->gray_lut == NULL) ||
3230141cc406Sopenharmony_ci	(scanner->red_lut == NULL) ||
3231141cc406Sopenharmony_ci	(scanner->green_lut == NULL) ||
3232141cc406Sopenharmony_ci	(scanner->blue_lut == NULL)) {
3233141cc406Sopenharmony_ci      DBG(23, "sane_open:  unable to allocate space for %d-entry LUT's;\n",
3234141cc406Sopenharmony_ci	  scanner->gamma_entries);
3235141cc406Sopenharmony_ci      DBG(23, "            so, gamma tables now DISABLED.\n");
3236141cc406Sopenharmony_ci      free(scanner->gray_lut);
3237141cc406Sopenharmony_ci      free(scanner->red_lut);
3238141cc406Sopenharmony_ci      free(scanner->green_lut);
3239141cc406Sopenharmony_ci      free(scanner->blue_lut);
3240141cc406Sopenharmony_ci    }
3241141cc406Sopenharmony_ci    for (j=0; j<scanner->gamma_entries; j += scanner->gamma_entry_size) {
3242141cc406Sopenharmony_ci      v = (SANE_Int)
3243141cc406Sopenharmony_ci	((double) j * (double) max_entry /
3244141cc406Sopenharmony_ci	 ((double) scanner->gamma_entries - 1.0) + 0.5);
3245141cc406Sopenharmony_ci      scanner->gray_lut[j] = v;
3246141cc406Sopenharmony_ci      scanner->red_lut[j] = v;
3247141cc406Sopenharmony_ci      scanner->green_lut[j] = v;
3248141cc406Sopenharmony_ci      scanner->blue_lut[j] = v;
3249141cc406Sopenharmony_ci    }
3250141cc406Sopenharmony_ci  } else {
3251141cc406Sopenharmony_ci    DBG(23, "sane_open:  NO gamma tables.  (max size = %lu)\n",
3252141cc406Sopenharmony_ci	(u_long)dev->info.max_lookup_size);
3253141cc406Sopenharmony_ci    scanner->gamma_entries = 0;
3254141cc406Sopenharmony_ci    scanner->gray_lut  = NULL;
3255141cc406Sopenharmony_ci    scanner->red_lut   = NULL;
3256141cc406Sopenharmony_ci    scanner->green_lut = NULL;
3257141cc406Sopenharmony_ci    scanner->blue_lut  = NULL;
3258141cc406Sopenharmony_ci  }
3259141cc406Sopenharmony_ci
3260141cc406Sopenharmony_ci  DBG(23, "sane_open:  init pass-time variables...\n");
3261141cc406Sopenharmony_ci  scanner->scanning = SANE_FALSE;
3262141cc406Sopenharmony_ci  scanner->this_pass = 0;
3263141cc406Sopenharmony_ci  scanner->sfd = -1;
3264141cc406Sopenharmony_ci  scanner->dev = dev;
3265141cc406Sopenharmony_ci  scanner->sense_flags = 0;
3266141cc406Sopenharmony_ci  scanner->scan_started = SANE_FALSE;
3267141cc406Sopenharmony_ci  scanner->woe = SANE_FALSE;
3268141cc406Sopenharmony_ci  scanner->cancel = SANE_FALSE;
3269141cc406Sopenharmony_ci
3270141cc406Sopenharmony_ci  DBG(23, "sane_open:  init clever cache...\n");
3271141cc406Sopenharmony_ci  /* clear out that clever cache, so it doesn't match anything */
3272141cc406Sopenharmony_ci  {
3273141cc406Sopenharmony_ci    int j;
3274141cc406Sopenharmony_ci    for (j=0; j<10; j++)
3275141cc406Sopenharmony_ci      scanner->mode_sense_cache[j] = 0;
3276141cc406Sopenharmony_ci    scanner->precal_record = MS_PRECAL_NONE;
3277141cc406Sopenharmony_ci  }
3278141cc406Sopenharmony_ci
3279141cc406Sopenharmony_ci  DBG(23, "sane_open:  initialize options:  \n");
3280141cc406Sopenharmony_ci  if ((status = init_options(scanner)) != SANE_STATUS_GOOD) return status;
3281141cc406Sopenharmony_ci
3282141cc406Sopenharmony_ci  scanner->next = first_handle;
3283141cc406Sopenharmony_ci  first_handle = scanner;
3284141cc406Sopenharmony_ci  *handle = scanner;
3285141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3286141cc406Sopenharmony_ci}
3287141cc406Sopenharmony_ci
3288141cc406Sopenharmony_ci
3289141cc406Sopenharmony_ci
3290141cc406Sopenharmony_ci/********************************************************************/
3291141cc406Sopenharmony_ci/* sane_close                                                       */
3292141cc406Sopenharmony_ci/********************************************************************/
3293141cc406Sopenharmony_civoid
3294141cc406Sopenharmony_cisane_close (SANE_Handle handle)
3295141cc406Sopenharmony_ci{
3296141cc406Sopenharmony_ci  Microtek_Scanner *ms = handle;
3297141cc406Sopenharmony_ci
3298141cc406Sopenharmony_ci  DBG(10, "sane_close...\n");
3299141cc406Sopenharmony_ci  /* free malloc'ed stuff (strdup counts too!) */
3300141cc406Sopenharmony_ci  free((void *) ms->sod[OPT_MODE].constraint.string_list);
3301141cc406Sopenharmony_ci  free((void *) ms->sod[OPT_SOURCE].constraint.string_list);
3302141cc406Sopenharmony_ci  free(ms->val[OPT_MODE].s);
3303141cc406Sopenharmony_ci  free(ms->val[OPT_HALFTONE_PATTERN].s);
3304141cc406Sopenharmony_ci  free(ms->val[OPT_SOURCE].s);
3305141cc406Sopenharmony_ci  free(ms->val[OPT_CUSTOM_GAMMA].s);
3306141cc406Sopenharmony_ci  free(ms->gray_lut);
3307141cc406Sopenharmony_ci  free(ms->red_lut);
3308141cc406Sopenharmony_ci  free(ms->green_lut);
3309141cc406Sopenharmony_ci  free(ms->blue_lut);
3310141cc406Sopenharmony_ci  /* remove Scanner from linked list */
3311141cc406Sopenharmony_ci  if (first_handle == ms)
3312141cc406Sopenharmony_ci    first_handle = ms->next;
3313141cc406Sopenharmony_ci  else {
3314141cc406Sopenharmony_ci    Microtek_Scanner *ts = first_handle;
3315141cc406Sopenharmony_ci    while ((ts != NULL) && (ts->next != ms)) ts = ts->next;
3316141cc406Sopenharmony_ci    ts->next = ts->next->next; /* == ms->next */
3317141cc406Sopenharmony_ci  }
3318141cc406Sopenharmony_ci  /* finally, say goodbye to the Scanner */
3319141cc406Sopenharmony_ci  free(ms);
3320141cc406Sopenharmony_ci}
3321141cc406Sopenharmony_ci
3322141cc406Sopenharmony_ci
3323141cc406Sopenharmony_ci
3324141cc406Sopenharmony_ci/********************************************************************/
3325141cc406Sopenharmony_ci/* sane_get_option_descriptor                                       */
3326141cc406Sopenharmony_ci/********************************************************************/
3327141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
3328141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle,
3329141cc406Sopenharmony_ci			    SANE_Int option)
3330141cc406Sopenharmony_ci{
3331141cc406Sopenharmony_ci  Microtek_Scanner *scanner = handle;
3332141cc406Sopenharmony_ci
3333141cc406Sopenharmony_ci  DBG(96, "sane_get_option_descriptor (%d)...\n", option);
3334141cc406Sopenharmony_ci  if ((unsigned)option >= NUM_OPTIONS) return NULL;
3335141cc406Sopenharmony_ci  return &(scanner->sod[option]);
3336141cc406Sopenharmony_ci}
3337141cc406Sopenharmony_ci
3338141cc406Sopenharmony_ci
3339141cc406Sopenharmony_ci
3340141cc406Sopenharmony_ci/********************************************************************/
3341141cc406Sopenharmony_ci/* sane_control_option                                              */
3342141cc406Sopenharmony_ci/********************************************************************/
3343141cc406Sopenharmony_ciSANE_Status
3344141cc406Sopenharmony_cisane_control_option (SANE_Handle handle,
3345141cc406Sopenharmony_ci		     SANE_Int option,
3346141cc406Sopenharmony_ci		     SANE_Action action,
3347141cc406Sopenharmony_ci		     void *value,
3348141cc406Sopenharmony_ci		     SANE_Int *info)
3349141cc406Sopenharmony_ci{
3350141cc406Sopenharmony_ci  Microtek_Scanner *scanner = handle;
3351141cc406Sopenharmony_ci  SANE_Option_Descriptor *sod;
3352141cc406Sopenharmony_ci  Option_Value  *val;
3353141cc406Sopenharmony_ci  SANE_Status status;
3354141cc406Sopenharmony_ci
3355141cc406Sopenharmony_ci  DBG(96, "sane_control_option (opt=%d,act=%d,val=%p,info=%p)\n",
3356141cc406Sopenharmony_ci      option, action, value, (void*) info);
3357141cc406Sopenharmony_ci
3358141cc406Sopenharmony_ci  sod = scanner->sod;
3359141cc406Sopenharmony_ci  val = scanner->val;
3360141cc406Sopenharmony_ci
3361141cc406Sopenharmony_ci  /* no changes while in mid-pass! */
3362141cc406Sopenharmony_ci  if (scanner->scanning) return SANE_STATUS_DEVICE_BUSY;
3363141cc406Sopenharmony_ci  /* and... no changes while in middle of three-pass series! */
3364141cc406Sopenharmony_ci  if (scanner->this_pass != 0) return SANE_STATUS_DEVICE_BUSY;
3365141cc406Sopenharmony_ci
3366141cc406Sopenharmony_ci  if ( ((option >= NUM_OPTIONS) || (option < 0)) ||
3367141cc406Sopenharmony_ci       (!SANE_OPTION_IS_ACTIVE(scanner->sod[option].cap)) )
3368141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
3369141cc406Sopenharmony_ci
3370141cc406Sopenharmony_ci  if (info) *info = 0;
3371141cc406Sopenharmony_ci
3372141cc406Sopenharmony_ci  /* choose by action */
3373141cc406Sopenharmony_ci  switch (action) {
3374141cc406Sopenharmony_ci
3375141cc406Sopenharmony_ci  case SANE_ACTION_GET_VALUE:
3376141cc406Sopenharmony_ci    switch (option) {
3377141cc406Sopenharmony_ci      /* word options... */
3378141cc406Sopenharmony_ci    case OPT_RESOLUTION:
3379141cc406Sopenharmony_ci    case OPT_SPEED:
3380141cc406Sopenharmony_ci    case OPT_BACKTRACK:
3381141cc406Sopenharmony_ci    case OPT_NEGATIVE:
3382141cc406Sopenharmony_ci    case OPT_PREVIEW:
3383141cc406Sopenharmony_ci    case OPT_TL_X:
3384141cc406Sopenharmony_ci    case OPT_TL_Y:
3385141cc406Sopenharmony_ci    case OPT_BR_X:
3386141cc406Sopenharmony_ci    case OPT_BR_Y:
3387141cc406Sopenharmony_ci    case OPT_EXPOSURE:
3388141cc406Sopenharmony_ci    case OPT_BRIGHTNESS:
3389141cc406Sopenharmony_ci    case OPT_CONTRAST:
3390141cc406Sopenharmony_ci    case OPT_HIGHLIGHT:
3391141cc406Sopenharmony_ci    case OPT_SHADOW:
3392141cc406Sopenharmony_ci    case OPT_MIDTONE:
3393141cc406Sopenharmony_ci    case OPT_GAMMA_BIND:
3394141cc406Sopenharmony_ci    case OPT_ANALOG_GAMMA:
3395141cc406Sopenharmony_ci    case OPT_ANALOG_GAMMA_R:
3396141cc406Sopenharmony_ci    case OPT_ANALOG_GAMMA_G:
3397141cc406Sopenharmony_ci    case OPT_ANALOG_GAMMA_B:
3398141cc406Sopenharmony_ci    case OPT_EXP_RES:
3399141cc406Sopenharmony_ci    case OPT_CALIB_ONCE:
3400141cc406Sopenharmony_ci      *(SANE_Word *)value = val[option].w;
3401141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3402141cc406Sopenharmony_ci      /* word-array options... */
3403141cc406Sopenharmony_ci      /*    case OPT_HALFTONE_PATTERN:*/
3404141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR:
3405141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_R:
3406141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_G:
3407141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_B:
3408141cc406Sopenharmony_ci      memcpy(value, val[option].wa, sod[option].size);
3409141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3410141cc406Sopenharmony_ci      /* string options... */
3411141cc406Sopenharmony_ci    case OPT_MODE:
3412141cc406Sopenharmony_ci    case OPT_HALFTONE_PATTERN:
3413141cc406Sopenharmony_ci    case OPT_CUSTOM_GAMMA:
3414141cc406Sopenharmony_ci    case OPT_SOURCE:
3415141cc406Sopenharmony_ci      strcpy(value, val[option].s);
3416141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3417141cc406Sopenharmony_ci      /* others.... */
3418141cc406Sopenharmony_ci    case OPT_NUM_OPTS:
3419141cc406Sopenharmony_ci      *(SANE_Word *) value = NUM_OPTIONS;
3420141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3421141cc406Sopenharmony_ci    default:
3422141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3423141cc406Sopenharmony_ci    }
3424141cc406Sopenharmony_ci    break;
3425141cc406Sopenharmony_ci
3426141cc406Sopenharmony_ci  case SANE_ACTION_SET_VALUE: {
3427141cc406Sopenharmony_ci    status = sanei_constrain_value(sod + option, value, info);
3428141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
3429141cc406Sopenharmony_ci      return status;
3430141cc406Sopenharmony_ci
3431141cc406Sopenharmony_ci    switch (option) {
3432141cc406Sopenharmony_ci      /* set word options... */
3433141cc406Sopenharmony_ci    case OPT_TL_X:
3434141cc406Sopenharmony_ci    case OPT_TL_Y:
3435141cc406Sopenharmony_ci    case OPT_BR_X:
3436141cc406Sopenharmony_ci    case OPT_BR_Y:
3437141cc406Sopenharmony_ci    case OPT_RESOLUTION:
3438141cc406Sopenharmony_ci      if (info)
3439141cc406Sopenharmony_ci	*info |= SANE_INFO_RELOAD_PARAMS;
3440141cc406Sopenharmony_ci      // fall through
3441141cc406Sopenharmony_ci    case OPT_SPEED:
3442141cc406Sopenharmony_ci    case OPT_PREVIEW:
3443141cc406Sopenharmony_ci    case OPT_BACKTRACK:
3444141cc406Sopenharmony_ci    case OPT_NEGATIVE:
3445141cc406Sopenharmony_ci    case OPT_EXPOSURE:
3446141cc406Sopenharmony_ci    case OPT_BRIGHTNESS:
3447141cc406Sopenharmony_ci    case OPT_CONTRAST:
3448141cc406Sopenharmony_ci    case OPT_ANALOG_GAMMA:
3449141cc406Sopenharmony_ci    case OPT_ANALOG_GAMMA_R:
3450141cc406Sopenharmony_ci    case OPT_ANALOG_GAMMA_G:
3451141cc406Sopenharmony_ci    case OPT_ANALOG_GAMMA_B:
3452141cc406Sopenharmony_ci      val[option].w = *(SANE_Word *)value;
3453141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3454141cc406Sopenharmony_ci
3455141cc406Sopenharmony_ci    case OPT_HIGHLIGHT:
3456141cc406Sopenharmony_ci    case OPT_SHADOW:
3457141cc406Sopenharmony_ci    case OPT_MIDTONE:
3458141cc406Sopenharmony_ci      val[option].w = *(SANE_Word *)value;
3459141cc406Sopenharmony_ci      /* we need to (silently) make sure shadow <= midtone <= highlight */
3460141cc406Sopenharmony_ci      if (scanner->midtone_support) {
3461141cc406Sopenharmony_ci	if (val[OPT_SHADOW].w > val[OPT_MIDTONE].w) {
3462141cc406Sopenharmony_ci	  if (option == OPT_SHADOW)
3463141cc406Sopenharmony_ci	    val[OPT_SHADOW].w = val[OPT_MIDTONE].w;
3464141cc406Sopenharmony_ci	  else
3465141cc406Sopenharmony_ci	    val[OPT_MIDTONE].w = val[OPT_SHADOW].w;
3466141cc406Sopenharmony_ci	}
3467141cc406Sopenharmony_ci	if (val[OPT_HIGHLIGHT].w < val[OPT_MIDTONE].w) {
3468141cc406Sopenharmony_ci	  if (option == OPT_HIGHLIGHT)
3469141cc406Sopenharmony_ci	    val[OPT_HIGHLIGHT].w = val[OPT_MIDTONE].w;
3470141cc406Sopenharmony_ci	  else
3471141cc406Sopenharmony_ci	    val[OPT_MIDTONE].w = val[OPT_HIGHLIGHT].w;
3472141cc406Sopenharmony_ci	}
3473141cc406Sopenharmony_ci      } else {
3474141cc406Sopenharmony_ci	if (val[OPT_SHADOW].w > val[OPT_HIGHLIGHT].w) {
3475141cc406Sopenharmony_ci	  if (option == OPT_SHADOW)
3476141cc406Sopenharmony_ci	    val[OPT_SHADOW].w = val[OPT_HIGHLIGHT].w;
3477141cc406Sopenharmony_ci	  else
3478141cc406Sopenharmony_ci	    val[OPT_HIGHLIGHT].w = val[OPT_SHADOW].w;
3479141cc406Sopenharmony_ci	}
3480141cc406Sopenharmony_ci      }
3481141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3482141cc406Sopenharmony_ci
3483141cc406Sopenharmony_ci    case OPT_EXP_RES:
3484141cc406Sopenharmony_ci      if (val[option].w != *(SANE_Word *) value) {
3485141cc406Sopenharmony_ci	val[option].w = *(SANE_Word *)value;
3486141cc406Sopenharmony_ci	if (info) *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
3487141cc406Sopenharmony_ci	if (val[OPT_EXP_RES].w) {
3488141cc406Sopenharmony_ci	  sod[OPT_RESOLUTION].constraint.range = &(scanner->exp_res_range);
3489141cc406Sopenharmony_ci	  val[OPT_RESOLUTION].w *= 2;
3490141cc406Sopenharmony_ci	} else {
3491141cc406Sopenharmony_ci	  sod[OPT_RESOLUTION].constraint.range = &(scanner->res_range);
3492141cc406Sopenharmony_ci	  val[OPT_RESOLUTION].w /= 2;
3493141cc406Sopenharmony_ci	}
3494141cc406Sopenharmony_ci      }
3495141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3496141cc406Sopenharmony_ci
3497141cc406Sopenharmony_ci    case OPT_CALIB_ONCE:
3498141cc406Sopenharmony_ci      val[option].w = *(SANE_Word *)value;
3499141cc406Sopenharmony_ci      /* toggling off and on should force a recalibration... */
3500141cc406Sopenharmony_ci      if (!(val[option].w)) scanner->precal_record = MS_PRECAL_NONE;
3501141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3502141cc406Sopenharmony_ci
3503141cc406Sopenharmony_ci    case OPT_GAMMA_BIND:
3504141cc406Sopenharmony_ci    case OPT_CUSTOM_GAMMA:
3505141cc406Sopenharmony_ci      if (option == OPT_GAMMA_BIND) {
3506141cc406Sopenharmony_ci	if (val[option].w != *(SANE_Word *) value)
3507141cc406Sopenharmony_ci	  if (info) *info |= SANE_INFO_RELOAD_OPTIONS;
3508141cc406Sopenharmony_ci	val[option].w = *(SANE_Word *) value;
3509141cc406Sopenharmony_ci      } else if (option == OPT_CUSTOM_GAMMA) {
3510141cc406Sopenharmony_ci	if (val[option].s) {
3511141cc406Sopenharmony_ci	  if (strcmp(value, val[option].s))
3512141cc406Sopenharmony_ci	    if (info) *info |= SANE_INFO_RELOAD_OPTIONS;
3513141cc406Sopenharmony_ci	  free(val[option].s);
3514141cc406Sopenharmony_ci	}
3515141cc406Sopenharmony_ci	val[option].s = strdup(value);
3516141cc406Sopenharmony_ci      }
3517141cc406Sopenharmony_ci      if ( !(strcmp(val[OPT_CUSTOM_GAMMA].s, M_NONE)) ||
3518141cc406Sopenharmony_ci	   !(strcmp(val[OPT_CUSTOM_GAMMA].s, M_SCALAR)) ) {
3519141cc406Sopenharmony_ci	sod[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
3520141cc406Sopenharmony_ci	sod[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
3521141cc406Sopenharmony_ci	sod[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
3522141cc406Sopenharmony_ci	sod[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
3523141cc406Sopenharmony_ci      }
3524141cc406Sopenharmony_ci      if ( !(strcmp(val[OPT_CUSTOM_GAMMA].s, M_NONE)) ||
3525141cc406Sopenharmony_ci	   !(strcmp(val[OPT_CUSTOM_GAMMA].s, M_TABLE)) ) {
3526141cc406Sopenharmony_ci	sod[OPT_ANALOG_GAMMA].cap |= SANE_CAP_INACTIVE;
3527141cc406Sopenharmony_ci	sod[OPT_ANALOG_GAMMA_R].cap |= SANE_CAP_INACTIVE;
3528141cc406Sopenharmony_ci	sod[OPT_ANALOG_GAMMA_G].cap |= SANE_CAP_INACTIVE;
3529141cc406Sopenharmony_ci	sod[OPT_ANALOG_GAMMA_B].cap |= SANE_CAP_INACTIVE;
3530141cc406Sopenharmony_ci      }
3531141cc406Sopenharmony_ci      if (!(strcmp(val[OPT_CUSTOM_GAMMA].s, M_SCALAR))) {
3532141cc406Sopenharmony_ci	if (val[OPT_GAMMA_BIND].w == SANE_TRUE) {
3533141cc406Sopenharmony_ci	  sod[OPT_ANALOG_GAMMA].cap &= ~SANE_CAP_INACTIVE;
3534141cc406Sopenharmony_ci	  sod[OPT_ANALOG_GAMMA_R].cap |= SANE_CAP_INACTIVE;
3535141cc406Sopenharmony_ci	  sod[OPT_ANALOG_GAMMA_G].cap |= SANE_CAP_INACTIVE;
3536141cc406Sopenharmony_ci	  sod[OPT_ANALOG_GAMMA_B].cap |= SANE_CAP_INACTIVE;
3537141cc406Sopenharmony_ci	} else {
3538141cc406Sopenharmony_ci	  sod[OPT_ANALOG_GAMMA].cap |= SANE_CAP_INACTIVE;
3539141cc406Sopenharmony_ci	  sod[OPT_ANALOG_GAMMA_R].cap &= ~SANE_CAP_INACTIVE;
3540141cc406Sopenharmony_ci	  sod[OPT_ANALOG_GAMMA_G].cap &= ~SANE_CAP_INACTIVE;
3541141cc406Sopenharmony_ci	  sod[OPT_ANALOG_GAMMA_B].cap &= ~SANE_CAP_INACTIVE;
3542141cc406Sopenharmony_ci	}
3543141cc406Sopenharmony_ci      }
3544141cc406Sopenharmony_ci      if (!(strcmp(val[OPT_CUSTOM_GAMMA].s, M_TABLE))) {
3545141cc406Sopenharmony_ci	if (val[OPT_GAMMA_BIND].w == SANE_TRUE) {
3546141cc406Sopenharmony_ci	  sod[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
3547141cc406Sopenharmony_ci	  sod[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
3548141cc406Sopenharmony_ci	  sod[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
3549141cc406Sopenharmony_ci	  sod[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
3550141cc406Sopenharmony_ci	} else {
3551141cc406Sopenharmony_ci	  sod[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
3552141cc406Sopenharmony_ci	  sod[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
3553141cc406Sopenharmony_ci	  sod[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
3554141cc406Sopenharmony_ci	  sod[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
3555141cc406Sopenharmony_ci	}
3556141cc406Sopenharmony_ci      }
3557141cc406Sopenharmony_ci      if (!(strcmp(val[OPT_CUSTOM_GAMMA].s, M_NONE)))
3558141cc406Sopenharmony_ci	sod[OPT_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
3559141cc406Sopenharmony_ci      else if (!(strcmp(val[OPT_MODE].s, M_COLOR)))
3560141cc406Sopenharmony_ci	sod[OPT_GAMMA_BIND].cap &= ~SANE_CAP_INACTIVE;
3561141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3562141cc406Sopenharmony_ci
3563141cc406Sopenharmony_ci
3564141cc406Sopenharmony_ci    case OPT_MODE:
3565141cc406Sopenharmony_ci      if (val[option].s) {
3566141cc406Sopenharmony_ci	if (strcmp(val[option].s, value))
3567141cc406Sopenharmony_ci	  if (info)
3568141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
3569141cc406Sopenharmony_ci	free(val[option].s);
3570141cc406Sopenharmony_ci      }
3571141cc406Sopenharmony_ci      val[option].s = strdup(value);
3572141cc406Sopenharmony_ci      if (strcmp(val[option].s, M_HALFTONE)) {
3573141cc406Sopenharmony_ci	sod[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
3574141cc406Sopenharmony_ci      } else {
3575141cc406Sopenharmony_ci	sod[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
3576141cc406Sopenharmony_ci      }
3577141cc406Sopenharmony_ci      if (strcmp(val[option].s, M_COLOR)) { /* not color */
3578141cc406Sopenharmony_ci        /*val[OPT_GAMMA_BIND].w = SANE_TRUE;*/
3579141cc406Sopenharmony_ci	DBG(23, "FLIP ma LID!  bind is %d\n", val[OPT_GAMMA_BIND].w);
3580141cc406Sopenharmony_ci	{
3581141cc406Sopenharmony_ci	  SANE_Bool Trueness = SANE_TRUE;
3582141cc406Sopenharmony_ci	  SANE_Status status;
3583141cc406Sopenharmony_ci	  status = sane_control_option(handle,
3584141cc406Sopenharmony_ci				       OPT_GAMMA_BIND,
3585141cc406Sopenharmony_ci				       SANE_ACTION_SET_VALUE,
3586141cc406Sopenharmony_ci				       &Trueness,
3587141cc406Sopenharmony_ci				       NULL);
3588141cc406Sopenharmony_ci	  DBG(23, "stat is: %d\n", status);
3589141cc406Sopenharmony_ci	}
3590141cc406Sopenharmony_ci	DBG(23, "LID be FLIPPED!  bind is %d\n", val[OPT_GAMMA_BIND].w);
3591141cc406Sopenharmony_ci	sod[OPT_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
3592141cc406Sopenharmony_ci	/*	sod[OPT_FORCE_3PASS].cap |= SANE_CAP_INACTIVE;*/
3593141cc406Sopenharmony_ci      } else {
3594141cc406Sopenharmony_ci	sod[OPT_GAMMA_BIND].cap &= ~SANE_CAP_INACTIVE;
3595141cc406Sopenharmony_ci	/*	if (scanner->dev->info.modes & MI_MODES_ONEPASS)
3596141cc406Sopenharmony_ci	  sod[OPT_FORCE_3PASS].cap &= ~SANE_CAP_INACTIVE;*/
3597141cc406Sopenharmony_ci      }
3598141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3599141cc406Sopenharmony_ci
3600141cc406Sopenharmony_ci    case OPT_HALFTONE_PATTERN:
3601141cc406Sopenharmony_ci    case OPT_SOURCE:
3602141cc406Sopenharmony_ci      if (val[option].s) free(val[option].s);
3603141cc406Sopenharmony_ci      val[option].s = strdup(value);
3604141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3605141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR:
3606141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_R:
3607141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_G:
3608141cc406Sopenharmony_ci    case OPT_GAMMA_VECTOR_B:
3609141cc406Sopenharmony_ci      memcpy(val[option].wa, value, sod[option].size);
3610141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
3611141cc406Sopenharmony_ci    default:
3612141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3613141cc406Sopenharmony_ci    }
3614141cc406Sopenharmony_ci  }
3615141cc406Sopenharmony_ci  break;
3616141cc406Sopenharmony_ci
3617141cc406Sopenharmony_ci  case SANE_ACTION_SET_AUTO:
3618141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;	/* We are DUMB. */
3619141cc406Sopenharmony_ci  }
3620141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3621141cc406Sopenharmony_ci}
3622141cc406Sopenharmony_ci
3623141cc406Sopenharmony_ci
3624141cc406Sopenharmony_ci
3625141cc406Sopenharmony_ci/********************************************************************/
3626141cc406Sopenharmony_ci/* sane_get_parameters                                              */
3627141cc406Sopenharmony_ci/********************************************************************/
3628141cc406Sopenharmony_ciSANE_Status
3629141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle,
3630141cc406Sopenharmony_ci		     SANE_Parameters *params)
3631141cc406Sopenharmony_ci{
3632141cc406Sopenharmony_ci  Microtek_Scanner *s = handle;
3633141cc406Sopenharmony_ci
3634141cc406Sopenharmony_ci  DBG(23, "sane_get_parameters...\n");
3635141cc406Sopenharmony_ci
3636141cc406Sopenharmony_ci  if (!s->scanning) {
3637141cc406Sopenharmony_ci    /* decipher scan mode */
3638141cc406Sopenharmony_ci    if (!(strcmp(s->val[OPT_MODE].s, M_LINEART)))
3639141cc406Sopenharmony_ci      s->mode = MS_MODE_LINEART;
3640141cc406Sopenharmony_ci    else if (!(strcmp(s->val[OPT_MODE].s, M_HALFTONE)))
3641141cc406Sopenharmony_ci      s->mode = MS_MODE_HALFTONE;
3642141cc406Sopenharmony_ci    else if (!(strcmp(s->val[OPT_MODE].s, M_GRAY)))
3643141cc406Sopenharmony_ci      s->mode = MS_MODE_GRAY;
3644141cc406Sopenharmony_ci    else if (!(strcmp(s->val[OPT_MODE].s, M_COLOR)))
3645141cc406Sopenharmony_ci      s->mode = MS_MODE_COLOR;
3646141cc406Sopenharmony_ci
3647141cc406Sopenharmony_ci    if (s->mode == MS_MODE_COLOR) {
3648141cc406Sopenharmony_ci      if (s->onepass) {
3649141cc406Sopenharmony_ci	/* regular one-pass */
3650141cc406Sopenharmony_ci	DBG(23, "sane_get_parameters:  regular 1-pass color\n");
3651141cc406Sopenharmony_ci	s->threepasscolor = SANE_FALSE;
3652141cc406Sopenharmony_ci	s->onepasscolor = SANE_TRUE;
3653141cc406Sopenharmony_ci	s->color_seq = s->dev->info.color_sequence;
3654141cc406Sopenharmony_ci      } else { /* 3-pass scanner */
3655141cc406Sopenharmony_ci	DBG(23, "sane_get_parameters:  regular 3-pass color\n");
3656141cc406Sopenharmony_ci	s->threepasscolor = SANE_TRUE;
3657141cc406Sopenharmony_ci	s->onepasscolor = SANE_FALSE;
3658141cc406Sopenharmony_ci	s->color_seq = s->dev->info.color_sequence;
3659141cc406Sopenharmony_ci      }
3660141cc406Sopenharmony_ci    } else { /* not color! */
3661141cc406Sopenharmony_ci	DBG(23, "sane_get_parameters:  non-color\n");
3662141cc406Sopenharmony_ci	s->threepasscolor = SANE_FALSE;
3663141cc406Sopenharmony_ci	s->onepasscolor = SANE_FALSE;
3664141cc406Sopenharmony_ci	s->color_seq = s->dev->info.color_sequence;
3665141cc406Sopenharmony_ci    }
3666141cc406Sopenharmony_ci
3667141cc406Sopenharmony_ci    s->transparency = !(strcmp(s->val[OPT_SOURCE].s, M_TRANS));
3668141cc406Sopenharmony_ci    s->useADF = !(strcmp(s->val[OPT_SOURCE].s, M_AUTOFEED));
3669141cc406Sopenharmony_ci    /* disallow exp. res. during preview scan XXXXXXXXXXX */
3670141cc406Sopenharmony_ci    /*s->expandedresolution =
3671141cc406Sopenharmony_ci      (s->val[OPT_EXP_RES].w) && !(s->val[OPT_PREVIEW].w);*/
3672141cc406Sopenharmony_ci    s->expandedresolution = (s->val[OPT_EXP_RES].w);
3673141cc406Sopenharmony_ci    s->doexpansion = (s->expandedresolution && !(s->dev->info.does_expansion));
3674141cc406Sopenharmony_ci
3675141cc406Sopenharmony_ci    if (s->res_type == MS_RES_1PER) {
3676141cc406Sopenharmony_ci      s->resolution = (SANE_Int)(SANE_UNFIX(s->val[OPT_RESOLUTION].w));
3677141cc406Sopenharmony_ci      s->resolution_code =
3678141cc406Sopenharmony_ci	0xFF & ((s->resolution * 100) /
3679141cc406Sopenharmony_ci		s->dev->info.base_resolution /
3680141cc406Sopenharmony_ci		(s->expandedresolution ? 2 : 1));
3681141cc406Sopenharmony_ci      DBG(23, "sane_get_parameters:  res_code = %d (%2x)\n",
3682141cc406Sopenharmony_ci	      s->resolution_code, s->resolution_code);
3683141cc406Sopenharmony_ci    } else {
3684141cc406Sopenharmony_ci      DBG(23, "sane_get_parameters:  5 percent!!!\n");
3685141cc406Sopenharmony_ci      /* XXXXXXXXXXXXX */
3686141cc406Sopenharmony_ci    }
3687141cc406Sopenharmony_ci
3688141cc406Sopenharmony_ci    s->calib_once = s->val[OPT_CALIB_ONCE].w;
3689141cc406Sopenharmony_ci
3690141cc406Sopenharmony_ci    s->reversecolors = s->val[OPT_NEGATIVE].w;
3691141cc406Sopenharmony_ci    s->prescan = s->val[OPT_PREVIEW].w;
3692141cc406Sopenharmony_ci    s->exposure = (s->val[OPT_EXPOSURE].w / 3) + 7;
3693141cc406Sopenharmony_ci    s->contrast = (s->val[OPT_CONTRAST].w / 7) + 7;
3694141cc406Sopenharmony_ci    s->velocity  = s->val[OPT_SPEED].w;
3695141cc406Sopenharmony_ci    s->shadow    = s->val[OPT_SHADOW].w;
3696141cc406Sopenharmony_ci    s->highlight = s->val[OPT_HIGHLIGHT].w;
3697141cc406Sopenharmony_ci    s->midtone   = s->val[OPT_MIDTONE].w;
3698141cc406Sopenharmony_ci    if (SANE_OPTION_IS_ACTIVE(s->sod[OPT_BRIGHTNESS].cap)) {
3699141cc406Sopenharmony_ci#if 1  /* this is _not_ what the docs specify! */
3700141cc406Sopenharmony_ci      if (s->val[OPT_BRIGHTNESS].w >= 0)
3701141cc406Sopenharmony_ci	s->bright_r = (SANE_Byte) (s->val[OPT_BRIGHTNESS].w);
3702141cc406Sopenharmony_ci      else
3703141cc406Sopenharmony_ci	s->bright_r = (SANE_Byte) (0x80 | (- s->val[OPT_BRIGHTNESS].w));
3704141cc406Sopenharmony_ci#else
3705141cc406Sopenharmony_ci      s->bright_r = (SANE_Byte) (s->val[OPT_BRIGHTNESS].w);
3706141cc406Sopenharmony_ci#endif
3707141cc406Sopenharmony_ci      s->bright_g = s->bright_b = s->bright_r;
3708141cc406Sopenharmony_ci      DBG(23, "bright_r of %d set to 0x%0x\n",
3709141cc406Sopenharmony_ci	  s->val[OPT_BRIGHTNESS].w, s->bright_r);
3710141cc406Sopenharmony_ci    } else {
3711141cc406Sopenharmony_ci      s->bright_r = s->bright_g = s->bright_b = 0;
3712141cc406Sopenharmony_ci    }
3713141cc406Sopenharmony_ci    /* figure out halftone pattern selection... */
3714141cc406Sopenharmony_ci    if (s->mode == MS_MODE_HALFTONE) {
3715141cc406Sopenharmony_ci      int i = 0;
3716141cc406Sopenharmony_ci      while ((halftone_mode_list[i] != NULL) &&
3717141cc406Sopenharmony_ci	     (strcmp(halftone_mode_list[i], s->val[OPT_HALFTONE_PATTERN].s)))
3718141cc406Sopenharmony_ci	i++;
3719141cc406Sopenharmony_ci      s->pattern = ((i < s->dev->info.pattern_count) ? i : 0);
3720141cc406Sopenharmony_ci    } else
3721141cc406Sopenharmony_ci      s->pattern = 0;
3722141cc406Sopenharmony_ci
3723141cc406Sopenharmony_ci
3724141cc406Sopenharmony_ci
3725141cc406Sopenharmony_ci    {
3726141cc406Sopenharmony_ci      /* need to 'round' things properly!  XXXXXXXX */
3727141cc406Sopenharmony_ci      SANE_Int widthpix;
3728141cc406Sopenharmony_ci      double dots_per_mm = s->resolution / MM_PER_INCH;
3729141cc406Sopenharmony_ci      double units_per_mm =
3730141cc406Sopenharmony_ci	(s->unit_type == MS_UNIT_18INCH) ?
3731141cc406Sopenharmony_ci	(8.0 / MM_PER_INCH) :                       /* 1/8 inches */
3732141cc406Sopenharmony_ci	(s->dev->info.base_resolution / MM_PER_INCH);   /* pixels     */
3733141cc406Sopenharmony_ci
3734141cc406Sopenharmony_ci      DBG(23, "sane_get_parameters:  dots_per_mm:  %f\n", dots_per_mm);
3735141cc406Sopenharmony_ci      DBG(23, "sane_get_parameters:  units_per_mm:  %f\n", units_per_mm);
3736141cc406Sopenharmony_ci
3737141cc406Sopenharmony_ci      /* calculate frame coordinates...
3738141cc406Sopenharmony_ci       *  scanner coords are in 'units' -- pixels or 1/8"
3739141cc406Sopenharmony_ci       *  option coords are MM
3740141cc406Sopenharmony_ci       */
3741141cc406Sopenharmony_ci      s->x1 = (SANE_Int)(SANE_UNFIX(s->val[OPT_TL_X].w) * units_per_mm + 0.5);
3742141cc406Sopenharmony_ci      s->y1 = (SANE_Int)(SANE_UNFIX(s->val[OPT_TL_Y].w) * units_per_mm + 0.5);
3743141cc406Sopenharmony_ci      s->x2 = (SANE_Int)(SANE_UNFIX(s->val[OPT_BR_X].w) * units_per_mm + 0.5);
3744141cc406Sopenharmony_ci      s->y2 = (SANE_Int)(SANE_UNFIX(s->val[OPT_BR_Y].w) * units_per_mm + 0.5);
3745141cc406Sopenharmony_ci      /* bug out if length or width is <= zero... */
3746141cc406Sopenharmony_ci      if ((s->x1 >= s->x2) || (s->y1 >= s->y2))
3747141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
3748141cc406Sopenharmony_ci
3749141cc406Sopenharmony_ci      /* these are just an estimate... (but *should* be completely accurate)
3750141cc406Sopenharmony_ci       * real values come from scanner after sane_start.
3751141cc406Sopenharmony_ci       */
3752141cc406Sopenharmony_ci      if (s->unit_type == MS_UNIT_18INCH) {
3753141cc406Sopenharmony_ci	/* who *knows* what happens */
3754141cc406Sopenharmony_ci	widthpix =
3755141cc406Sopenharmony_ci	  (SANE_Int)((double)(s->x2 - s->x1 + 1) / 8.0 *
3756141cc406Sopenharmony_ci		     (double)s->resolution);
3757141cc406Sopenharmony_ci	s->params.lines =
3758141cc406Sopenharmony_ci	  (SANE_Int)((double)(s->y2 - s->y1 + 1) / 8.0 *
3759141cc406Sopenharmony_ci		     (double)s->resolution);
3760141cc406Sopenharmony_ci      } else {
3761141cc406Sopenharmony_ci	/* calculate pixels per scanline returned by scanner... */
3762141cc406Sopenharmony_ci	/* scanner (E6 at least) always seems to return
3763141cc406Sopenharmony_ci	   an -even- number of -bytes- */
3764141cc406Sopenharmony_ci	if (s->resolution <= s->dev->info.base_resolution)
3765141cc406Sopenharmony_ci	  widthpix =
3766141cc406Sopenharmony_ci	    (SANE_Int)((double)(s->x2 - s->x1 + 1) *
3767141cc406Sopenharmony_ci		       (double)(s->resolution) /
3768141cc406Sopenharmony_ci		       (double)(s->dev->info.base_resolution));
3769141cc406Sopenharmony_ci	else
3770141cc406Sopenharmony_ci	  widthpix = (s->x2 - s->x1 + 1);
3771141cc406Sopenharmony_ci	if ((s->mode == MS_MODE_LINEART) ||
3772141cc406Sopenharmony_ci	    (s->mode == MS_MODE_HALFTONE)) {
3773141cc406Sopenharmony_ci	  DBG(23, "WIDTHPIX:  before: %d", widthpix);
3774141cc406Sopenharmony_ci	  widthpix = ((widthpix / 8) & ~0x1) * 8;
3775141cc406Sopenharmony_ci	  DBG(23, "after: %d", widthpix);
3776141cc406Sopenharmony_ci	} else {
3777141cc406Sopenharmony_ci	  widthpix = widthpix & ~0x1;
3778141cc406Sopenharmony_ci	}
3779141cc406Sopenharmony_ci	DBG(23, "WIDTHPIX:  before exp: %d\n", widthpix);
3780141cc406Sopenharmony_ci	/* ok, now fix up expanded-mode conversions */
3781141cc406Sopenharmony_ci	if (s->resolution > s->dev->info.base_resolution)
3782141cc406Sopenharmony_ci	  widthpix = (SANE_Int) ((double)widthpix *
3783141cc406Sopenharmony_ci				 (double)s->resolution /
3784141cc406Sopenharmony_ci				 (double)s->dev->info.base_resolution);
3785141cc406Sopenharmony_ci	s->params.pixels_per_line = widthpix;
3786141cc406Sopenharmony_ci	s->params.lines =
3787141cc406Sopenharmony_ci	  (SANE_Int)((double)(s->y2 - s->y1 + 1) *
3788141cc406Sopenharmony_ci		     (double)(s->resolution) /
3789141cc406Sopenharmony_ci		     (double)(s->dev->info.base_resolution));
3790141cc406Sopenharmony_ci      }
3791141cc406Sopenharmony_ci    }
3792141cc406Sopenharmony_ci
3793141cc406Sopenharmony_ci    switch (s->mode) {
3794141cc406Sopenharmony_ci    case MS_MODE_LINEART:
3795141cc406Sopenharmony_ci    case MS_MODE_HALFTONE:
3796141cc406Sopenharmony_ci      s->multibit = SANE_FALSE;
3797141cc406Sopenharmony_ci      s->params.format = SANE_FRAME_GRAY;
3798141cc406Sopenharmony_ci      s->params.depth = 1;
3799141cc406Sopenharmony_ci      s->filter = MS_FILT_CLEAR;
3800141cc406Sopenharmony_ci      s->params.bytes_per_line = s->params.pixels_per_line / 8;
3801141cc406Sopenharmony_ci      break;
3802141cc406Sopenharmony_ci    case MS_MODE_GRAY:
3803141cc406Sopenharmony_ci      s->multibit = SANE_TRUE;
3804141cc406Sopenharmony_ci      s->params.format = SANE_FRAME_GRAY;
3805141cc406Sopenharmony_ci      s->params.depth = s->bits_per_color;
3806141cc406Sopenharmony_ci      s->filter = MS_FILT_CLEAR;
3807141cc406Sopenharmony_ci      s->params.bytes_per_line = s->params.pixels_per_line;
3808141cc406Sopenharmony_ci      break;
3809141cc406Sopenharmony_ci    case MS_MODE_COLOR:
3810141cc406Sopenharmony_ci      s->multibit = SANE_TRUE;
3811141cc406Sopenharmony_ci      if (s->onepasscolor) { /* a single-pass color scan */
3812141cc406Sopenharmony_ci	s->params.format = SANE_FRAME_RGB;
3813141cc406Sopenharmony_ci	s->params.depth = s->bits_per_color;
3814141cc406Sopenharmony_ci	s->filter = MS_FILT_CLEAR;
3815141cc406Sopenharmony_ci	s->params.bytes_per_line = s->params.pixels_per_line * 3;
3816141cc406Sopenharmony_ci      } else { /* a three-pass color scan */
3817141cc406Sopenharmony_ci	s->params.depth = s->bits_per_color;
3818141cc406Sopenharmony_ci	/* this will be correctly set in sane_start */
3819141cc406Sopenharmony_ci	s->params.format = SANE_FRAME_RED;
3820141cc406Sopenharmony_ci	s->params.bytes_per_line = s->params.pixels_per_line;
3821141cc406Sopenharmony_ci      }
3822141cc406Sopenharmony_ci      break;
3823141cc406Sopenharmony_ci    }
3824141cc406Sopenharmony_ci
3825141cc406Sopenharmony_ci    DBG(23, "sane_get_parameters:  lines: %d  ppl: %d  bpl: %d\n",
3826141cc406Sopenharmony_ci	s->params.lines, s->params.pixels_per_line, s->params.bytes_per_line);
3827141cc406Sopenharmony_ci
3828141cc406Sopenharmony_ci    /* also fixed in sane_start for multi-pass scans */
3829141cc406Sopenharmony_ci    s->params.last_frame = SANE_TRUE;  /* ?? XXXXXXXX */
3830141cc406Sopenharmony_ci  }
3831141cc406Sopenharmony_ci
3832141cc406Sopenharmony_ci  if (params)
3833141cc406Sopenharmony_ci    *params = s->params;
3834141cc406Sopenharmony_ci
3835141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3836141cc406Sopenharmony_ci}
3837141cc406Sopenharmony_ci
3838141cc406Sopenharmony_ci
3839141cc406Sopenharmony_ci
3840141cc406Sopenharmony_ci/********************************************************************/
3841141cc406Sopenharmony_ci/* sane_start                                                       */
3842141cc406Sopenharmony_ci/********************************************************************/
3843141cc406Sopenharmony_cistatic SANE_Status
3844141cc406Sopenharmony_cisane_start_guts (SANE_Handle handle)
3845141cc406Sopenharmony_ci{
3846141cc406Sopenharmony_ci  Microtek_Scanner *s = handle;
3847141cc406Sopenharmony_ci  SANE_Status status;
3848141cc406Sopenharmony_ci  SANE_Int busy, linewidth;
3849141cc406Sopenharmony_ci
3850141cc406Sopenharmony_ci  DBG(10, "sane_start...\n");
3851141cc406Sopenharmony_ci
3852141cc406Sopenharmony_ci  if (s->sfd != -1) {
3853141cc406Sopenharmony_ci    DBG(23, "sane_start:  sfd already set!\n");
3854141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
3855141cc406Sopenharmony_ci  }
3856141cc406Sopenharmony_ci
3857141cc406Sopenharmony_ci  if ((status = sane_get_parameters(s, 0)) != SANE_STATUS_GOOD)
3858141cc406Sopenharmony_ci    return end_scan(s, status);
3859141cc406Sopenharmony_ci  set_pass_parameters(s);
3860141cc406Sopenharmony_ci
3861141cc406Sopenharmony_ci  s->scanning = SANE_TRUE;
3862141cc406Sopenharmony_ci  s->cancel = SANE_FALSE;
3863141cc406Sopenharmony_ci
3864141cc406Sopenharmony_ci  status = sanei_scsi_open(s->dev->sane.name,
3865141cc406Sopenharmony_ci			   &(s->sfd),
3866141cc406Sopenharmony_ci			   sense_handler,
3867141cc406Sopenharmony_ci			   &(s->sense_flags));
3868141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD) {
3869141cc406Sopenharmony_ci    DBG(10, "sane_start: open of %s failed: %s\n",
3870141cc406Sopenharmony_ci	s->dev->sane.name, sane_strstatus (status));
3871141cc406Sopenharmony_ci    s->sfd = -1;
3872141cc406Sopenharmony_ci    return end_scan(s, status);
3873141cc406Sopenharmony_ci  }
3874141cc406Sopenharmony_ci
3875141cc406Sopenharmony_ci  if ((status = wait_ready(s)) != SANE_STATUS_GOOD) return end_scan(s, status);
3876141cc406Sopenharmony_ci
3877141cc406Sopenharmony_ci  if ((status = finagle_precal(s)) != SANE_STATUS_GOOD)
3878141cc406Sopenharmony_ci    return end_scan(s, status);
3879141cc406Sopenharmony_ci
3880141cc406Sopenharmony_ci  if ((status = scanning_frame(s)) != SANE_STATUS_GOOD) return end_scan(s, status);
3881141cc406Sopenharmony_ci  if (s->dev->info.source_options &
3882141cc406Sopenharmony_ci      (MI_SRC_FEED_BT | MI_SRC_HAS_TRANS |
3883141cc406Sopenharmony_ci       MI_SRC_FEED_SUPP | MI_SRC_HAS_FEED)) { /* ZZZZZZZZZZZ */
3884141cc406Sopenharmony_ci    if ((status = accessory(s)) != SANE_STATUS_GOOD) return end_scan(s, status);
3885141cc406Sopenharmony_ci    /* if SWslct ????  XXXXXXXXXXXXXXX */
3886141cc406Sopenharmony_ci  }
3887141cc406Sopenharmony_ci  if ((status = download_gamma(s)) != SANE_STATUS_GOOD)
3888141cc406Sopenharmony_ci    return end_scan(s, status);
3889141cc406Sopenharmony_ci  if ((status = mode_select(s)) != SANE_STATUS_GOOD)
3890141cc406Sopenharmony_ci    return end_scan(s, status);
3891141cc406Sopenharmony_ci  if (s->dev->info.does_mode1) {
3892141cc406Sopenharmony_ci    if ((status = mode_select_1(s)) != SANE_STATUS_GOOD)
3893141cc406Sopenharmony_ci      return end_scan(s, status);
3894141cc406Sopenharmony_ci  }
3895141cc406Sopenharmony_ci  if ((s->do_clever_precal) || (s->do_real_calib)) {
3896141cc406Sopenharmony_ci    if ((status = save_mode_sense(s)) != SANE_STATUS_GOOD)
3897141cc406Sopenharmony_ci      return end_scan(s, status);
3898141cc406Sopenharmony_ci  }
3899141cc406Sopenharmony_ci  if ((status = wait_ready(s)) != SANE_STATUS_GOOD) return end_scan(s, status);
3900141cc406Sopenharmony_ci  s->scan_started = SANE_TRUE;
3901141cc406Sopenharmony_ci  if ((status = start_scan(s)) != SANE_STATUS_GOOD) return end_scan(s, status);
3902141cc406Sopenharmony_ci  if ((status = get_scan_status(s, &busy,
3903141cc406Sopenharmony_ci				&linewidth, &(s->unscanned_lines))) !=
3904141cc406Sopenharmony_ci      SANE_STATUS_GOOD) {
3905141cc406Sopenharmony_ci    DBG(10, "sane_start:  get_scan_status fails\n");
3906141cc406Sopenharmony_ci    return end_scan(s, status);
3907141cc406Sopenharmony_ci  }
3908141cc406Sopenharmony_ci  /* check for a bizarre linecount */
3909141cc406Sopenharmony_ci  if ((s->unscanned_lines < 0) ||
3910141cc406Sopenharmony_ci      (s->unscanned_lines >
3911141cc406Sopenharmony_ci       (s->params.lines * 2 * (s->expandedresolution ? 2 : 1)))) {
3912141cc406Sopenharmony_ci    DBG(10, "sane_start:  get_scan_status returns weird line count %d\n",
3913141cc406Sopenharmony_ci	s->unscanned_lines);
3914141cc406Sopenharmony_ci    return end_scan(s, SANE_STATUS_DEVICE_BUSY);
3915141cc406Sopenharmony_ci  }
3916141cc406Sopenharmony_ci
3917141cc406Sopenharmony_ci
3918141cc406Sopenharmony_ci  /* figure out image format parameters */
3919141cc406Sopenharmony_ci  switch (s->mode) {
3920141cc406Sopenharmony_ci  case MS_MODE_LINEART:
3921141cc406Sopenharmony_ci  case MS_MODE_HALFTONE:
3922141cc406Sopenharmony_ci    s->pixel_bpl = linewidth;
3923141cc406Sopenharmony_ci    s->header_bpl = 0;
3924141cc406Sopenharmony_ci    s->ppl = linewidth * 8;
3925141cc406Sopenharmony_ci    s->planes = 1;
3926141cc406Sopenharmony_ci    s->line_format = MS_LNFMT_FLAT;
3927141cc406Sopenharmony_ci    break;
3928141cc406Sopenharmony_ci  case MS_MODE_GRAY:
3929141cc406Sopenharmony_ci    if (s->bits_per_color < 8) {
3930141cc406Sopenharmony_ci      s->pixel_bpl = linewidth;
3931141cc406Sopenharmony_ci      s->ppl = linewidth * (8 / s->bits_per_color);
3932141cc406Sopenharmony_ci    }	else {
3933141cc406Sopenharmony_ci      s->pixel_bpl = linewidth * ((s->bits_per_color + 7) / 8);
3934141cc406Sopenharmony_ci      s->ppl = linewidth;
3935141cc406Sopenharmony_ci    }
3936141cc406Sopenharmony_ci    s->header_bpl = 0;
3937141cc406Sopenharmony_ci    s->planes = 1;
3938141cc406Sopenharmony_ci    s->line_format = MS_LNFMT_FLAT;
3939141cc406Sopenharmony_ci    break;
3940141cc406Sopenharmony_ci  case MS_MODE_COLOR:
3941141cc406Sopenharmony_ci    switch (s->color_seq) {
3942141cc406Sopenharmony_ci    case MI_COLSEQ_PLANE:
3943141cc406Sopenharmony_ci      s->pixel_bpl = linewidth * ((s->bits_per_color + 7) / 8);
3944141cc406Sopenharmony_ci      s->ppl = linewidth;
3945141cc406Sopenharmony_ci      s->header_bpl = 0;
3946141cc406Sopenharmony_ci      s->planes = 1;
3947141cc406Sopenharmony_ci      s->line_format = MS_LNFMT_FLAT;
3948141cc406Sopenharmony_ci      break;
3949141cc406Sopenharmony_ci    case MI_COLSEQ_NONRGB:
3950141cc406Sopenharmony_ci      s->pixel_bpl = (linewidth - 2) * 3 * ((s->bits_per_color + 7) / 8);
3951141cc406Sopenharmony_ci      s->ppl = linewidth - 2;
3952141cc406Sopenharmony_ci      s->header_bpl = 2 * 3;
3953141cc406Sopenharmony_ci      s->planes = 3;
3954141cc406Sopenharmony_ci      s->line_format = MS_LNFMT_GOOFY_RGB;
3955141cc406Sopenharmony_ci      break;
3956141cc406Sopenharmony_ci    case MI_COLSEQ_PIXEL:
3957141cc406Sopenharmony_ci      s->pixel_bpl = linewidth * 3 * ((s->bits_per_color + 7) / 8);
3958141cc406Sopenharmony_ci      s->ppl = linewidth;
3959141cc406Sopenharmony_ci      s->header_bpl = 0;
3960141cc406Sopenharmony_ci      s->planes = 3;
3961141cc406Sopenharmony_ci      s->line_format = MS_LNFMT_FLAT;
3962141cc406Sopenharmony_ci      break;
3963141cc406Sopenharmony_ci    case MI_COLSEQ_2PIXEL:
3964141cc406Sopenharmony_ci      s->pixel_bpl = linewidth * 3 * ((s->bits_per_color + 7) / 8);
3965141cc406Sopenharmony_ci      s->ppl = linewidth;
3966141cc406Sopenharmony_ci      s->header_bpl = 0;
3967141cc406Sopenharmony_ci      s->planes = 3;
3968141cc406Sopenharmony_ci      s->line_format = MS_LNFMT_SEQ_2R2G2B;
3969141cc406Sopenharmony_ci      break;
3970141cc406Sopenharmony_ci    case MI_COLSEQ_RGB:
3971141cc406Sopenharmony_ci      s->pixel_bpl = linewidth * 3 * ((s->bits_per_color + 7) / 8);
3972141cc406Sopenharmony_ci      s->ppl = linewidth;
3973141cc406Sopenharmony_ci      s->header_bpl = 0;
3974141cc406Sopenharmony_ci      s->planes = 3;
3975141cc406Sopenharmony_ci      s->line_format = MS_LNFMT_SEQ_RGB;
3976141cc406Sopenharmony_ci      break;
3977141cc406Sopenharmony_ci    default:
3978141cc406Sopenharmony_ci      DBG(10, "sane_start:  Unknown color_sequence: %d\n",
3979141cc406Sopenharmony_ci	  s->dev->info.color_sequence);
3980141cc406Sopenharmony_ci      return end_scan(s, SANE_STATUS_INVAL);
3981141cc406Sopenharmony_ci    }
3982141cc406Sopenharmony_ci    break;
3983141cc406Sopenharmony_ci  default:
3984141cc406Sopenharmony_ci    DBG(10, "sane_start:  Unknown scan mode: %d\n", s->mode);
3985141cc406Sopenharmony_ci    return end_scan(s, SANE_STATUS_INVAL);
3986141cc406Sopenharmony_ci  }
3987141cc406Sopenharmony_ci
3988141cc406Sopenharmony_ci  if ((s->doexpansion) &&
3989141cc406Sopenharmony_ci      (s->resolution > s->dev->info.base_resolution)) {
3990141cc406Sopenharmony_ci    s->dest_ppl = (int) ((double)s->ppl *
3991141cc406Sopenharmony_ci			 (double)s->resolution /
3992141cc406Sopenharmony_ci			 (double)s->dev->info.base_resolution);
3993141cc406Sopenharmony_ci    /*+ 0.5 XXXXXX */
3994141cc406Sopenharmony_ci    s->exp_aspect = (double)s->ppl / (double)s->dest_ppl;
3995141cc406Sopenharmony_ci    s->dest_pixel_bpl = (int) ceil((double)s->pixel_bpl / s->exp_aspect);
3996141cc406Sopenharmony_ci    /*s->exp_aspect =
3997141cc406Sopenharmony_ci      (double) s->dev->info.base_resolution / (double) s->resolution;*/
3998141cc406Sopenharmony_ci    /* s->dest_pixel_bpl = s->pixel_bpl / s->exp_aspect;
3999141cc406Sopenharmony_ci       s->dest_ppl = s->ppl / s->exp_aspect;*/
4000141cc406Sopenharmony_ci    /*s->dest_ppl = s->ppl / s->exp_aspect;
4001141cc406Sopenharmony_ci      s->dest_pixel_bpl = (int) ceil((double)s->dest_ppl *
4002141cc406Sopenharmony_ci      (double)s->pixel_bpl /
4003141cc406Sopenharmony_ci      (double)s->ppl);*/
4004141cc406Sopenharmony_ci  } else {
4005141cc406Sopenharmony_ci    s->exp_aspect = 1.0;
4006141cc406Sopenharmony_ci    s->dest_pixel_bpl = s->pixel_bpl;
4007141cc406Sopenharmony_ci    s->dest_ppl = s->ppl;
4008141cc406Sopenharmony_ci  }
4009141cc406Sopenharmony_ci
4010141cc406Sopenharmony_ci  s->params.lines = s->unscanned_lines;
4011141cc406Sopenharmony_ci  s->params.pixels_per_line = s->dest_ppl;
4012141cc406Sopenharmony_ci  s->params.bytes_per_line = s->dest_pixel_bpl;
4013141cc406Sopenharmony_ci
4014141cc406Sopenharmony_ci  /* calculate maximum line capacity of SCSI buffer */
4015141cc406Sopenharmony_ci  s->max_scsi_lines = SCSI_BUFF_SIZE / (s->pixel_bpl + s->header_bpl);
4016141cc406Sopenharmony_ci  if (s->max_scsi_lines < 1) {
4017141cc406Sopenharmony_ci    DBG(10, "sane_start:  SCSI buffer smaller that one scan line!\n");
4018141cc406Sopenharmony_ci    return end_scan(s, SANE_STATUS_NO_MEM);
4019141cc406Sopenharmony_ci  }
4020141cc406Sopenharmony_ci
4021141cc406Sopenharmony_ci  s->scsi_buffer = (uint8_t *) malloc(SCSI_BUFF_SIZE * sizeof(uint8_t));
4022141cc406Sopenharmony_ci  if (s->scsi_buffer == NULL) return SANE_STATUS_NO_MEM;
4023141cc406Sopenharmony_ci
4024141cc406Sopenharmony_ci  /* what's a good initial size for this? */
4025141cc406Sopenharmony_ci  s->rb = ring_alloc(s->max_scsi_lines * s->dest_pixel_bpl,
4026141cc406Sopenharmony_ci      s->dest_pixel_bpl, s->dest_ppl);
4027141cc406Sopenharmony_ci
4028141cc406Sopenharmony_ci  s->undelivered_bytes = s->unscanned_lines * s->dest_pixel_bpl;
4029141cc406Sopenharmony_ci
4030141cc406Sopenharmony_ci  DBG(23, "Scan Param:\n");
4031141cc406Sopenharmony_ci  DBG(23, "pix bpl: %d    hdr bpl: %d   ppl: %d\n",
4032141cc406Sopenharmony_ci      s->pixel_bpl, s->header_bpl, s->ppl);
4033141cc406Sopenharmony_ci  DBG(23, "undel bytes: %d   unscan lines: %d   planes: %d\n",
4034141cc406Sopenharmony_ci      s->undelivered_bytes, s->unscanned_lines, s->planes);
4035141cc406Sopenharmony_ci  DBG(23, "dest bpl: %d   dest ppl: %d  aspect: %f\n",
4036141cc406Sopenharmony_ci      s->dest_pixel_bpl, s->dest_ppl, s->exp_aspect);
4037141cc406Sopenharmony_ci
4038141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4039141cc406Sopenharmony_ci}
4040141cc406Sopenharmony_ci
4041141cc406Sopenharmony_ci
4042141cc406Sopenharmony_ciSANE_Status
4043141cc406Sopenharmony_cisane_start (SANE_Handle handle)
4044141cc406Sopenharmony_ci{
4045141cc406Sopenharmony_ci  Microtek_Scanner *s = handle;
4046141cc406Sopenharmony_ci  SANE_Status status;
4047141cc406Sopenharmony_ci
4048141cc406Sopenharmony_ci  s->woe = SANE_TRUE;
4049141cc406Sopenharmony_ci  status = sane_start_guts(handle);
4050141cc406Sopenharmony_ci  s->woe = SANE_FALSE;
4051141cc406Sopenharmony_ci  return status;
4052141cc406Sopenharmony_ci}
4053141cc406Sopenharmony_ci
4054141cc406Sopenharmony_ci
4055141cc406Sopenharmony_ci
4056141cc406Sopenharmony_ci/********************************************************************/
4057141cc406Sopenharmony_ci/* sane_read                                                        */
4058141cc406Sopenharmony_ci/********************************************************************/
4059141cc406Sopenharmony_cistatic SANE_Status
4060141cc406Sopenharmony_cisane_read_guts (SANE_Handle handle, SANE_Byte *dest_buffer,
4061141cc406Sopenharmony_ci		SANE_Int dest_length, SANE_Int *ret_length)
4062141cc406Sopenharmony_ci{
4063141cc406Sopenharmony_ci  Microtek_Scanner *s = handle;
4064141cc406Sopenharmony_ci  SANE_Status status;
4065141cc406Sopenharmony_ci  int nlines;
4066141cc406Sopenharmony_ci  ring_buffer *rb = s->rb;
4067141cc406Sopenharmony_ci
4068141cc406Sopenharmony_ci  DBG(10, "sane_read...\n");
4069141cc406Sopenharmony_ci
4070141cc406Sopenharmony_ci  *ret_length = 0; /* default: no data */
4071141cc406Sopenharmony_ci  /* we have been cancelled... */
4072141cc406Sopenharmony_ci  if (s->cancel) return end_scan(s, SANE_STATUS_CANCELLED);
4073141cc406Sopenharmony_ci  /* we're not really scanning!... */
4074141cc406Sopenharmony_ci  if (!(s->scanning)) return SANE_STATUS_INVAL;
4075141cc406Sopenharmony_ci  /* we are done scanning... */
4076141cc406Sopenharmony_ci  if (s->undelivered_bytes <= 0) return end_scan(s, SANE_STATUS_EOF);
4077141cc406Sopenharmony_ci
4078141cc406Sopenharmony_ci  /* get more bytes if our ring is empty... */
4079141cc406Sopenharmony_ci  while (rb->complete_count == 0) {
4080141cc406Sopenharmony_ci    if ((status = read_from_scanner(s, &nlines)) != SANE_STATUS_GOOD) {
4081141cc406Sopenharmony_ci      DBG(18, "sane_read:  read_from_scanner failed.\n");
4082141cc406Sopenharmony_ci      return end_scan(s, status);
4083141cc406Sopenharmony_ci    }
4084141cc406Sopenharmony_ci    if ((status = pack_into_ring(s, nlines)) != SANE_STATUS_GOOD) {
4085141cc406Sopenharmony_ci      DBG(18, "sane_read:  pack_into_ring failed.\n");
4086141cc406Sopenharmony_ci      return end_scan(s, status);
4087141cc406Sopenharmony_ci    }
4088141cc406Sopenharmony_ci  }
4089141cc406Sopenharmony_ci  /* return some data to caller */
4090141cc406Sopenharmony_ci  *ret_length = pack_into_dest(dest_buffer, dest_length, rb);
4091141cc406Sopenharmony_ci  s->undelivered_bytes -= *ret_length;
4092141cc406Sopenharmony_ci
4093141cc406Sopenharmony_ci  if (s->cancel) return end_scan(s, SANE_STATUS_CANCELLED);
4094141cc406Sopenharmony_ci
4095141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
4096141cc406Sopenharmony_ci}
4097141cc406Sopenharmony_ci
4098141cc406Sopenharmony_ci
4099141cc406Sopenharmony_ciSANE_Status
4100141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte *dest_buffer,
4101141cc406Sopenharmony_ci	   SANE_Int dest_length, SANE_Int *ret_length)
4102141cc406Sopenharmony_ci{
4103141cc406Sopenharmony_ci  Microtek_Scanner *s = handle;
4104141cc406Sopenharmony_ci  SANE_Status status;
4105141cc406Sopenharmony_ci
4106141cc406Sopenharmony_ci  s->woe = SANE_TRUE;
4107141cc406Sopenharmony_ci  status = sane_read_guts(handle, dest_buffer, dest_length, ret_length);
4108141cc406Sopenharmony_ci  s->woe = SANE_FALSE;
4109141cc406Sopenharmony_ci  return status;
4110141cc406Sopenharmony_ci}
4111141cc406Sopenharmony_ci
4112141cc406Sopenharmony_ci
4113141cc406Sopenharmony_ci
4114141cc406Sopenharmony_ci/********************************************************************/
4115141cc406Sopenharmony_ci/* sane_exit                                                        */
4116141cc406Sopenharmony_ci/********************************************************************/
4117141cc406Sopenharmony_civoid
4118141cc406Sopenharmony_cisane_exit (void)
4119141cc406Sopenharmony_ci{
4120141cc406Sopenharmony_ci  Microtek_Device *next;
4121141cc406Sopenharmony_ci
4122141cc406Sopenharmony_ci  DBG(10, "sane_exit...\n");
4123141cc406Sopenharmony_ci  /* close all leftover Scanners */
4124141cc406Sopenharmony_ci  /*(beware of how sane_close interacts with linked list) */
4125141cc406Sopenharmony_ci  while (first_handle != NULL)
4126141cc406Sopenharmony_ci    sane_close(first_handle);
4127141cc406Sopenharmony_ci  /* free up device list */
4128141cc406Sopenharmony_ci  while (first_dev != NULL) {
4129141cc406Sopenharmony_ci    next = first_dev->next;
4130141cc406Sopenharmony_ci    free((void *) first_dev->sane.name);
4131141cc406Sopenharmony_ci    free((void *) first_dev->sane.model);
4132141cc406Sopenharmony_ci    free(first_dev);
4133141cc406Sopenharmony_ci    first_dev = next;
4134141cc406Sopenharmony_ci  }
4135141cc406Sopenharmony_ci  /* the devlist allocated by sane_get_devices */
4136141cc406Sopenharmony_ci  free(devlist);
4137141cc406Sopenharmony_ci  DBG(10, "sane_exit:  MICROTEK says goodbye.\n");
4138141cc406Sopenharmony_ci}
4139141cc406Sopenharmony_ci
4140141cc406Sopenharmony_ci
4141141cc406Sopenharmony_ci
4142141cc406Sopenharmony_ci/********************************************************************/
4143141cc406Sopenharmony_ci/* sane_cancel                                                      */
4144141cc406Sopenharmony_ci/********************************************************************/
4145141cc406Sopenharmony_civoid
4146141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
4147141cc406Sopenharmony_ci{
4148141cc406Sopenharmony_ci  Microtek_Scanner *ms = handle;
4149141cc406Sopenharmony_ci  DBG(10, "sane_cancel...\n");
4150141cc406Sopenharmony_ci  ms->cancel = SANE_TRUE;
4151141cc406Sopenharmony_ci  if (!(ms->woe)) end_scan(ms, SANE_STATUS_CANCELLED);
4152141cc406Sopenharmony_ci}
4153141cc406Sopenharmony_ci
4154141cc406Sopenharmony_ci
4155141cc406Sopenharmony_ci
4156141cc406Sopenharmony_ci/********************************************************************/
4157141cc406Sopenharmony_ci/* sane_set_io_mode                                                 */
4158141cc406Sopenharmony_ci/********************************************************************/
4159141cc406Sopenharmony_ciSANE_Status
4160141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
4161141cc406Sopenharmony_ci{
4162141cc406Sopenharmony_ci  DBG(10, "sane_set_io_mode...\n");
4163141cc406Sopenharmony_ci  (void) handle;
4164141cc406Sopenharmony_ci  if (non_blocking)
4165141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
4166141cc406Sopenharmony_ci  else
4167141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4168141cc406Sopenharmony_ci}
4169141cc406Sopenharmony_ci
4170141cc406Sopenharmony_ci
4171141cc406Sopenharmony_ci
4172141cc406Sopenharmony_ci/********************************************************************/
4173141cc406Sopenharmony_ci/* sane_get_select_fd                                               */
4174141cc406Sopenharmony_ci/********************************************************************/
4175141cc406Sopenharmony_ciSANE_Status
4176141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
4177141cc406Sopenharmony_ci{
4178141cc406Sopenharmony_ci  DBG(10, "sane_get_select_fd...\n");
4179141cc406Sopenharmony_ci  (void) handle, (void) fd;
4180141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
4181141cc406Sopenharmony_ci}
4182