1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   ScanMaker 3840 Backend
4141cc406Sopenharmony_ci   Copyright (C) 2005-7 Earle F. Philhower, III
5141cc406Sopenharmony_ci   earle@ziplabel.com - http://www.ziplabel.com
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
8141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
9141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
10141cc406Sopenharmony_ci   License, or (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
13141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
14141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15141cc406Sopenharmony_ci   General Public License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
21141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
24141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
25141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
26141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
27141cc406Sopenharmony_ci   account of linking the SANE library code into it.
28141cc406Sopenharmony_ci
29141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
30141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
31141cc406Sopenharmony_ci   License.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
34141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
35141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
38141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
39141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci*/
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci#include <stdio.h>
44141cc406Sopenharmony_ci#include <stdarg.h>
45141cc406Sopenharmony_ci#include <math.h>
46141cc406Sopenharmony_ci#include "sm3840_lib.h"
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci#ifndef BACKENDNAME
49141cc406Sopenharmony_ci/* For standalone compilation */
50141cc406Sopenharmony_cistatic void
51141cc406Sopenharmony_ciDBG (int ignored, const char *fmt, ...)
52141cc406Sopenharmony_ci{
53141cc406Sopenharmony_ci  va_list a;
54141cc406Sopenharmony_ci  va_start (a, fmt);
55141cc406Sopenharmony_ci  vfprintf (stderr, fmt, a);
56141cc406Sopenharmony_ci  va_end (a);
57141cc406Sopenharmony_ci}
58141cc406Sopenharmony_ci#else
59141cc406Sopenharmony_ci/* For SANE compilation, convert libusb to sanei_usb */
60141cc406Sopenharmony_cistatic int
61141cc406Sopenharmony_cimy_usb_bulk_write (p_usb_dev_handle dev, int ep,
62141cc406Sopenharmony_ci		   unsigned char *bytes, int size, int timeout)
63141cc406Sopenharmony_ci{
64141cc406Sopenharmony_ci  SANE_Status status;
65141cc406Sopenharmony_ci  size_t my_size;
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci  (void) timeout;
68141cc406Sopenharmony_ci  (void) ep;
69141cc406Sopenharmony_ci  my_size = size;
70141cc406Sopenharmony_ci  status =
71141cc406Sopenharmony_ci    sanei_usb_write_bulk ((SANE_Int) dev, (SANE_Byte *) bytes, &my_size);
72141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
73141cc406Sopenharmony_ci    my_size = -1;
74141cc406Sopenharmony_ci  return my_size;
75141cc406Sopenharmony_ci}
76141cc406Sopenharmony_ci
77141cc406Sopenharmony_cistatic int
78141cc406Sopenharmony_cimy_usb_bulk_read (p_usb_dev_handle dev, int ep,
79141cc406Sopenharmony_ci		  unsigned char *bytes, int size, int timeout)
80141cc406Sopenharmony_ci{
81141cc406Sopenharmony_ci  SANE_Status status;
82141cc406Sopenharmony_ci  size_t my_size;
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci  (void) timeout;
85141cc406Sopenharmony_ci  (void) ep;
86141cc406Sopenharmony_ci  my_size = size;
87141cc406Sopenharmony_ci  status =
88141cc406Sopenharmony_ci    sanei_usb_read_bulk ((SANE_Int) dev, (SANE_Byte *) bytes, &my_size);
89141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
90141cc406Sopenharmony_ci    my_size = -1;
91141cc406Sopenharmony_ci  return my_size;
92141cc406Sopenharmony_ci}
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_cistatic int
95141cc406Sopenharmony_cimy_usb_control_msg (p_usb_dev_handle dev, int requesttype,
96141cc406Sopenharmony_ci		    int request, int value, int index,
97141cc406Sopenharmony_ci		    unsigned char *bytes, int size, int timeout)
98141cc406Sopenharmony_ci{
99141cc406Sopenharmony_ci  SANE_Status status;
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_ci  (void) timeout;
102141cc406Sopenharmony_ci  status = sanei_usb_control_msg ((SANE_Int) dev, (SANE_Int) requesttype,
103141cc406Sopenharmony_ci				  (SANE_Int) request, (SANE_Int) value,
104141cc406Sopenharmony_ci				  (SANE_Int) index, (SANE_Int) size,
105141cc406Sopenharmony_ci				  (SANE_Byte *) bytes);
106141cc406Sopenharmony_ci  return status;
107141cc406Sopenharmony_ci}
108141cc406Sopenharmony_ci#endif
109141cc406Sopenharmony_ci
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci/* Sanitize and convert scan parameters from inches to pixels */
112141cc406Sopenharmony_cistatic void
113141cc406Sopenharmony_ciprepare_params (SM3840_Params * params)
114141cc406Sopenharmony_ci{
115141cc406Sopenharmony_ci  if (params->gray)
116141cc406Sopenharmony_ci    params->gray = 1;
117141cc406Sopenharmony_ci  if (params->lineart) {
118141cc406Sopenharmony_ci    params->gray = 1;
119141cc406Sopenharmony_ci    params->lineart = 1;
120141cc406Sopenharmony_ci  }
121141cc406Sopenharmony_ci  if (params->halftone) {
122141cc406Sopenharmony_ci    params->gray = 1;
123141cc406Sopenharmony_ci    params->halftone = 1;
124141cc406Sopenharmony_ci  }
125141cc406Sopenharmony_ci  if (params->dpi != 1200 && params->dpi != 600 && params->dpi != 300
126141cc406Sopenharmony_ci      && params->dpi != 150)
127141cc406Sopenharmony_ci    params->dpi = 150;
128141cc406Sopenharmony_ci  if (params->bpp != 8 && params->bpp != 16)
129141cc406Sopenharmony_ci    params->bpp = 8;
130141cc406Sopenharmony_ci
131141cc406Sopenharmony_ci  /* Sanity check input sizes */
132141cc406Sopenharmony_ci  if (params->top < 0)
133141cc406Sopenharmony_ci    params->top = 0;
134141cc406Sopenharmony_ci  if (params->left < 0)
135141cc406Sopenharmony_ci    params->left = 0;
136141cc406Sopenharmony_ci  if (params->width < 0)
137141cc406Sopenharmony_ci    params->width = 0;
138141cc406Sopenharmony_ci  if (params->height < 0)
139141cc406Sopenharmony_ci    params->height = 0;
140141cc406Sopenharmony_ci  if ((params->top + params->height) > 11.7)
141141cc406Sopenharmony_ci    params->height = 11.7 - params->top;
142141cc406Sopenharmony_ci  if ((params->left + params->width) > 8.5)
143141cc406Sopenharmony_ci    params->width = 8.5 - params->left;
144141cc406Sopenharmony_ci
145141cc406Sopenharmony_ci  params->topline = params->top * params->dpi;
146141cc406Sopenharmony_ci  params->scanlines = params->height * params->dpi;
147141cc406Sopenharmony_ci  params->leftpix = params->left * params->dpi;
148141cc406Sopenharmony_ci  params->leftpix &= ~1;	/* Always start on even pixel boundary for remap */
149141cc406Sopenharmony_ci  /* Scanpix always a multiple of 128 */
150141cc406Sopenharmony_ci  params->scanpix = params->width * params->dpi;
151141cc406Sopenharmony_ci  params->scanpix = (params->scanpix + 127) & ~127;
152141cc406Sopenharmony_ci
153141cc406Sopenharmony_ci  /* Sanity check outputs... */
154141cc406Sopenharmony_ci  if (params->topline < 0)
155141cc406Sopenharmony_ci    params->topline = 0;
156141cc406Sopenharmony_ci  if (params->scanlines < 1)
157141cc406Sopenharmony_ci    params->scanlines = 1;
158141cc406Sopenharmony_ci  if (params->leftpix < 0)
159141cc406Sopenharmony_ci    params->leftpix = 0;
160141cc406Sopenharmony_ci  if (params->scanpix < 128)
161141cc406Sopenharmony_ci    params->scanpix = 128;
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci  /* Some handy calculations */
164141cc406Sopenharmony_ci  params->linelen =
165141cc406Sopenharmony_ci    params->scanpix * (params->bpp / 8) * (params->gray ? 1 : 3);
166141cc406Sopenharmony_ci}
167141cc406Sopenharmony_ci
168141cc406Sopenharmony_ci#ifndef BACKENDNAME
169141cc406Sopenharmony_ciusb_dev_handle *
170141cc406Sopenharmony_cifind_device (unsigned int idVendor, unsigned int idProduct)
171141cc406Sopenharmony_ci{
172141cc406Sopenharmony_ci  struct usb_bus *bus;
173141cc406Sopenharmony_ci  struct usb_device *dev;
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_ci  usb_init ();
176141cc406Sopenharmony_ci  usb_find_busses ();
177141cc406Sopenharmony_ci  usb_find_devices ();
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_ci  for (bus = usb_get_busses (); bus; bus = bus->next)
180141cc406Sopenharmony_ci    for (dev = bus->devices; dev; dev = dev->next)
181141cc406Sopenharmony_ci      if (dev->descriptor.idVendor == idVendor &&
182141cc406Sopenharmony_ci	  dev->descriptor.idProduct == idProduct)
183141cc406Sopenharmony_ci	return usb_open (dev);
184141cc406Sopenharmony_ci
185141cc406Sopenharmony_ci  return NULL;
186141cc406Sopenharmony_ci}
187141cc406Sopenharmony_ci#endif
188141cc406Sopenharmony_ci
189141cc406Sopenharmony_cistatic void
190141cc406Sopenharmony_ciidle_ab (p_usb_dev_handle udev)
191141cc406Sopenharmony_ci{
192141cc406Sopenharmony_ci  int i;
193141cc406Sopenharmony_ci  unsigned char buff[8] = { 0x64, 0x65, 0x16, 0x17, 0x64, 0x65, 0x44, 0x45 };
194141cc406Sopenharmony_ci  for (i = 0; i < 8; i++)
195141cc406Sopenharmony_ci    {
196141cc406Sopenharmony_ci      usb_control_msg (udev, 0x40, 0x0c, 0x0090, 0x0000, buff + i,
197141cc406Sopenharmony_ci                       0x0001, wr_timeout);
198141cc406Sopenharmony_ci    }
199141cc406Sopenharmony_ci}
200141cc406Sopenharmony_ci
201141cc406Sopenharmony_ci/* CW: 40 04 00b0 0000 <len> :  <reg1> <value1> <reg2> <value2> ... */
202141cc406Sopenharmony_cistatic void
203141cc406Sopenharmony_ciwrite_regs (p_usb_dev_handle udev, int regs, int reg1, int val1,
204141cc406Sopenharmony_ci	    ... /* int reg, int val, ... */ )
205141cc406Sopenharmony_ci{
206141cc406Sopenharmony_ci  unsigned char buff[512];
207141cc406Sopenharmony_ci  va_list marker;
208141cc406Sopenharmony_ci  int i;
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_ci  va_start (marker, val1);
211141cc406Sopenharmony_ci  buff[0] = reg1;
212141cc406Sopenharmony_ci  buff[1] = val1;
213141cc406Sopenharmony_ci  for (i = 1; i < regs; i++)
214141cc406Sopenharmony_ci    {
215141cc406Sopenharmony_ci      buff[i * 2] = va_arg (marker, int);
216141cc406Sopenharmony_ci      buff[i * 2 + 1] = va_arg (marker, int);
217141cc406Sopenharmony_ci    }
218141cc406Sopenharmony_ci  va_end (marker);
219141cc406Sopenharmony_ci
220141cc406Sopenharmony_ci  usb_control_msg (udev, 0x40, 0x04, 0x00b0, 0x0000, buff,
221141cc406Sopenharmony_ci                   regs * 2, wr_timeout);
222141cc406Sopenharmony_ci}
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_cistatic int
225141cc406Sopenharmony_ciwrite_vctl (p_usb_dev_handle udev, int request, int value,
226141cc406Sopenharmony_ci	    int index, unsigned char byte)
227141cc406Sopenharmony_ci{
228141cc406Sopenharmony_ci  return usb_control_msg (udev, 0x40, request, value, index,
229141cc406Sopenharmony_ci			  &byte, 1, wr_timeout);
230141cc406Sopenharmony_ci}
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_cistatic int
233141cc406Sopenharmony_ciread_vctl (p_usb_dev_handle udev, int request, int value,
234141cc406Sopenharmony_ci	   int index, unsigned char *byte)
235141cc406Sopenharmony_ci{
236141cc406Sopenharmony_ci  return usb_control_msg (udev, 0xc0, request, value, index,
237141cc406Sopenharmony_ci			  byte, 1, wr_timeout);
238141cc406Sopenharmony_ci}
239141cc406Sopenharmony_ci
240141cc406Sopenharmony_ci#ifndef BACKENDNAME
241141cc406Sopenharmony_ci/* Copy from a USB data pipe to a file with optional header */
242141cc406Sopenharmony_cistatic void
243141cc406Sopenharmony_cirecord_head (p_usb_dev_handle udev, char *fname, int bytes, char *header)
244141cc406Sopenharmony_ci{
245141cc406Sopenharmony_ci  FILE *fp;
246141cc406Sopenharmony_ci  unsigned char buff[65536];
247141cc406Sopenharmony_ci  int len;
248141cc406Sopenharmony_ci  int toread;
249141cc406Sopenharmony_ci
250141cc406Sopenharmony_ci  fp = fopen (fname, "wb");
251141cc406Sopenharmony_ci  if (header)
252141cc406Sopenharmony_ci    fprintf (fp, "%s", header);
253141cc406Sopenharmony_ci  do
254141cc406Sopenharmony_ci    {
255141cc406Sopenharmony_ci      toread = (bytes > 65536) ? 65536 : bytes;
256141cc406Sopenharmony_ci      len = usb_bulk_read (udev, 1, buff, toread, rd_timeout);
257141cc406Sopenharmony_ci      if (len > 0)
258141cc406Sopenharmony_ci	{
259141cc406Sopenharmony_ci	  fwrite (buff, len, 1, fp);
260141cc406Sopenharmony_ci	  bytes -= len;
261141cc406Sopenharmony_ci	}
262141cc406Sopenharmony_ci      else
263141cc406Sopenharmony_ci	{
264141cc406Sopenharmony_ci	  DBG (2, "TIMEOUT\n");
265141cc406Sopenharmony_ci	}
266141cc406Sopenharmony_ci    }
267141cc406Sopenharmony_ci  while (bytes);
268141cc406Sopenharmony_ci  fclose (fp);
269141cc406Sopenharmony_ci}
270141cc406Sopenharmony_ci
271141cc406Sopenharmony_ci/* Copy from a USB data pipe to a file without header */
272141cc406Sopenharmony_cistatic void
273141cc406Sopenharmony_cirecord (p_usb_dev_handle udev, char *fname, int bytes)
274141cc406Sopenharmony_ci{
275141cc406Sopenharmony_ci  record_head (udev, fname, bytes, "");
276141cc406Sopenharmony_ci}
277141cc406Sopenharmony_ci#endif
278141cc406Sopenharmony_ci
279141cc406Sopenharmony_cistatic int
280141cc406Sopenharmony_cimax (int a, int b)
281141cc406Sopenharmony_ci{
282141cc406Sopenharmony_ci  return (a > b) ? a : b;
283141cc406Sopenharmony_ci}
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci
286141cc406Sopenharmony_ci#define DPI1200SHUFFLE 6
287141cc406Sopenharmony_cistatic void
288141cc406Sopenharmony_cirecord_line (int reset,
289141cc406Sopenharmony_ci	     p_usb_dev_handle udev,
290141cc406Sopenharmony_ci	     unsigned char *storeline,
291141cc406Sopenharmony_ci	     int dpi, int scanpix, int gray, int bpp16,
292141cc406Sopenharmony_ci	     int *save_i,
293141cc406Sopenharmony_ci	     unsigned char **save_scan_line,
294141cc406Sopenharmony_ci	     unsigned char **save_dpi1200_remap,
295141cc406Sopenharmony_ci	     unsigned char **save_color_remap)
296141cc406Sopenharmony_ci{
297141cc406Sopenharmony_ci  unsigned char *scan_line, *dpi1200_remap;
298141cc406Sopenharmony_ci  unsigned char *color_remap;
299141cc406Sopenharmony_ci  int i;
300141cc406Sopenharmony_ci  int red_delay, blue_delay, green_delay;
301141cc406Sopenharmony_ci  int j;
302141cc406Sopenharmony_ci  int linelen;
303141cc406Sopenharmony_ci  int pixsize;
304141cc406Sopenharmony_ci  unsigned char *ptrcur, *ptrprev;
305141cc406Sopenharmony_ci  unsigned char *savestoreline;
306141cc406Sopenharmony_ci  int lineptr, outline, bufflines;
307141cc406Sopenharmony_ci
308141cc406Sopenharmony_ci  i = *save_i;
309141cc406Sopenharmony_ci  scan_line = *save_scan_line;
310141cc406Sopenharmony_ci  dpi1200_remap = *save_dpi1200_remap;
311141cc406Sopenharmony_ci  color_remap = *save_color_remap;
312141cc406Sopenharmony_ci
313141cc406Sopenharmony_ci  pixsize = (gray ? 1 : 3) * (bpp16 ? 2 : 1);
314141cc406Sopenharmony_ci  linelen = scanpix * pixsize;
315141cc406Sopenharmony_ci
316141cc406Sopenharmony_ci  if (gray)
317141cc406Sopenharmony_ci    {
318141cc406Sopenharmony_ci      red_delay = 0;
319141cc406Sopenharmony_ci      blue_delay = 0;
320141cc406Sopenharmony_ci      green_delay = 0;
321141cc406Sopenharmony_ci    }
322141cc406Sopenharmony_ci  else if (dpi == 150)
323141cc406Sopenharmony_ci    {
324141cc406Sopenharmony_ci      red_delay = 0;
325141cc406Sopenharmony_ci      blue_delay = 6;
326141cc406Sopenharmony_ci      green_delay = 3;
327141cc406Sopenharmony_ci    }
328141cc406Sopenharmony_ci  else if (dpi == 300)
329141cc406Sopenharmony_ci    {
330141cc406Sopenharmony_ci      red_delay = 0;
331141cc406Sopenharmony_ci      blue_delay = 12;
332141cc406Sopenharmony_ci      green_delay = 6;
333141cc406Sopenharmony_ci    }
334141cc406Sopenharmony_ci  else if (dpi == 600)
335141cc406Sopenharmony_ci    {
336141cc406Sopenharmony_ci      red_delay = 0;
337141cc406Sopenharmony_ci      blue_delay = 24;
338141cc406Sopenharmony_ci      green_delay = 12;
339141cc406Sopenharmony_ci    }
340141cc406Sopenharmony_ci  else				/*(dpi==1200) */
341141cc406Sopenharmony_ci    {
342141cc406Sopenharmony_ci      red_delay = 0;
343141cc406Sopenharmony_ci      blue_delay = 48;
344141cc406Sopenharmony_ci      green_delay = 24;
345141cc406Sopenharmony_ci    }
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci  bufflines = max (max (red_delay, blue_delay), green_delay) + 1;
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci  if (reset)
350141cc406Sopenharmony_ci    {
351141cc406Sopenharmony_ci      if (dpi1200_remap)
352141cc406Sopenharmony_ci	free (dpi1200_remap);
353141cc406Sopenharmony_ci      if (scan_line)
354141cc406Sopenharmony_ci	free (scan_line);
355141cc406Sopenharmony_ci      if (color_remap)
356141cc406Sopenharmony_ci	free (color_remap);
357141cc406Sopenharmony_ci
358141cc406Sopenharmony_ci      *save_color_remap = color_remap =
359141cc406Sopenharmony_ci	(unsigned char *) malloc (bufflines * linelen);
360141cc406Sopenharmony_ci
361141cc406Sopenharmony_ci      *save_scan_line = scan_line = (unsigned char *) calloc (linelen, 1);
362141cc406Sopenharmony_ci      if (dpi == 1200)
363141cc406Sopenharmony_ci	*save_dpi1200_remap = dpi1200_remap =
364141cc406Sopenharmony_ci	  (unsigned char *) calloc (linelen, DPI1200SHUFFLE);
365141cc406Sopenharmony_ci      else
366141cc406Sopenharmony_ci	*save_dpi1200_remap = dpi1200_remap = NULL;
367141cc406Sopenharmony_ci
368141cc406Sopenharmony_ci      *save_i = i = 0;		/* i is our linenumber */
369141cc406Sopenharmony_ci    }
370141cc406Sopenharmony_ci
371141cc406Sopenharmony_ci  while (1)
372141cc406Sopenharmony_ci    {				/* We'll exit inside the loop... */
373141cc406Sopenharmony_ci      usb_bulk_read (udev, 1, scan_line, linelen, rd_timeout);
374141cc406Sopenharmony_ci      if (dpi == 1200)
375141cc406Sopenharmony_ci	{
376141cc406Sopenharmony_ci	  ptrcur = dpi1200_remap + (linelen * (i % DPI1200SHUFFLE));
377141cc406Sopenharmony_ci	  ptrprev =
378141cc406Sopenharmony_ci	    dpi1200_remap +
379141cc406Sopenharmony_ci	    (linelen * ((i - (DPI1200SHUFFLE - 2)) % DPI1200SHUFFLE));
380141cc406Sopenharmony_ci	}
381141cc406Sopenharmony_ci      else
382141cc406Sopenharmony_ci	{
383141cc406Sopenharmony_ci	  ptrcur = scan_line;
384141cc406Sopenharmony_ci	  ptrprev = NULL;
385141cc406Sopenharmony_ci	}
386141cc406Sopenharmony_ci      if (gray)
387141cc406Sopenharmony_ci	{
388141cc406Sopenharmony_ci	  memcpy (ptrcur, scan_line, linelen);
389141cc406Sopenharmony_ci	}
390141cc406Sopenharmony_ci      else
391141cc406Sopenharmony_ci	{
392141cc406Sopenharmony_ci	  int pixsize = bpp16 ? 2 : 1;
393141cc406Sopenharmony_ci	  int pix = linelen / (3 * pixsize);
394141cc406Sopenharmony_ci	  unsigned char *outbuff = ptrcur;
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_ci	  outline = i;
397141cc406Sopenharmony_ci	  lineptr = i % bufflines;
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ci	  memcpy (color_remap + linelen * lineptr, scan_line, linelen);
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci	  outline++;
402141cc406Sopenharmony_ci	  if (outline > bufflines)
403141cc406Sopenharmony_ci	    {
404141cc406Sopenharmony_ci	      int redline = (outline + red_delay) % bufflines;
405141cc406Sopenharmony_ci	      int greenline = (outline + green_delay) % bufflines;
406141cc406Sopenharmony_ci	      int blueline = (outline + blue_delay) % bufflines;
407141cc406Sopenharmony_ci	      unsigned char *rp, *gp, *bp;
408141cc406Sopenharmony_ci
409141cc406Sopenharmony_ci	      rp = color_remap + linelen * redline;
410141cc406Sopenharmony_ci	      gp = color_remap + linelen * greenline + 1 * pixsize;
411141cc406Sopenharmony_ci	      bp = color_remap + linelen * blueline + 2 * pixsize;
412141cc406Sopenharmony_ci
413141cc406Sopenharmony_ci	      for (j = 0; j < pix; j++)
414141cc406Sopenharmony_ci		{
415141cc406Sopenharmony_ci		  if (outbuff)
416141cc406Sopenharmony_ci		    {
417141cc406Sopenharmony_ci		      *(outbuff++) = *rp;
418141cc406Sopenharmony_ci		      if (pixsize == 2)
419141cc406Sopenharmony_ci			*(outbuff++) = *(rp + 1);
420141cc406Sopenharmony_ci		      *(outbuff++) = *gp;
421141cc406Sopenharmony_ci		      if (pixsize == 2)
422141cc406Sopenharmony_ci			*(outbuff++) = *(gp + 1);
423141cc406Sopenharmony_ci		      *(outbuff++) = *bp;
424141cc406Sopenharmony_ci		      if (pixsize == 2)
425141cc406Sopenharmony_ci			*(outbuff++) = *(bp + 1);
426141cc406Sopenharmony_ci		    }
427141cc406Sopenharmony_ci		  rp += 3 * pixsize;
428141cc406Sopenharmony_ci		  gp += 3 * pixsize;
429141cc406Sopenharmony_ci		  bp += 3 * pixsize;
430141cc406Sopenharmony_ci		}
431141cc406Sopenharmony_ci	    }
432141cc406Sopenharmony_ci	  lineptr = (lineptr + 1) % bufflines;
433141cc406Sopenharmony_ci	}
434141cc406Sopenharmony_ci
435141cc406Sopenharmony_ci      if (dpi != 1200)
436141cc406Sopenharmony_ci	{
437141cc406Sopenharmony_ci	  if (i > blue_delay)
438141cc406Sopenharmony_ci	    {
439141cc406Sopenharmony_ci	      savestoreline = storeline;
440141cc406Sopenharmony_ci	      for (j = 0; j < scanpix; j++)
441141cc406Sopenharmony_ci		{
442141cc406Sopenharmony_ci		  memcpy (storeline, ptrcur + linelen - (j + 1) * pixsize,
443141cc406Sopenharmony_ci			  pixsize);
444141cc406Sopenharmony_ci		  storeline += pixsize;
445141cc406Sopenharmony_ci		}
446141cc406Sopenharmony_ci	      if (dpi == 150)
447141cc406Sopenharmony_ci		{
448141cc406Sopenharmony_ci		  /* 150 DPI skips every 4th returned line */
449141cc406Sopenharmony_ci		  if (i % 4)
450141cc406Sopenharmony_ci		    {
451141cc406Sopenharmony_ci		      i++;
452141cc406Sopenharmony_ci		      *save_i = i;
453141cc406Sopenharmony_ci		      if (bpp16)
454141cc406Sopenharmony_ci			fix_endian_short ((unsigned short *) storeline,
455141cc406Sopenharmony_ci					  scanpix);
456141cc406Sopenharmony_ci		      return;
457141cc406Sopenharmony_ci		    }
458141cc406Sopenharmony_ci		  storeline = savestoreline;
459141cc406Sopenharmony_ci		}
460141cc406Sopenharmony_ci	      else
461141cc406Sopenharmony_ci		{
462141cc406Sopenharmony_ci		  i++;
463141cc406Sopenharmony_ci		  *save_i = i;
464141cc406Sopenharmony_ci		  if (bpp16)
465141cc406Sopenharmony_ci		    fix_endian_short ((unsigned short *) storeline, scanpix);
466141cc406Sopenharmony_ci		  return;
467141cc406Sopenharmony_ci		}
468141cc406Sopenharmony_ci	    }
469141cc406Sopenharmony_ci	}
470141cc406Sopenharmony_ci      else			/* dpi==1200 */
471141cc406Sopenharmony_ci	{
472141cc406Sopenharmony_ci	  if (i > (DPI1200SHUFFLE + blue_delay))
473141cc406Sopenharmony_ci	    {
474141cc406Sopenharmony_ci	      for (j = 0; j < scanpix; j++)
475141cc406Sopenharmony_ci		{
476141cc406Sopenharmony_ci		  if (1 == (j & 1))
477141cc406Sopenharmony_ci		    memcpy (storeline, ptrcur + linelen - (j + 1) * pixsize,
478141cc406Sopenharmony_ci			    pixsize);
479141cc406Sopenharmony_ci		  else
480141cc406Sopenharmony_ci		    memcpy (storeline, ptrprev + linelen - (j + 1) * pixsize,
481141cc406Sopenharmony_ci			    pixsize);
482141cc406Sopenharmony_ci		  storeline += pixsize;
483141cc406Sopenharmony_ci		}		/* end for */
484141cc406Sopenharmony_ci	      i++;
485141cc406Sopenharmony_ci	      *save_i = i;
486141cc406Sopenharmony_ci	      if (bpp16)
487141cc406Sopenharmony_ci		fix_endian_short ((unsigned short *) storeline, scanpix);
488141cc406Sopenharmony_ci	      return;
489141cc406Sopenharmony_ci	    }			/* end if >dpi1200shuffle */
490141cc406Sopenharmony_ci	}			/* end if dpi1200 */
491141cc406Sopenharmony_ci      i++;
492141cc406Sopenharmony_ci    }				/* end for */
493141cc406Sopenharmony_ci}
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci
496141cc406Sopenharmony_ci#ifndef BACKENDNAME
497141cc406Sopenharmony_ci/* Record an image to a file with remapping/reordering/etc. */
498141cc406Sopenharmony_civoid
499141cc406Sopenharmony_cirecord_image (p_usb_dev_handle udev, char *fname, int dpi,
500141cc406Sopenharmony_ci	      int scanpix, int scanlines, int gray, char *head, int bpp16)
501141cc406Sopenharmony_ci{
502141cc406Sopenharmony_ci  FILE *fp;
503141cc406Sopenharmony_ci  int i;
504141cc406Sopenharmony_ci  int save_i;
505141cc406Sopenharmony_ci  unsigned char *save_scan_line;
506141cc406Sopenharmony_ci  unsigned char *save_dpi1200_remap;
507141cc406Sopenharmony_ci  unsigned char *save_color_remap;
508141cc406Sopenharmony_ci  unsigned char *storeline;
509141cc406Sopenharmony_ci
510141cc406Sopenharmony_ci  save_i = 0;
511141cc406Sopenharmony_ci  save_scan_line = save_dpi1200_remap = save_color_remap = NULL;
512141cc406Sopenharmony_ci  storeline =
513141cc406Sopenharmony_ci    (unsigned char *) malloc (scanpix * (gray ? 1 : 3) * (bpp16 ? 2 : 1));
514141cc406Sopenharmony_ci
515141cc406Sopenharmony_ci  fp = fopen (fname, "wb");
516141cc406Sopenharmony_ci  if (head)
517141cc406Sopenharmony_ci    fprintf (fp, "%s", head);
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci  for (i = 0; i < scanlines; i++)
520141cc406Sopenharmony_ci    {
521141cc406Sopenharmony_ci      record_line ((i == 0) ? 1 : 0, udev, storeline, dpi, scanpix, gray,
522141cc406Sopenharmony_ci		   bpp16, &save_i, &save_scan_line, &save_dpi1200_remap,
523141cc406Sopenharmony_ci		   &save_color_remap);
524141cc406Sopenharmony_ci      fwrite (storeline, scanpix * (gray ? 1 : 3) * (bpp16 ? 2 : 1), 1, fp);
525141cc406Sopenharmony_ci    }
526141cc406Sopenharmony_ci  fclose (fp);
527141cc406Sopenharmony_ci  if (save_scan_line)
528141cc406Sopenharmony_ci    free (save_scan_line);
529141cc406Sopenharmony_ci  if (save_dpi1200_remap)
530141cc406Sopenharmony_ci    free (save_dpi1200_remap);
531141cc406Sopenharmony_ci  if (save_color_remap)
532141cc406Sopenharmony_ci    free (save_color_remap);
533141cc406Sopenharmony_ci  free (storeline);
534141cc406Sopenharmony_ci}
535141cc406Sopenharmony_ci#endif
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_cistatic void
538141cc406Sopenharmony_cirecord_mem (p_usb_dev_handle udev, unsigned char **dest, int bytes)
539141cc406Sopenharmony_ci{
540141cc406Sopenharmony_ci  unsigned char *mem;
541141cc406Sopenharmony_ci  unsigned char buff[65536];
542141cc406Sopenharmony_ci  int len;
543141cc406Sopenharmony_ci
544141cc406Sopenharmony_ci  mem = (unsigned char *) malloc (bytes);
545141cc406Sopenharmony_ci  *dest = mem;
546141cc406Sopenharmony_ci  do
547141cc406Sopenharmony_ci    {
548141cc406Sopenharmony_ci      len =
549141cc406Sopenharmony_ci	usb_bulk_read (udev, 1, buff, bytes > 65536 ? 65536 : bytes,
550141cc406Sopenharmony_ci		       rd_timeout);
551141cc406Sopenharmony_ci      if (len > 0)
552141cc406Sopenharmony_ci	{
553141cc406Sopenharmony_ci	  memcpy (mem, buff, len);
554141cc406Sopenharmony_ci	  bytes -= len;
555141cc406Sopenharmony_ci	  mem += len;
556141cc406Sopenharmony_ci	}
557141cc406Sopenharmony_ci    }
558141cc406Sopenharmony_ci  while (bytes);
559141cc406Sopenharmony_ci}
560141cc406Sopenharmony_ci
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_cistatic void
563141cc406Sopenharmony_cireset_scanner (p_usb_dev_handle udev)
564141cc406Sopenharmony_ci{
565141cc406Sopenharmony_ci  unsigned char rd_byte;
566141cc406Sopenharmony_ci
567141cc406Sopenharmony_ci  DBG (2, "+reset_scanner\n");
568141cc406Sopenharmony_ci  write_regs (udev, 5, 0x83, 0x00, 0xa3, 0xff, 0xa4, 0xff, 0xa1, 0xff,
569141cc406Sopenharmony_ci	      0xa2, 0xff);
570141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00);
571141cc406Sopenharmony_ci  write_regs (udev, 2, 0xbe, 0x00, 0x84, 0x00);
572141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00);
573141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00);
574141cc406Sopenharmony_ci  write_regs (udev, 16, 0xbe, 0x18, 0x80, 0x00, 0x84, 0x00, 0x89, 0x00,
575141cc406Sopenharmony_ci	      0x88, 0x00, 0x86, 0x00, 0x90, 0x00, 0xc1, 0x00,
576141cc406Sopenharmony_ci	      0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5, 0x00,
577141cc406Sopenharmony_ci	      0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc0, 0x00);
578141cc406Sopenharmony_ci  write_regs (udev, 16, 0x84, 0x94, 0x80, 0xd1, 0x80, 0xc1, 0x82, 0x7f,
579141cc406Sopenharmony_ci	      0xcf, 0x04, 0xc1, 0x02, 0xc2, 0x00, 0xc3, 0x06,
580141cc406Sopenharmony_ci	      0xc4, 0xff, 0xc5, 0x40, 0xc6, 0x8c, 0xc7, 0xdc,
581141cc406Sopenharmony_ci	      0xc8, 0x20, 0xc0, 0x72, 0x89, 0xff, 0x86, 0xff);
582141cc406Sopenharmony_ci  write_regs (udev, 7, 0xa8, 0x80, 0x83, 0xa2, 0x85, 0xc8, 0x83, 0x82,
583141cc406Sopenharmony_ci	      0x85, 0xaf, 0x83, 0x00, 0x93, 0x00);
584141cc406Sopenharmony_ci  write_regs (udev, 3, 0xa8, 0x0a, 0x8c, 0x08, 0x94, 0x00);
585141cc406Sopenharmony_ci  write_regs (udev, 4, 0x83, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x97, 0x0a);
586141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
587141cc406Sopenharmony_ci  read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
588141cc406Sopenharmony_ci  write_regs (udev, 1, 0x97, 0x0b);
589141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
590141cc406Sopenharmony_ci  read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
591141cc406Sopenharmony_ci  write_regs (udev, 1, 0x97, 0x0f);
592141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
593141cc406Sopenharmony_ci  read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
594141cc406Sopenharmony_ci  write_regs (udev, 1, 0x97, 0x05);
595141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
596141cc406Sopenharmony_ci  read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
597141cc406Sopenharmony_ci  DBG (2, "-reset_scanner\n");
598141cc406Sopenharmony_ci}
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_cistatic void
601141cc406Sopenharmony_cipoll1 (p_usb_dev_handle udev)
602141cc406Sopenharmony_ci{
603141cc406Sopenharmony_ci  unsigned char rd_byte;
604141cc406Sopenharmony_ci  DBG (2, "+poll1\n");
605141cc406Sopenharmony_ci  do
606141cc406Sopenharmony_ci    {
607141cc406Sopenharmony_ci      write_regs (udev, 1, 0x97, 0x00);
608141cc406Sopenharmony_ci      write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
609141cc406Sopenharmony_ci      read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
610141cc406Sopenharmony_ci    }
611141cc406Sopenharmony_ci  while (0 == (rd_byte & 0x40));
612141cc406Sopenharmony_ci  DBG (2, "-poll1\n");
613141cc406Sopenharmony_ci}
614141cc406Sopenharmony_ci
615141cc406Sopenharmony_cistatic void
616141cc406Sopenharmony_cipoll2 (p_usb_dev_handle udev)
617141cc406Sopenharmony_ci{
618141cc406Sopenharmony_ci  unsigned char rd_byte;
619141cc406Sopenharmony_ci  DBG (2, "+poll2\n");
620141cc406Sopenharmony_ci  do
621141cc406Sopenharmony_ci    {
622141cc406Sopenharmony_ci      write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
623141cc406Sopenharmony_ci      read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
624141cc406Sopenharmony_ci    }
625141cc406Sopenharmony_ci  while (0 == (rd_byte & 0x02));
626141cc406Sopenharmony_ci  DBG (2, "-poll2\n");
627141cc406Sopenharmony_ci}
628141cc406Sopenharmony_ci
629141cc406Sopenharmony_ci#ifndef BACKENDNAME
630141cc406Sopenharmony_cistatic void
631141cc406Sopenharmony_cicheck_buttons (p_usb_dev_handle udev, int *scan, int *print, int *mail)
632141cc406Sopenharmony_ci{
633141cc406Sopenharmony_ci  unsigned char rd_byte;
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_ci  write_regs (udev, 4, 0x83, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x97, 0x0a);
636141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
637141cc406Sopenharmony_ci  read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
638141cc406Sopenharmony_ci  if (scan)
639141cc406Sopenharmony_ci    {
640141cc406Sopenharmony_ci      if (0 == (rd_byte & 1))
641141cc406Sopenharmony_ci	*scan = 1;
642141cc406Sopenharmony_ci      else
643141cc406Sopenharmony_ci	*scan = 0;
644141cc406Sopenharmony_ci    }
645141cc406Sopenharmony_ci  if (print)
646141cc406Sopenharmony_ci    {
647141cc406Sopenharmony_ci      if (0 == (rd_byte & 2))
648141cc406Sopenharmony_ci	*print = 1;
649141cc406Sopenharmony_ci      else
650141cc406Sopenharmony_ci	*print = 0;
651141cc406Sopenharmony_ci    }
652141cc406Sopenharmony_ci  if (mail)
653141cc406Sopenharmony_ci    {
654141cc406Sopenharmony_ci      if (0 == (rd_byte & 4))
655141cc406Sopenharmony_ci	*mail = 1;
656141cc406Sopenharmony_ci      else
657141cc406Sopenharmony_ci	*mail = 0;
658141cc406Sopenharmony_ci    }
659141cc406Sopenharmony_ci  write_regs (udev, 1, 0x97, 0x0b);
660141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
661141cc406Sopenharmony_ci  read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
662141cc406Sopenharmony_ci  idle_ab (udev);
663141cc406Sopenharmony_ci  write_regs (udev, 1, 0x97, 0x0f);
664141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
665141cc406Sopenharmony_ci  read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
666141cc406Sopenharmony_ci  idle_ab (udev);
667141cc406Sopenharmony_ci  write_regs (udev, 1, 0x97, 0x05);
668141cc406Sopenharmony_ci  write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00);
669141cc406Sopenharmony_ci  read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte);
670141cc406Sopenharmony_ci  idle_ab (udev);
671141cc406Sopenharmony_ci}
672141cc406Sopenharmony_ci#endif
673141cc406Sopenharmony_ci
674141cc406Sopenharmony_cistatic int
675141cc406Sopenharmony_cilut (int val, double gain, int offset)
676141cc406Sopenharmony_ci{
677141cc406Sopenharmony_ci  /* int offset = 1800; */
678141cc406Sopenharmony_ci  /* double exponent = 3.5; */
679141cc406Sopenharmony_ci  return (offset + 8192.0 * (pow ((8192.0 - val) / 8192.0, gain)));
680141cc406Sopenharmony_ci}
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci
683141cc406Sopenharmony_cistatic void
684141cc406Sopenharmony_cicalc_lightmap (unsigned short *buff,
685141cc406Sopenharmony_ci	       unsigned short *storage, int index, int dpi,
686141cc406Sopenharmony_ci	       double gain, int offset)
687141cc406Sopenharmony_ci{
688141cc406Sopenharmony_ci  int val, line;
689141cc406Sopenharmony_ci  int px = 5632;
690141cc406Sopenharmony_ci  int i;
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci  line = px * 3;
693141cc406Sopenharmony_ci
694141cc406Sopenharmony_ci  for (i = 0; i < px; i++)
695141cc406Sopenharmony_ci    {
696141cc406Sopenharmony_ci      if ((i >= 2) && (i <= (px - 2)))
697141cc406Sopenharmony_ci	{
698141cc406Sopenharmony_ci	  val = 0;
699141cc406Sopenharmony_ci	  val += 1 * buff[i * 3 + index - 3 * 2];
700141cc406Sopenharmony_ci	  val += 3 * buff[i * 3 + index - 3 * 1];
701141cc406Sopenharmony_ci	  val += 5 * buff[i * 3 + index + 3 * 0];
702141cc406Sopenharmony_ci	  val += 3 * buff[i * 3 + index + 3 * 1];
703141cc406Sopenharmony_ci	  val += 1 * buff[i * 3 + index + 3 * 2];
704141cc406Sopenharmony_ci	  val += 2 * buff[i * 3 + index - 3 * 1 + line];
705141cc406Sopenharmony_ci	  val += 3 * buff[i * 3 + index + 3 * 0 + line];
706141cc406Sopenharmony_ci	  val += 2 * buff[i * 3 + index + 3 * 1 + line];
707141cc406Sopenharmony_ci	  val += 1 * buff[i * 3 + index + 3 * 0 + 2 * line];
708141cc406Sopenharmony_ci	  val /= 21;
709141cc406Sopenharmony_ci	}
710141cc406Sopenharmony_ci      else
711141cc406Sopenharmony_ci	{
712141cc406Sopenharmony_ci	  val = 1 * buff[i * 3 + index];
713141cc406Sopenharmony_ci	}
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci      val = val >> 3;
716141cc406Sopenharmony_ci      if (val > 8191)
717141cc406Sopenharmony_ci	val = 8191;
718141cc406Sopenharmony_ci      val = lut (val, gain, offset);
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci      if (val > 8191)
721141cc406Sopenharmony_ci	val = 8191;
722141cc406Sopenharmony_ci      if (val < 0)
723141cc406Sopenharmony_ci	val = 0;
724141cc406Sopenharmony_ci      storage[i * (dpi == 1200 ? 2 : 1)] = val;
725141cc406Sopenharmony_ci      if (dpi == 1200)
726141cc406Sopenharmony_ci	storage[i * 2 + 1] = val;
727141cc406Sopenharmony_ci    }
728141cc406Sopenharmony_ci
729141cc406Sopenharmony_ci  fix_endian_short (storage, (dpi == 1200) ? i * 2 : i);
730141cc406Sopenharmony_ci}
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci
735141cc406Sopenharmony_ci/*#define VALMAP  0x1fff */
736141cc406Sopenharmony_ci/*#define SCANMAP 0x2000*/
737141cc406Sopenharmony_ci#define RAWPIXELS600 7320
738141cc406Sopenharmony_ci#define RAWPIXELS1200 14640
739141cc406Sopenharmony_ci
740141cc406Sopenharmony_cistatic void
741141cc406Sopenharmony_ciselect_pixels (unsigned short *map, int dpi, int start, int end)
742141cc406Sopenharmony_ci{
743141cc406Sopenharmony_ci  int i;
744141cc406Sopenharmony_ci  int skip, offset;
745141cc406Sopenharmony_ci  unsigned short VALMAP = 0x1fff;
746141cc406Sopenharmony_ci  unsigned short SCANMAP = 0x2000;
747141cc406Sopenharmony_ci
748141cc406Sopenharmony_ci  fix_endian_short (&VALMAP, 1);
749141cc406Sopenharmony_ci  fix_endian_short (&SCANMAP, 1);
750141cc406Sopenharmony_ci
751141cc406Sopenharmony_ci  /* Clear the pixel-on flags for all bits */
752141cc406Sopenharmony_ci  for (i = 0; i < ((dpi == 1200) ? RAWPIXELS1200 : RAWPIXELS600); i++)
753141cc406Sopenharmony_ci    map[i] &= VALMAP;
754141cc406Sopenharmony_ci
755141cc406Sopenharmony_ci  /* 300 and 150 have subsampling */
756141cc406Sopenharmony_ci  if (dpi == 300)
757141cc406Sopenharmony_ci    skip = -2;
758141cc406Sopenharmony_ci  else if (dpi == 150)
759141cc406Sopenharmony_ci    skip = -4;
760141cc406Sopenharmony_ci  else
761141cc406Sopenharmony_ci    skip = -1;
762141cc406Sopenharmony_ci
763141cc406Sopenharmony_ci  /* 1200 has 2x pixels so start at 2x the offset */
764141cc406Sopenharmony_ci  if (dpi == 1200)
765141cc406Sopenharmony_ci    offset = 234 + (8.5 * 1200);
766141cc406Sopenharmony_ci  else
767141cc406Sopenharmony_ci    offset = 117 + (8.5 * 600);
768141cc406Sopenharmony_ci
769141cc406Sopenharmony_ci  if (0 == (offset & 1))
770141cc406Sopenharmony_ci    offset++;
771141cc406Sopenharmony_ci
772141cc406Sopenharmony_ci  DBG (2, "offset=%d start=%d skip=%d\n", offset, start, skip);
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci  for (i = 0; i < end; i++)
775141cc406Sopenharmony_ci    {
776141cc406Sopenharmony_ci      int x;
777141cc406Sopenharmony_ci      x = offset + (start * skip) + (i * skip);
778141cc406Sopenharmony_ci      if (x < 0 || x > ((dpi == 1200) ? RAWPIXELS1200 : RAWPIXELS600))
779141cc406Sopenharmony_ci	DBG (2, "ERR %d\n", x);
780141cc406Sopenharmony_ci      else
781141cc406Sopenharmony_ci	map[x] |= SCANMAP;
782141cc406Sopenharmony_ci    }
783141cc406Sopenharmony_ci}
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ci
786141cc406Sopenharmony_cistatic void
787141cc406Sopenharmony_ciset_lightmap_white (unsigned short *map, int dpi, int color)
788141cc406Sopenharmony_ci{
789141cc406Sopenharmony_ci  int i;
790141cc406Sopenharmony_ci  unsigned short VALMAP = 0x1fff;
791141cc406Sopenharmony_ci  unsigned short SCANMAP = 0x2000;
792141cc406Sopenharmony_ci
793141cc406Sopenharmony_ci  fix_endian_short (&VALMAP, 1);
794141cc406Sopenharmony_ci  fix_endian_short (&SCANMAP, 1);
795141cc406Sopenharmony_ci
796141cc406Sopenharmony_ci  if (dpi != 1200)
797141cc406Sopenharmony_ci    {
798141cc406Sopenharmony_ci      memset (map, 0, RAWPIXELS600 * 2);
799141cc406Sopenharmony_ci      if (color != 0)
800141cc406Sopenharmony_ci	return;			/* Only 1st has enables... */
801141cc406Sopenharmony_ci      for (i = 0; i < 22; i++)
802141cc406Sopenharmony_ci	map[7 + i] = SCANMAP;	/* Get some black... */
803141cc406Sopenharmony_ci      for (i = 0; i < 1024; i++)
804141cc406Sopenharmony_ci	map[2048 + i] = SCANMAP;	/* And some white... */
805141cc406Sopenharmony_ci    }
806141cc406Sopenharmony_ci  else
807141cc406Sopenharmony_ci    {
808141cc406Sopenharmony_ci      memset (map, 0, RAWPIXELS1200 * 2);
809141cc406Sopenharmony_ci      if (color != 0)
810141cc406Sopenharmony_ci	return;
811141cc406Sopenharmony_ci      for (i = 16; i < 61; i++)
812141cc406Sopenharmony_ci	map[i] = SCANMAP;
813141cc406Sopenharmony_ci      for (i = 4076; i < 6145; i++)
814141cc406Sopenharmony_ci	map[i] = SCANMAP;
815141cc406Sopenharmony_ci      /* 3rd is all clear */
816141cc406Sopenharmony_ci    }
817141cc406Sopenharmony_ci}
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci
820141cc406Sopenharmony_cistatic void
821141cc406Sopenharmony_ciset_lamp_timer (p_usb_dev_handle udev, int timeout_in_mins)
822141cc406Sopenharmony_ci{
823141cc406Sopenharmony_ci  write_regs (udev, 7, 0xa8, 0x80, 0x83, 0xa2, 0x85, 0xc8, 0x83, 0x82,
824141cc406Sopenharmony_ci	      0x85, 0xaf, 0x83, 0x00, 0x93, 0x00);
825141cc406Sopenharmony_ci  write_regs (udev, 3, 0xa8, timeout_in_mins * 2, 0x8c, 0x08, 0x94, 0x00);
826141cc406Sopenharmony_ci  idle_ab (udev);
827141cc406Sopenharmony_ci  write_regs (udev, 4, 0x83, 0x20, 0x8d, 0x26, 0x83, 0x00, 0x8d, 0xff);
828141cc406Sopenharmony_ci}
829141cc406Sopenharmony_ci
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_cistatic void
832141cc406Sopenharmony_cicalculate_lut8 (double *poly, int skip, unsigned char *dest)
833141cc406Sopenharmony_ci{
834141cc406Sopenharmony_ci  int i;
835141cc406Sopenharmony_ci  double sum, x;
836141cc406Sopenharmony_ci  if (!poly || !dest)
837141cc406Sopenharmony_ci    return;
838141cc406Sopenharmony_ci  for (i = 0; i < 8192; i += skip)
839141cc406Sopenharmony_ci    {
840141cc406Sopenharmony_ci      sum = poly[0];
841141cc406Sopenharmony_ci      x = (double) i;
842141cc406Sopenharmony_ci      sum += poly[1] * x;
843141cc406Sopenharmony_ci      x = x * i;
844141cc406Sopenharmony_ci      sum += poly[2] * x;
845141cc406Sopenharmony_ci      x = x * i;
846141cc406Sopenharmony_ci      sum += poly[3] * x;
847141cc406Sopenharmony_ci      x = x * i;
848141cc406Sopenharmony_ci      sum += poly[4] * x;
849141cc406Sopenharmony_ci      x = x * i;
850141cc406Sopenharmony_ci      sum += poly[5] * x;
851141cc406Sopenharmony_ci      x = x * i;
852141cc406Sopenharmony_ci      sum += poly[6] * x;
853141cc406Sopenharmony_ci      x = x * i;
854141cc406Sopenharmony_ci      sum += poly[7] * x;
855141cc406Sopenharmony_ci      x = x * i;
856141cc406Sopenharmony_ci      sum += poly[8] * x;
857141cc406Sopenharmony_ci      x = x * i;
858141cc406Sopenharmony_ci      sum += poly[9] * x;
859141cc406Sopenharmony_ci      x = x * i;
860141cc406Sopenharmony_ci      if (sum < 0)
861141cc406Sopenharmony_ci	sum = 0;
862141cc406Sopenharmony_ci      if (sum > 255)
863141cc406Sopenharmony_ci	sum = 255;
864141cc406Sopenharmony_ci      *dest = (unsigned char) sum;
865141cc406Sopenharmony_ci      dest++;
866141cc406Sopenharmony_ci    }
867141cc406Sopenharmony_ci}
868141cc406Sopenharmony_ci
869141cc406Sopenharmony_cistatic void
870141cc406Sopenharmony_cidownload_lut8 (p_usb_dev_handle udev, int dpi, int incolor)
871141cc406Sopenharmony_ci{
872141cc406Sopenharmony_ci  double color[10] = { 0.0, 1.84615261590892E-01, -2.19613868292657E-04,
873141cc406Sopenharmony_ci    1.79549523214101E-07, -8.69378513113239E-11,
874141cc406Sopenharmony_ci    2.56694911984996E-14, -4.67288886157239E-18,
875141cc406Sopenharmony_ci    5.11622894146250E-22, -3.08729724411991E-26,
876141cc406Sopenharmony_ci    7.88581670873938E-31
877141cc406Sopenharmony_ci  };
878141cc406Sopenharmony_ci  double gray[10] = { 0.0, 1.73089945056694E-01, -1.39794924306080E-04,
879141cc406Sopenharmony_ci    9.70266873814926E-08, -4.57503008236968E-11,
880141cc406Sopenharmony_ci    1.37092321631794E-14, -2.54395068387198E-18,
881141cc406Sopenharmony_ci    2.82432084125966E-22, -1.71787408822688E-26,
882141cc406Sopenharmony_ci    4.40306800664567E-31
883141cc406Sopenharmony_ci  };
884141cc406Sopenharmony_ci  unsigned char *lut;
885141cc406Sopenharmony_ci
886141cc406Sopenharmony_ci  DBG (2, "+download_lut8\n");
887141cc406Sopenharmony_ci  switch (dpi)
888141cc406Sopenharmony_ci    {
889141cc406Sopenharmony_ci    case 150:
890141cc406Sopenharmony_ci    case 300:
891141cc406Sopenharmony_ci    case 600:
892141cc406Sopenharmony_ci      lut = (unsigned char *) malloc (4096);
893141cc406Sopenharmony_ci      if (!lut)
894141cc406Sopenharmony_ci	return;
895141cc406Sopenharmony_ci
896141cc406Sopenharmony_ci      if (!incolor)
897141cc406Sopenharmony_ci	{
898141cc406Sopenharmony_ci	  calculate_lut8 (gray, 2, lut);
899141cc406Sopenharmony_ci	  write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x20, 0xb2, 0x07, 0xb3, 0xff,
900141cc406Sopenharmony_ci		      0xb4, 0x2f, 0xb5, 0x07);
901141cc406Sopenharmony_ci	  write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00);
902141cc406Sopenharmony_ci	  usb_bulk_write (udev, 2, lut, 4096, wr_timeout);
903141cc406Sopenharmony_ci	}
904141cc406Sopenharmony_ci      else
905141cc406Sopenharmony_ci	{
906141cc406Sopenharmony_ci	  calculate_lut8 (color, 2, lut);
907141cc406Sopenharmony_ci	  write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x10, 0xb2, 0x07, 0xb3, 0xff,
908141cc406Sopenharmony_ci		      0xb4, 0x1f, 0xb5, 0x07);
909141cc406Sopenharmony_ci	  write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00);
910141cc406Sopenharmony_ci	  usb_bulk_write (udev, 2, lut, 4096, wr_timeout);
911141cc406Sopenharmony_ci	  write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x20, 0xb2, 0x07, 0xb3, 0xff,
912141cc406Sopenharmony_ci		      0xb4, 0x2f, 0xb5, 0x07);
913141cc406Sopenharmony_ci	  write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00);
914141cc406Sopenharmony_ci	  usb_bulk_write (udev, 2, lut, 4096, wr_timeout);
915141cc406Sopenharmony_ci	  write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x30, 0xb2, 0x07, 0xb3, 0xff,
916141cc406Sopenharmony_ci		      0xb4, 0x3f, 0xb5, 0x07);
917141cc406Sopenharmony_ci	  write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00);
918141cc406Sopenharmony_ci	  usb_bulk_write (udev, 2, lut, 4096, wr_timeout);
919141cc406Sopenharmony_ci	}
920141cc406Sopenharmony_ci      break;
921141cc406Sopenharmony_ci
922141cc406Sopenharmony_ci    case 1200:
923141cc406Sopenharmony_ci    default:
924141cc406Sopenharmony_ci      lut = (unsigned char *) malloc (8192);
925141cc406Sopenharmony_ci      if (!lut)
926141cc406Sopenharmony_ci	return;
927141cc406Sopenharmony_ci
928141cc406Sopenharmony_ci      if (!incolor)
929141cc406Sopenharmony_ci	{
930141cc406Sopenharmony_ci	  calculate_lut8 (gray, 1, lut);
931141cc406Sopenharmony_ci	  write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x06, 0xb3, 0xff,
932141cc406Sopenharmony_ci		      0xb4, 0x5f, 0xb5, 0x06);
933141cc406Sopenharmony_ci	  write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00);
934141cc406Sopenharmony_ci	  usb_bulk_write (udev, 2, lut, 8192, wr_timeout);
935141cc406Sopenharmony_ci	}
936141cc406Sopenharmony_ci      else
937141cc406Sopenharmony_ci	{
938141cc406Sopenharmony_ci	  calculate_lut8 (color, 1, lut);
939141cc406Sopenharmony_ci	  write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x20, 0xb2, 0x06, 0xb3, 0xff,
940141cc406Sopenharmony_ci		      0xb4, 0x3f, 0xb5, 0x06);
941141cc406Sopenharmony_ci	  write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00);
942141cc406Sopenharmony_ci	  usb_bulk_write (udev, 2, lut, 8192, wr_timeout);
943141cc406Sopenharmony_ci	  write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x06, 0xb3, 0xff,
944141cc406Sopenharmony_ci		      0xb4, 0x5f, 0xb5, 0x06);
945141cc406Sopenharmony_ci	  write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00);
946141cc406Sopenharmony_ci	  usb_bulk_write (udev, 2, lut, 8192, wr_timeout);
947141cc406Sopenharmony_ci	  write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x60, 0xb2, 0x06, 0xb3, 0xff,
948141cc406Sopenharmony_ci		      0xb4, 0x7f, 0xb5, 0x06);
949141cc406Sopenharmony_ci	  write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00);
950141cc406Sopenharmony_ci	  usb_bulk_write (udev, 2, lut, 8192, wr_timeout);
951141cc406Sopenharmony_ci	}
952141cc406Sopenharmony_ci      break;
953141cc406Sopenharmony_ci    }
954141cc406Sopenharmony_ci
955141cc406Sopenharmony_ci  free (lut);
956141cc406Sopenharmony_ci  DBG (2, "-download_lut8\n");
957141cc406Sopenharmony_ci}
958141cc406Sopenharmony_ci
959141cc406Sopenharmony_ci
960141cc406Sopenharmony_cistatic void
961141cc406Sopenharmony_ciset_gain_black (p_usb_dev_handle udev,
962141cc406Sopenharmony_ci		int r_gain, int g_gain, int b_gain,
963141cc406Sopenharmony_ci		int r_black, int g_black, int b_black)
964141cc406Sopenharmony_ci{
965141cc406Sopenharmony_ci  write_regs (udev, 1, 0x80, 0x00);
966141cc406Sopenharmony_ci  write_regs (udev, 1, 0x80, 0x01);
967141cc406Sopenharmony_ci  write_regs (udev, 1, 0x04, 0x80);
968141cc406Sopenharmony_ci  write_regs (udev, 1, 0x04, 0x00);
969141cc406Sopenharmony_ci  write_regs (udev, 1, 0x00, 0x00);
970141cc406Sopenharmony_ci  write_regs (udev, 1, 0x01, 0x03);
971141cc406Sopenharmony_ci  write_regs (udev, 1, 0x02, 0x04);
972141cc406Sopenharmony_ci  write_regs (udev, 1, 0x03, 0x11);
973141cc406Sopenharmony_ci  write_regs (udev, 1, 0x05, 0x00);
974141cc406Sopenharmony_ci  write_regs (udev, 1, 0x28, r_gain);
975141cc406Sopenharmony_ci  write_regs (udev, 1, 0x29, g_gain);
976141cc406Sopenharmony_ci  write_regs (udev, 1, 0x2a, b_gain);
977141cc406Sopenharmony_ci  write_regs (udev, 1, 0x20, r_black);
978141cc406Sopenharmony_ci  write_regs (udev, 1, 0x21, g_black);
979141cc406Sopenharmony_ci  write_regs (udev, 1, 0x22, b_black);
980141cc406Sopenharmony_ci  write_regs (udev, 1, 0x24, 0x00);
981141cc406Sopenharmony_ci  write_regs (udev, 1, 0x25, 0x00);
982141cc406Sopenharmony_ci  write_regs (udev, 1, 0x26, 0x00);
983141cc406Sopenharmony_ci}
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci/* Handle short endianness issues */
986141cc406Sopenharmony_cistatic void
987141cc406Sopenharmony_cifix_endian_short (unsigned short *data, int count)
988141cc406Sopenharmony_ci{
989141cc406Sopenharmony_ci  unsigned short testvalue = 255;
990141cc406Sopenharmony_ci  unsigned char *firstbyte = (unsigned char *) &testvalue;
991141cc406Sopenharmony_ci  int i;
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ci  if (*firstbyte == 255)
994141cc406Sopenharmony_ci    return;			/* INTC endianness */
995141cc406Sopenharmony_ci
996141cc406Sopenharmony_ci  DBG (2, "swapping endianness...\n");
997141cc406Sopenharmony_ci  for (i = 0; i < count; i++)
998141cc406Sopenharmony_ci    data[i] = ((data[i] >> 8) & 0x00ff) | ((data[i] << 8) & 0xff00);
999141cc406Sopenharmony_ci}
1000