1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 2020 Ralph Little <skelband@gmail.com>
3    Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
4    Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
5    Copyright (c) 2003 Henning Meier-Geinitz, <henning@meier-geinitz.de>
6 
7    Originally copied from HP3300 testtools. Original notice follows:
8 
9    Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl)
10 
11    This file is part of the SANE package.
12 
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License
15    as published by the Free Software Foundation; either version 2
16    of the License, or (at your option) any later version.
17 
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21    GNU General Public License for more details.
22 
23    You should have received a copy of the GNU General Public License
24    along with this program.  If not, see <https://www.gnu.org/licenses/>.
25 
26    As a special exception, the authors of SANE give permission for
27    additional uses of the libraries contained in this release of SANE.
28 
29    The exception is that, if you link a SANE library with other files
30    to produce an executable, this does not by itself cause the
31    resulting executable to be covered by the GNU General Public
32    License.  Your use of that executable is in no way restricted on
33    account of linking the SANE library code into it.
34 
35    This exception does not, however, invalidate any other reasons why
36    the executable file might be covered by the GNU General Public
37    License.
38 
39    If you submit changes to SANE to the maintainers to be included in
40    a subsequent release, you agree by submitting the changes that
41    those changes may be distributed with this exception intact.
42 
43    If you write modifications of your own for SANE, it is your choice
44    whether to permit this exception to apply to your modifications.
45    If you do not wish that, delete this exception notice.
46 
47    HP5400/5470 Test util.
48    Currently is only able to read back the scanner version string,
49    but this basically demonstrates ability to communicate with the scanner.
50 
51    Massively expanded. Can do calibration scan, upload gamma and calibration
52    tables and stores the results of a scan. - 19/02/2003 Martijn
53 */
54 
55 #include <stdio.h>		/* for printf */
56 #include <stdlib.h>		/* for exit */
57 #include <assert.h>
58 #include <errno.h>
59 #include <string.h>
60 #include <unistd.h>
61 #include <math.h>
62 #include <netinet/in.h>		/* for htons */
63 #include <string.h>
64 
65 
66 #include "hp5400.h"
67 #include "hp5400_xfer.h"
68 #include "hp5400_internal.h"
69 #include "hp5400_debug.h" /* debug functions */
70 
71 
72 #ifndef min
73 #define min(A,B) (((A)<(B)) ? (A) : (B))
74 #endif
75 #ifndef max
76 #define max(A,B) (((A)>(B)) ? (A) : (B))
77 #endif
78 
79 
80 #ifndef STRING_VERSION_MATCH
81 #define NO_STRING_VERSION_MATCH 1
82 #endif
83 
84 #ifdef __GNUC__
85 #define PACKED __attribute__ ((packed))
86 #else
87 #define PACKED
88 #endif
89 
90 /* If this is enabled, a copy of the raw data from the scanner will be saved to
91    imagedebug.dat and the attempted conversion to imagedebug.ppm */
92 /* #define IMAGE_DEBUG */
93 
94 /* If this is defined you get extra info on the calibration */
95 /* #define CALIB_DEBUG */
96 
97 
98 typedef struct versionString {
99 	char strVersion[128];
100 } versionString;
101 
102 const int numVersions = 3;
103 versionString *MatchVersions;
104 
105 
106 static TScannerModel Model_HP54xx =
107   { "Hewlett-Packard", "HP54xx Flatbed Scanner" };
108 
109 
110 HP5400_SANE_STATIC
111 int
InitHp5400_internal()112 InitHp5400_internal() {
113 
114 	MatchVersions = malloc( sizeof(versionString) * numVersions );
115 	strcpy( MatchVersions[0].strVersion, "SilitekIBlizd C3 ScannerV0.84");
116 	strcpy( MatchVersions[1].strVersion, "SilitekIBlizd C3 ScannerV0.86");
117 	strcpy( MatchVersions[2].strVersion, "SilitekIBlizd C3 ScannerV0.87");
118 
119 	return 1;
120 }
121 
122 HP5400_SANE_STATIC
123 int
FreeHp5400_internal()124 FreeHp5400_internal() {
125 
126 	free(MatchVersions);
127 	MatchVersions = NULL;
128 
129 	return 1;
130 }
131 
132 
133 HP5400_SANE_STATIC
134 int
WriteByte(int iHandle,int cmd,char data)135 WriteByte (int iHandle, int cmd, char data)
136 {
137   if (hp5400_command_write (iHandle, cmd, 1, &data) < 0)
138     {
139       HP5400_DBG (DBG_MSG, "failed to send byte (cmd=%04X)\n", cmd);
140       return -1;
141     }
142   return 0;
143 }
144 
145 HP5400_SANE_STATIC
146 int
SetLamp(THWParams * pHWParams,int fLampOn)147 SetLamp (THWParams * pHWParams, int fLampOn)
148 {
149   if (fLampOn)
150     {
151       if (WriteByte (pHWParams->iXferHandle, 0x0000, 0x01) == 0)
152         return 0;
153     }
154   return -1;
155 }
156 
157 
158 HP5400_SANE_STATIC
159 int
GetSensors(THWParams * pHWParams,uint16_t * sensorMap)160 GetSensors(THWParams * pHWParams, uint16_t *sensorMap)
161 {
162   /*
163    * Read until we get 0.
164    * Max 10 iterations for safety.
165    *
166    */
167   *sensorMap = 0;
168   uint16_t thisSensorMap = 0;
169   size_t iterCount = 10;
170   do
171     {
172       if (hp5400_command_read
173           (pHWParams->iXferHandle, CMD_GETSENSORS, sizeof (uint16_t), &thisSensorMap) < 0)
174         {
175           HP5400_DBG (DBG_MSG, "failed to read sensors\n");
176           return -1;
177         }
178       *sensorMap |= thisSensorMap;
179     } while (iterCount-- && (thisSensorMap > 0));
180 
181     return 0;
182 }
183 
184 HP5400_SANE_STATIC
185 int
GetPanelInfo(THWParams * pHWParams,TPanelInfo * panelInfo)186 GetPanelInfo (THWParams * pHWParams, TPanelInfo *panelInfo)
187 {
188   struct PanelInfo info;
189   if (hp5400_command_read (pHWParams->iXferHandle, CMD_READPANEL,
190                            sizeof(info), &info) < 0)
191     {
192       HP5400_DBG (DBG_MSG, "failed to read panel info\n");
193       return -1;
194     }
195 
196   panelInfo->copycount = (SANE_Word)info.copycount;
197   panelInfo->bwcolour = (SANE_Word)info.bwcolour;
198 
199   return 0;
200 }
201 
202 HP5400_SANE_STATIC
203 int
SetCopyCount(THWParams * pHWParams,SANE_Word copyCount)204 SetCopyCount(THWParams * pHWParams, SANE_Word copyCount)
205 {
206 
207   /*
208    * I don't know what most of these things are but it is
209    * necessary to send something sane otherwise we get an error from the scanner.
210    * I got these settings from a USB trace.
211    * Hopefully, we will learn what it is all about at some point
212    * and hopefully it doesn't screw with other settings.
213    *
214    */
215   uint8_t packetImage[] = {0x02, 0x06, 0x32, 0x01,
216                           0xf2, 0x40, 0x16, 0x01,
217                           0x7b, 0x41, 0x16, 0x01,
218                           0xdc, 0x06, 0x32, 0x01,
219                           0xd7, 0x5b, 0x16, 0x01,
220                           0xac, 0x06, 0x32, 0x01,
221                           0xf8, 0xd7, 0x18, 0x01,
222                           0xd8, 0x06, 0x32, 0x01,
223                           0x2c, 0xf3, 0x12, 0x00,
224                           0x70, 0x8d, 0x18, 0x01,
225                           0x7b, 0x00, 0x00, 0x00};
226 
227   struct PanelInfo workingInfo;
228   (void)memcpy(&workingInfo, packetImage, sizeof(workingInfo));
229 
230   workingInfo.copycount = (uint8_t)copyCount;
231 
232   if (hp5400_command_write (pHWParams->iXferHandle, CMD_WRITEPANEL,
233                            sizeof(workingInfo), &workingInfo) < 0)
234     {
235       HP5400_DBG (DBG_MSG, "failed to write panel info\n");
236       return -1;
237     }
238 
239   return 0;
240 }
241 
242 HP5400_SANE_STATIC
243 int
SetColourBW(THWParams * pHWParams,SANE_Word colourBW)244 SetColourBW(THWParams * pHWParams, SANE_Word colourBW)
245 {
246 
247   /*
248    * I don't know what most of these things are but it is
249    * necessary to send something sane otherwise we get an error from the scanner.
250    * I got these settings from a USB trace.
251    * Hopefully, we will learn what it is all about at some point
252    * and hopefully it doesn't screw with other settings.
253    *
254    */
255   uint8_t packetImage[] = {0x03, 0x06, 0x32, 0x01,
256                           0xf2, 0x40, 0x16, 0x01,
257                           0x7b, 0x41, 0x16, 0x01,
258                           0xdc, 0x06, 0x32, 0x01,
259                           0xd7, 0x5b, 0x16, 0x01,
260                           0xac, 0x06, 0x32, 0x01,
261                           0xf8, 0xd7, 0x18, 0x01,
262                           0xd8, 0x06, 0x32, 0x01,
263                           0x68, 0xf5, 0x12, 0x00,
264                           0x70, 0x8d, 0x18, 0x01,
265                           0x7b, 0x00, 0x00, 0x00};
266 
267   struct PanelInfo workingInfo;
268   (void)memcpy(&workingInfo, packetImage, sizeof(workingInfo));
269 
270   workingInfo.bwcolour = (uint8_t)colourBW;
271 
272   if (hp5400_command_write (pHWParams->iXferHandle, CMD_WRITEPANEL,
273                            sizeof(workingInfo), &workingInfo) < 0)
274     {
275       HP5400_DBG (DBG_MSG, "failed to write panel info\n");
276       return -1;
277     }
278 
279   return 0;
280 }
281 
282 
283 
284 HP5400_SANE_STATIC
285 int
WarmupLamp(int iHandle)286 WarmupLamp (int iHandle)
287 {
288   int i = 30;			/* Max 30 seconds, 15 is typical for cold start? */
289   int couldRead;
290   unsigned char dataVerify[0x02];
291 
292   /* Keep writing 01 to 0000 until no error... */
293   unsigned char data0000[] = {
294     0x01
295   };
296   unsigned char data0300[3];
297 
298 
299   hp5400_command_write_noverify (iHandle, 0x0000, data0000, 1);
300 
301   do
302     {
303       hp5400_command_read_noverify (iHandle, 0x0300, 3, data0300);
304 
305       hp5400_command_write_noverify (iHandle, 0x0000, data0000, 1);
306 
307       couldRead =
308 	hp5400_command_read_noverify (iHandle, 0xc500, 0x02, dataVerify);
309       if ((dataVerify[0] != 0) || (dataVerify[1] != 0))
310 	sleep (1);
311     }
312   while ((i-- > 0) && (couldRead >= 0)
313 	 && ((dataVerify[0] != 0) || (dataVerify[1] != 0)));
314 
315   if (i > 0)
316     return 0;
317 
318   /*
319 
320      while( i > 0 )
321      {
322      if( WriteByte( iHandle, 0x0000, 0x01 ) == 0 )
323      return 0;
324      sleep(1);
325      i--;
326      }
327    */
328 
329   HP5400_DBG (DBG_MSG, "***WARNING*** Warmup lamp failed...\n");
330   return -1;
331 }
332 
333 #define CALPIXBYBLOCK  42
334 
335 HP5400_SANE_STATIC
336 int
SetCalibration(int iHandle,int numPixels,unsigned int * low_vals[3],unsigned int * high_vals[3],int dpi)337 SetCalibration (int iHandle, int numPixels, unsigned int *low_vals[3],
338 		unsigned int *high_vals[3], int dpi)
339 {
340   char cmd[8];
341   /* unsigned char cmd[8]; */ /* should fix the compilation warning
342 				 but I don't have a scanner right now
343 				 to check that the fix does not break
344 				 calibration */
345 
346   int i, j, k;
347   struct CalPixel
348   {
349     char highr[2], highg[2], highb[2];
350     char lowr[2], lowg[2], lowb[2];
351   };
352   struct CalBlock
353   {
354     struct CalPixel pixels[CALPIXBYBLOCK];
355     char pad[8];
356   }
357   PACKED;
358 
359   struct CalBlock *calinfo;
360 
361   /**
362    we did scan test at 300 dpi, so we don't have all the needed pixels.
363    To fill the gap, we loop
364    */
365   int numLoop = max (1, dpi / 300);
366   int calBlockSize = CALPIXBYBLOCK * (6 * sizeof (short)) + 8 * sizeof (char);	/* = sizeof(calBlock) */
367   int numCalBlock =
368     ((numPixels / CALPIXBYBLOCK) +
369      ((numPixels % CALPIXBYBLOCK != 0) ? 1 : 0));
370   int calSize = numLoop * calBlockSize * numCalBlock;
371 
372   calinfo = malloc (calSize);
373   memset (calinfo, 0, calSize);
374 
375   for (j = 0; j < numLoop * numCalBlock * CALPIXBYBLOCK; j++)
376     {
377       struct CalPixel *pixel =
378 	&calinfo[j / CALPIXBYBLOCK].pixels[j % CALPIXBYBLOCK];
379 
380       /*
381          i = ( j % (int)( 0.80 * numPixels ) ) + (int)(0.10 * numPixels );
382        */
383       /* better solution : stretch the actual scan size to the calibration size */
384       i = j / numLoop;
385 
386       /* This is obviously not quite right. The values on
387        * the right are approximately what windows sends */
388       k = (high_vals[0][i] > 0x4000) ? 1000000000 / high_vals[0][i] : 0;	/* 0x6700 */
389       pixel->highr[0] = k;
390       pixel->highr[1] = k >> 8;
391       k = (high_vals[1][i] > 0x4000) ? 1000000000 / high_vals[1][i] : 0;	/* 0x5e00 */
392       pixel->highg[0] = k;
393       pixel->highg[1] = k >> 8;
394       k = (high_vals[2][i] > 0x4000) ? 1000000000 / high_vals[2][i] : 0;	/* 0x6000 */
395       pixel->highb[0] = k;
396       pixel->highb[1] = k >> 8;
397 
398       pixel->lowr[0] = low_vals[0][i];		/* 0x0530 */
399       pixel->lowr[1] = low_vals[0][i] >> 8;
400       pixel->lowg[0] = low_vals[1][i];		/* 0x0530 */
401       pixel->lowg[1] = low_vals[1][i] >> 8;
402       pixel->lowb[0] = low_vals[2][i];		/* 0x0530 */
403       pixel->lowb[1] = low_vals[2][i] >> 8;
404     }
405 
406   cmd[0] = 0xff & (calSize >> 16);
407   cmd[1] = 0xff & (calSize >> 8);
408   cmd[2] = 0xff & (calSize >> 0);
409   cmd[3] = 0x00;
410   cmd[4] = 0x54;
411   cmd[5] = 0x02;
412   cmd[6] = -128;                // 0x80; fixes compiler warning (for
413                                 // signed char implementations), see
414                                 // also comment above
415   cmd[7] = 0x00;
416 
417   hp5400_bulk_command_write (iHandle, 0xE603, cmd, 8, calSize, calSize,
418 			     (void *) calinfo);
419 
420   free (calinfo);
421   return 0;
422 }
423 
424 /* Write a gamma table */
425 HP5400_SANE_STATIC
426 void
WriteGammaCalibTable(int iHandle,const int * pabGammaR,const int * pabGammaG,const int * pabGammaB)427 WriteGammaCalibTable (int iHandle, const int *pabGammaR, const int *pabGammaG,
428 		      const int *pabGammaB)
429 {
430   char cmd[3];
431   char *buffer;
432   int i, j;
433 
434   /* Setup dummy gamma correction table */
435   buffer = malloc (2 * 65536);
436 
437   cmd[0] = 2;
438   cmd[1] = 0;
439   cmd[2] = 0;
440 
441   for (i = 0; i < 3; i++)
442     {
443       const int *ptr = (i == 0) ? pabGammaR :
444 	(i == 1) ? pabGammaG : pabGammaB;
445 
446       for (j = 0; j < 65536; j++) {
447 	buffer[2 * j] = ptr[j];
448 	buffer[2 * j + 1] = ptr[j] >> 8;
449       }
450 
451       hp5400_bulk_command_write (iHandle, 0x2A01 + i, cmd, 3, 2 * 65536,
452 				 65536, (void *) buffer);
453     }
454   free (buffer);
455 
456   return;
457 }
458 
459 #ifdef STANDALONE
460 HP5400_SANE_STATIC
461 void
SetDefaultGamma(int iHandle)462 SetDefaultGamma (int iHandle)
463 {
464   int *buffer = malloc (sizeof (int) * 65536);
465   int i;
466 
467   for (i = 0; i < 65336; i++)
468     buffer[i] = i;
469 
470   WriteGammaCalibTable (iHandle, buffer, buffer, buffer);
471 }
472 #endif
473 
474 #define BUFFER_SIZE (6*65536)
475 
476 #ifdef IMAGE_DEBUG
477 FILE *temp;
478 #endif
479 
480 /* Bytes per line is the number of pixels. The actual bytes is one more */
481 HP5400_SANE_STATIC
482 void
CircBufferInit(int iHandle,TDataPipe * p,int iBytesPerLine,int bpp,int iMisAlignment,int blksize,int iTransferSize)483 CircBufferInit (int iHandle, TDataPipe * p, int iBytesPerLine,
484 		int bpp, int iMisAlignment, int blksize, int iTransferSize)
485 {
486   iHandle = iHandle; /* to avoid compilation warning */
487   p->buffersize = max (BUFFER_SIZE, 3 * blksize);
488 
489   if (p->buffer)
490     {
491       free (p->buffer);
492     }
493 
494   /* Allocate a large enough buffer for transfer */
495   p->buffer = malloc (p->buffersize);
496 
497   p->pixels = (iBytesPerLine / 3) / bpp;
498 
499   /* These three must always be positive */
500   p->roff = 0;
501   p->goff = p->pixels * bpp + 1;
502   p->boff = 2 * p->pixels * bpp + 2;;
503 
504   p->linelength = iBytesPerLine + 3;	/* NUL at end of each row */
505   p->bpp = bpp;
506   p->bufstart = p->bufend = 0;
507 
508   if (iMisAlignment > 0)
509     {
510       p->roff += 0;
511       p->goff += p->linelength * iMisAlignment;
512       p->boff += p->linelength * iMisAlignment * 2;
513     }
514 
515   if (iMisAlignment < 0)
516     {
517       p->roff -= p->linelength * iMisAlignment * 2;
518       p->goff -= p->linelength * iMisAlignment;
519       p->boff -= 0;
520     }
521 
522   p->blksize = blksize;
523   p->transfersize = iTransferSize;
524 
525 #ifdef IMAGE_DEBUG
526   temp = fopen ("imagedebug.dat", "w+b");
527 #endif
528 
529   HP5400_DBG (DBG_MSG,
530        "Begin: line=%d (%X), pixels=%d (%X), r=%d (%X), g=%d (%X), b=%d (%X), bpp=%d, step=%d\n",
531        p->linelength, p->linelength, p->pixels, p->pixels, p->roff, p->roff,
532        p->goff, p->goff, p->boff, p->boff, bpp, iMisAlignment);
533 }
534 
535 
536 HP5400_SANE_STATIC
537 int
CircBufferGetLine(int iHandle,TDataPipe * p,void * pabLine)538 CircBufferGetLine (int iHandle, TDataPipe * p, void *pabLine)
539 {
540   int i;
541   int maxoff = 0;
542   char* buftmp = (char*) (p->buffer);
543 
544 /*  HP5400_DBG(DBG_MSG, "CircBufferGetLine:\n");   */
545 
546   if (p->roff > maxoff)
547     maxoff = p->roff;
548   if (p->goff > maxoff)
549     maxoff = p->goff;
550   if (p->boff > maxoff)
551     maxoff = p->boff;
552 
553   maxoff += p->pixels * p->bpp;
554 
555   if (maxoff < p->linelength)
556     maxoff = p->linelength;
557 
558 
559   /* resize buffer if needed */
560   if (p->bufstart + maxoff >= p->buffersize + p->blksize)
561     {
562       /* store actual buffer pointer */
563       void *tmpBuf = p->buffer;
564       /* calculate new size for buffer (oversize a bit) */
565       int newsize = p->bufstart + maxoff + 2 * p->blksize;
566 
567       p->buffer = malloc (newsize);
568       memcpy (p->buffer, tmpBuf, p->buffersize);
569       p->buffersize = newsize;
570 
571       /* free old buffer */
572       free (tmpBuf);
573       buftmp = (char*)(p->buffer);
574     }
575 
576   while (p->bufstart + maxoff >= p->bufend)	/* Not enough data in buffer */
577     {
578       int res;
579       unsigned char cmd[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
580       cmd[4] = p->blksize;
581       cmd[5] = p->blksize >> 8;
582 
583       assert ((p->bufend + p->blksize) <= p->buffersize);
584 
585       HP5400_DBG (DBG_MSG, "Reading block, %d bytes remain\n", p->transfersize);
586       p->transfersize -= p->blksize;
587 
588       res =
589 	hp5400_bulk_read_block (iHandle, CMD_INITBULK3, cmd, sizeof (cmd),
590     				buftmp + p->bufend, p->blksize);
591       if (res != p->blksize)
592 	{
593 	  HP5400_DBG (DBG_ERR, "*** ERROR: Read returned %d. FATAL.\n", res);
594 	  return -1;
595 	}
596 #ifdef IMAGE_DEBUG
597       fwrite (
598     	buftmp + p->bufend
599 	,p->blksize
600 	,1
601 	,temp
602 	);
603 #endif
604       p->bufend += p->blksize;
605     }
606 
607   assert (p->bufstart + maxoff < p->bufend);
608 
609   /* Copy a line into the result buffer */
610   if (p->bpp == 1)
611     {
612       char *itPix = (char *) pabLine;
613       char *itR = (char *) (buftmp + p->bufstart + p->roff);
614       char *itG = (char *) (buftmp + p->bufstart + p->goff);
615       char *itB = (char *) (buftmp + p->bufstart + p->boff);
616       for (i = 0; i < p->pixels; i++)
617 	{
618 	  /* pointer move goes a little bit faster than vector access */
619 	  /* Although I wouldn't be surprised if the compiler worked that out anyway.
620 	   * No matter, this is easier to read :) */
621 	  *(itPix++) = *(itR++);
622 	  *(itPix++) = *(itG++);
623 	  *(itPix++) = *(itB++);
624 	}
625     }
626   else
627     {
628       short *itPix = (short *) pabLine;
629       short *itR = (short *) (buftmp + p->bufstart + p->roff);
630       short *itG = (short *) (buftmp + p->bufstart + p->goff);
631       short *itB = (short *) (buftmp + p->bufstart + p->boff);
632       for (i = 0; i < p->pixels; i++)
633 	{
634 #if 0
635 	  /* This code, while correct for PBM is not correct for the host and
636 	   * since we need it correct for calibration, it has to go */
637 	  ((short *) pabLine)[3 * i + 0] =
638 	    *((short *) (p->buffer + p->bufstart + p->roff + 2 * i));
639 	  ((short *) pabLine)[3 * i + 1] =
640 	    *((short *) (p->buffer + p->bufstart + p->goff + 2 * i));
641 	  ((short *) pabLine)[3 * i + 2] =
642 	    *((short *) (p->buffer + p->bufstart + p->boff + 2 * i));
643 #else
644 	  /* pointer move goes a little bit faster than vector access */
645 	  *(itPix++) = htons (*(itR++));
646 	  *(itPix++) = htons (*(itG++));
647 	  *(itPix++) = htons (*(itB++));
648 #endif
649 	}
650     }
651 
652   p->bufstart += p->linelength;
653 
654   assert (p->bufstart <= p->bufend);
655 
656   /* If we've used a whole block at the beginning, move it */
657   if (p->bufstart > p->blksize)
658     {
659       memmove (
660 	buftmp
661 	,buftmp + p->bufstart
662 	,p->bufend - p->bufstart
663 	);
664 
665       p->bufend -= p->bufstart;
666       p->bufstart = 0;
667     }
668 
669   return 0;
670 }
671 
672 HP5400_SANE_STATIC
673 void
CircBufferExit(TDataPipe * p)674 CircBufferExit (TDataPipe * p)
675 {
676   free (p->buffer);
677   p->buffer = NULL;
678 #ifdef IMAGE_DEBUG
679   fclose (temp);
680   temp = NULL;
681 #endif
682   return;
683 }
684 
685 
686 #ifdef STANDALONE
687 /* bpp is BYTES per pixel */
688 HP5400_SANE_STATIC
689 void
DecodeImage(FILE * file,int planes,int bpp,int xsize,int ysize,const char * filename)690 DecodeImage (FILE * file, int planes, int bpp, int xsize, int ysize,
691 	     const char *filename)
692 {
693   char *in, *buf;
694   char *p[3];
695   FILE *output;
696   int i, j, k;
697 
698   /* xsize is byte width, not pixel width */
699   xsize /= planes * bpp;
700 
701   HP5400_DBG (DBG_MSG,
702        "DecodeImage(planes=%d,bpp=%d,xsize=%d,ysize=%d) => %d (file=%s)\n",
703        planes, bpp, xsize, ysize, planes * bpp * xsize * ysize, filename);
704 
705   in = malloc (planes * (xsize * bpp + 1));
706 
707   for (i = 0; i < planes; i++)
708     p[i] = in + i * (xsize * bpp + 1);
709 
710   buf = malloc (3 * xsize * bpp);
711 
712   output = fopen (filename, "wb");
713 
714   fprintf (output, "P%d\n%d %d\n", (planes == 3) ? 6 : 5, xsize, ysize);
715   fprintf (output, "%d\n", (bpp == 1) ? 255 : 0xb000);
716 
717   for (i = 0; i < ysize; i++)
718     {
719       fread (in, planes * (xsize * bpp + 1), 1, file);
720 
721       for (j = 0; j < xsize; j++)
722 	{
723 	  for (k = 0; k < planes; k++)
724 	    {
725 	      if (bpp == 1)
726 		{
727 		  buf[j * planes + k] = p[k][j];
728 		}
729 	      else if (bpp == 2)
730 		{
731 		  buf[j * planes * 2 + k * 2 + 0] = p[k][2 * j + 0];
732 		  buf[j * planes * 2 + k * 2 + 1] = p[k][2 * j + 1];
733 		}
734 	    }
735 	}
736       fwrite (buf, planes * xsize * bpp, 1, output);
737     }
738 
739   fclose (output);
740 
741   free (in);
742   free (buf);
743 }
744 
745 HP5400_SANE_STATIC
746 int
hp5400_test_scan_response(struct ScanResponse * resp,struct ScanRequest * req)747 hp5400_test_scan_response (struct ScanResponse *resp, struct ScanRequest *req)
748 {
749   req = req; /* to avoid compilation warning */
750   HP5400_DBG (DBG_MSG, "Scan response:\n");
751   HP5400_DBG (DBG_MSG, "  transfersize=%d   htonl-> %d\n", resp->transfersize,
752        htonl (resp->transfersize));
753   HP5400_DBG (DBG_MSG, "  xsize=%d    htonl-> %d\n", resp->xsize,
754        htonl (resp->xsize));
755   HP5400_DBG (DBG_MSG, "  ysize=%d    htons-> %d\n", resp->ysize,
756        htons (resp->ysize));
757   return 1;
758 }
759 #endif
760 
761 /* This is a very specialised scanning function. It does the scan request as
762  * usual but instead of producing an image it returns three arrays of ints.
763  * These are averages of the R,G,B values for each column.
764  *
765  * Note the array argument should point to an array of three NULL. These
766  * will be overwritten with allocated pointers. */
767 
768 HP5400_SANE_STATIC
769 int
DoAverageScan(int iHandle,struct ScanRequest * req,int code,unsigned int ** array)770 DoAverageScan (int iHandle, struct ScanRequest *req, int code,
771 	       unsigned int **array)
772 {
773   THWParams HWParams;
774   struct ScanResponse res;
775   unsigned short *buffer;
776   int i, j, k, length;
777 
778   memset (&HWParams, 0, sizeof (HWParams));
779 
780   HWParams.iXferHandle = iHandle;
781 
782   if (InitScan2 (SCAN_TYPE_CALIBRATION, req, &HWParams, &res, 0, code) != 0)
783     return -1;			/* No colour offsetting, we want raw */
784 
785   length = htonl (res.xsize) / 6;
786 
787   HP5400_DBG (DBG_MSG, "Calibration scan: %d pixels wide\n", length);
788 
789   for (j = 0; j < 3; j++)
790     {
791       array[j] = malloc (sizeof (int) * length);
792       memset (array[j], 0, sizeof (int) * length);	/* Clear array */
793     }
794 
795   buffer = malloc (htonl (res.xsize) + 1);
796 
797   /* First we just sum them all */
798   for (i = 0; i < htons (res.ysize); i++)
799     {
800       CircBufferGetLine (iHandle, &HWParams.pipe, buffer);
801 
802       for (j = 0; j < length; j++)
803 	for (k = 0; k < 3; k++)
804 	  array[k][j] += buffer[3 * j + k];
805     }
806 
807   free (buffer);
808   FinishScan (&HWParams);
809 
810   /* Now divide by the height to get the average */
811   for (j = 0; j < length; j++)
812     for (k = 0; k < 3; k++)
813       array[k][j] /= htons (res.ysize);
814 
815   return 0;
816 }
817 
818 #ifdef STANDALONE
819 HP5400_SANE_STATIC
820 int
DoScan(int iHandle,struct ScanRequest * req,const char * filename,int code,struct ScanResponse * res)821 DoScan (int iHandle, struct ScanRequest *req, const char *filename, int code,
822 	struct ScanResponse *res)
823 {
824   FILE *file;
825   THWParams HWParams;
826   struct ScanResponse res_temp;
827   void *buffer;
828 /*  int bpp, planes; */
829   int i;
830 
831   code = code; /*to avoid compilation warning*/
832 
833   if (res == NULL)
834     res = &res_temp;
835 
836   memset (&HWParams, 0, sizeof (HWParams));
837 
838   file = fopen (filename, "w+b");
839   if (!file)
840     {
841       HP5400_DBG (DBG_MSG, "Couldn't open outputfile (%s)\n", strerror (errno));
842       return -1;
843     }
844 
845   HWParams.iXferHandle = iHandle;
846 
847   if (InitScan2 (SCAN_TYPE_NORMAL, req, &HWParams, res, 1, 0x40) != 0)
848     return -1;
849 
850   fprintf (file, "P%d\n%d %d\n", 6, htonl (res->xsize) / 3,
851 	   htons (res->ysize));
852   fprintf (file, "%d\n", 255);
853 
854   buffer = malloc (htonl (res->xsize) + 1);
855   for (i = 0; i < htons (res->ysize); i++)
856     {
857       CircBufferGetLine (iHandle, &HWParams.pipe, buffer);
858 
859       fwrite (buffer, htonl (res->xsize), 1, file);
860     }
861   free (buffer);
862 
863   FinishScan (&HWParams);
864 
865   fclose (file);
866   return 0;
867 }
868 #endif
869 
870 HP5400_SANE_STATIC
871 int
Calibrate(int iHandle,int dpi)872 Calibrate (int iHandle, int dpi)
873 {
874   struct ScanRequest req;
875 
876   unsigned int *low_array[3];
877   unsigned int *high_array[3];
878 #ifdef CALIB_DEBUG
879   char buffer[512];
880   int i, j;
881 #endif
882 
883 /* The first calibration scan. Finds maximum of each CCD */
884   memset(&req, 0, sizeof(req));
885 
886   req.x1 = 0x08;
887   req.dpix = htons (300);	/* = 300 dpi */
888   req.dpiy = htons (300);	/* = 300 dpi */
889   req.offx = htons (0);		/* = 0cm */
890   req.offy = htons (0);		/* = 0cm */
891   req.lenx = htons (2690);	/* = 22.78cm */
892   req.leny = htons (50);	/* =  0.42cm */
893 
894   req.flags1 = htons (0x0000);
895   req.flags2 = htons (0x0010);
896   req.flags3 = htons (0x3020);	/* First calibration scan, 48bpp */
897 
898   req.gamma[0] = htons (100);
899   req.gamma[1] = htons (100);
900   req.gamma[2] = htons (100);
901 
902   if (DoAverageScan (iHandle, &req, 0x40, high_array) != 0)
903     return -1;
904 
905 #ifdef CALIB_DEBUG
906   for (i = 0; i < 3; i++)
907     {
908       int len;
909       buffer[0] = 0;
910       sprintf (buffer, "Average %d: \n", i);
911       len = strlen (buffer);
912 
913       for (j = 0; j < 24; j++)
914 	{
915 	  sprintf (buffer + len, "%04X ", high_array[i][j]);
916 	  len += 5;
917 	}
918       strcat (buffer, " ... \n");
919       len += 6;
920 
921       for (j = 1000; j < 1024; j++)
922 	{
923 	  sprintf (buffer + len, "%04X ", high_array[i][j]);
924 	  len += 5;
925 	}
926       strcat (buffer, " ... \n");
927       len += 6;
928 
929       for (j = 2000; j < 2024; j++)
930 	{
931 	  sprintf (buffer + len, "%04X ", high_array[i][j]);
932 	  len += 5;
933 	}
934       strcat (buffer, " ... \n");
935       len += 6;
936 
937       HP5400_DBG (DBG_MSG, buffer);
938     }
939 #endif
940 
941 /* The second calibration scan. Finds minimum of each CCD */
942   memset(&req, 0, sizeof(req));
943 
944   req.x1 = 0x08;
945   req.dpix = htons (300);	/* = 300 dpi */
946   req.dpiy = htons (300);	/* = 300 dpi */
947   req.offx = htons (0);		/* = 0cm */
948   req.offy = htons (0);		/* = 0cm */
949   req.lenx = htons (2690);	/* = 22.78cm */
950   req.leny = htons (16);	/* =  0.14cm */
951 
952   req.flags1 = htons (0x0000);
953   req.flags2 = htons (0x0010);
954   req.flags3 = htons (0x3024);	/* Second calibration scan, 48bpp */
955 
956   req.gamma[0] = htons (100);
957   req.gamma[1] = htons (100);
958   req.gamma[2] = htons (100);
959 
960   if (DoAverageScan (iHandle, &req, 0x00, low_array) != 0)
961     return -1;
962 
963 #ifdef CALIB_DEBUG
964   for (i = 0; i < 3; i++)
965     {
966       int len;
967       buffer[0] = 0;
968       sprintf (buffer, "Average %d: \n", i);
969       len = strlen (buffer);
970 
971       for (j = 0; j < 24; j++)
972 	{
973 	  sprintf (buffer + len, "%04X ", low_array[i][j]);
974 	  len += 5;
975 	}
976       strcat (buffer, " ... \n");
977       len += 6;
978 
979       for (j = 1000; j < 1024; j++)
980 	{
981 	  sprintf (buffer + len, "%04X ", low_array[i][j]);
982 	  len += 5;
983 	}
984       strcat (buffer, " ... \n");
985       len += 6;
986 
987       for (j = 2000; j < 2024; j++)
988 	{
989 	  sprintf (buffer + len, "%04X ", low_array[i][j]);
990 	  len += 5;
991 	}
992       strcat (buffer, " ... \n");
993       len += 6;
994 
995       HP5400_DBG (DBG_MSG, buffer);
996     }
997 #endif
998 
999   SetCalibration (iHandle, 2690, low_array, high_array, dpi);
1000 
1001   return 0;
1002 }
1003 
1004 #ifdef STANDALONE
1005 HP5400_SANE_STATIC
1006 int
hp5400_scan(int iHandle,TScanParams * params,THWParams * pHWParams,const char * filename)1007 hp5400_scan (int iHandle, TScanParams * params, THWParams * pHWParams,
1008 	     const char *filename)
1009 {
1010   struct ScanRequest req;
1011   struct ScanResponse res;
1012   int result;
1013 
1014   pHWParams = pHWParams; /*to avoid compilation warning*/
1015 
1016   HP5400_DBG (DBG_MSG, "\n");
1017   HP5400_DBG (DBG_MSG, "Scanning :\n");
1018   HP5400_DBG (DBG_MSG, "   dpi(x) : %d\n", params->iDpi);
1019   HP5400_DBG (DBG_MSG, "   dpi(y) : %d\n", params->iLpi);
1020   HP5400_DBG (DBG_MSG, "   x0 : %d\n", params->iLeft);
1021   HP5400_DBG (DBG_MSG, "   y0 : %d\n", params->iTop);
1022   HP5400_DBG (DBG_MSG, "   width : %d\n", params->iWidth);
1023   HP5400_DBG (DBG_MSG, "   height : %d\n", params->iHeight);
1024   HP5400_DBG (DBG_MSG, "\n");
1025 
1026   memset(&req, 0, sizeof(req));
1027 
1028   req.x1 = 0x08;
1029   req.dpix = htons (params->iDpi);
1030   req.dpiy = htons (params->iLpi);
1031 
1032   /* These offsets and lengths should all be in the reference DPI which
1033    * is set to HW_LPI */
1034   req.offx = htons (params->iLeft);
1035   req.offy = htons (params->iTop);
1036   req.lenx = htons (params->iWidth);
1037   req.leny = htons (params->iHeight);
1038 
1039   req.flags1 = htons (0x0080);
1040   req.flags2 = htons (0x0000);
1041   req.flags3 = htons ((params->iDpi < 2400) ? 0x18E8 : 0x18C0);	/* Try preview scan */
1042 
1043   req.gamma[0] = htons (100);
1044   req.gamma[1] = htons (100);
1045   req.gamma[2] = htons (100);
1046 
1047   if (Calibrate (iHandle, params->iDpi) != 0)
1048     return -1;
1049   SetDefaultGamma (iHandle);
1050 
1051   result = DoScan (iHandle, &req, filename, 0x40, &res);
1052 
1053   /* Pass the results back to the parent */
1054   params->iBytesPerLine = htonl (res.xsize);
1055   params->iLines = htons (res.ysize);
1056 
1057 #if 0
1058   imageFile = fopen ("output.dat", "r+b");
1059   if (imageFile)
1060     {
1061       int planes = 3;
1062       int bpp = 1;
1063       fseek (imageFile, 0, SEEK_SET);
1064       DecodeImage (imageFile, planes, bpp, planes * bpp * params->iWidth,
1065 		   params->iHeight, filename);
1066       fclose (imageFile);
1067     }
1068 #endif
1069   return result;
1070 }
1071 
1072 HP5400_SANE_STATIC
1073 int
PreviewScan(int iHandle)1074 PreviewScan (int iHandle)
1075 {
1076   TScanParams params;
1077   THWParams pHWParams;
1078 
1079   /* Reference LPI is 300dpi, remember */
1080   params.iDpi = 75;
1081   params.iLpi = 75;
1082   params.iLeft = 0;
1083   params.iTop = 0;
1084   params.iWidth = 2552;		/* = 21.61cm * 300dpi */
1085   params.iHeight = 3510;	/* = 29.72cm * 300dpi */
1086   params.iColourOffset = 1;
1087 
1088   return hp5400_scan (iHandle, &params, &pHWParams, "output.ppm");
1089 }
1090 
1091 
1092 static char UISetup1[] = {
1093 /* Offset 40 */
1094   0x50, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6E, 0x67, 0x14, 0x00,
1095     0x52, 0x65, 0x61, 0x64,
1096   0x79, 0x00, 0x53, 0x63, 0x61, 0x6E, 0x6E, 0x65, 0x72, 0x20, 0x4C, 0x6F,
1097     0x63, 0x6B, 0x65, 0x64,
1098   0x00, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x00, 0x43, 0x61, 0x6E, 0x63, 0x65,
1099     0x6C, 0x69, 0x6E, 0x67,
1100   0x14, 0x00, 0x50, 0x6F, 0x77, 0x65, 0x72, 0x53, 0x61, 0x76, 0x65, 0x20,
1101     0x4F, 0x6E, 0x00, 0x53,
1102 };
1103 
1104 static char UISetup2[] = {
1105 
1106   0x63, 0x61, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x14, 0x00, 0x41, 0x44, 0x46,
1107     0x20, 0x70, 0x61, 0x70,
1108   0x65, 0x72, 0x20, 0x6A, 0x61, 0x6D, 0x00, 0x43, 0x6F, 0x70, 0x69, 0x65,
1109     0x73, 0x00, 0x00,
1110 };
1111 
1112 HP5400_SANE_STATIC
1113 int
InitScanner(int iHandle)1114 InitScanner (int iHandle)
1115 {
1116   WarmupLamp (iHandle);
1117 
1118   if (WriteByte (iHandle, 0xF200, 0x40) < 0)
1119     return -1;
1120 
1121   if (hp5400_command_write (iHandle, 0xF10B, sizeof (UISetup1), UISetup1) < 0)
1122     {
1123       HP5400_DBG (DBG_MSG, "failed to send UISetup1 (%lu)\n", (u_long) sizeof (UISetup1));
1124       return -1;
1125     }
1126 
1127   if (WriteByte (iHandle, 0xF200, 0x00) < 0)
1128     return -1;
1129 
1130   if (hp5400_command_write (iHandle, 0xF10C, sizeof (UISetup2), UISetup2) < 0)
1131     {
1132       HP5400_DBG (DBG_MSG, "failed to send UISetup2\n");
1133       return -1;
1134     }
1135   return 0;
1136 }
1137 #endif
1138 
1139 /* Warning! The caller must have configured the gamma tables at this stage */
1140 HP5400_SANE_STATIC
1141 int
InitScan(enum ScanType scantype,TScanParams * pParams,THWParams * pHWParams)1142 InitScan (enum ScanType scantype, TScanParams * pParams,
1143 	  THWParams * pHWParams)
1144 {
1145   struct ScanRequest req;
1146   struct ScanResponse res;
1147   int ret;
1148 
1149   memset(&req, 0, sizeof(req));
1150 
1151   req.x1 = 0x08;
1152   req.dpix = htons (pParams->iDpi);	/* = 300 dpi */
1153   req.dpiy = htons (pParams->iLpi);	/* = 300 dpi */
1154   req.offx = htons (pParams->iLeft);	/* = 0cm */
1155   req.offy = htons (pParams->iTop);	/* = 0cm */
1156   req.lenx = htons (pParams->iWidth);	/* = 22.78cm */
1157 
1158   /* Scan a few extra rows so we can colour offset properly. At 300dpi the
1159    * difference is 4 lines */
1160 
1161   req.leny = htons (pParams->iHeight);	/* =  0.42cm */
1162 
1163   req.flags1 = htons ((scantype == SCAN_TYPE_CALIBRATION) ? 0x0000 : 0x0080);
1164   req.flags2 = htons ((scantype == SCAN_TYPE_CALIBRATION) ? 0x0010 :
1165 		      (scantype == SCAN_TYPE_PREVIEW) ? 0x0000 :
1166 		      /* SCAN_TYPE_NORMAL  */ 0x0040);
1167   req.flags3 = htons (0x18E8);
1168 
1169   req.gamma[0] = htons (100);
1170   req.gamma[1] = htons (100);
1171   req.gamma[2] = htons (100);
1172 
1173   if (Calibrate (pHWParams->iXferHandle, pParams->iDpi) != 0)
1174     return -1;
1175 /*  SetDefaultGamma( pHWParams->iXferHandle ); ** Must be done by caller */
1176 
1177   HP5400_DBG (DBG_MSG, "Calibration complete\n");
1178   ret =
1179     InitScan2 (scantype, &req, pHWParams, &res, pParams->iColourOffset, 0x40);
1180 
1181   HP5400_DBG (DBG_MSG, "InitScan2 returned %d\n", ret);
1182 
1183   /* Pass the results back to the parent */
1184   pParams->iBytesPerLine = htonl (res.xsize);
1185 
1186   /* Hide the extra lines we're scanning */
1187   pParams->iLines = htons (res.ysize);
1188 
1189   return ret;			/* 0 is good, -1 is bad */
1190 }
1191 
1192 /* For want of a better name ... */
1193 HP5400_SANE_STATIC
1194 int
InitScan2(enum ScanType scantype,struct ScanRequest * req,THWParams * pHWParams,struct ScanResponse * result,int iColourOffset,int code)1195 InitScan2 (enum ScanType scantype, struct ScanRequest *req,
1196 	   THWParams * pHWParams, struct ScanResponse *result,
1197 	   int iColourOffset, int code)
1198 {
1199   struct ScanResponse res;
1200   int iHandle = pHWParams->iXferHandle;
1201 
1202   memset(&res, 0, sizeof(res));
1203 
1204   /* Protect scanner from damage. This stops stpuid errors.  It basically
1205    * limits you to the scanner glass. Stuff like calibrations which need
1206    * more access do it safely by fiddling other parameters. Note you can
1207    * still break things by fiddling the ScanOffset, but that is not yet
1208    * under user control */
1209 
1210   if (scantype != SCAN_TYPE_CALIBRATION)
1211     {
1212       HP5400_DBG (DBG_MSG, "Off(%d,%d) : Len(%d,%d)\n", htons (req->offx),
1213 	   htons (req->offy), htons (req->lenx), htons (req->leny));
1214       /* Yes, all the htons() is silly but we want this check as late as possible */
1215       if (htons (req->offx) > 0x09F8)
1216 	req->offx = htons (0x09F8);
1217       if (htons (req->offy) > 0x0DB6)
1218 	req->offy = htons (0x0DB6);
1219       /* These tests are meaningless as htons() returns unsigned
1220          if( htons( req->offx ) < 0      ) req->offx = 0;
1221          if( htons( req->offy ) < 0      ) req->offy = 0;
1222        */
1223       if (htons (req->offx) + htons (req->lenx) > 0x09F8)
1224 	req->lenx = htons (0x09F8 - htons (req->offx));
1225       if (htons (req->offy) + htons (req->leny) > 0x0DB6)
1226 	req->leny = htons (0x0DB6 - htons (req->offy));
1227       if (htons (req->lenx) <= 1)
1228 	return -1;
1229       if (htons (req->leny) <= 1)
1230 	return -1;
1231     }
1232 
1233   WarmupLamp (iHandle);
1234 
1235   {				/* Try to set it to make scan succeed, URB 53 *//*  0x1B01 => 0x40  */
1236     /* I think this tries to cancel any existing scan */
1237     char flag = 0x40;
1238     if (hp5400_command_write (iHandle, CMD_STOPSCAN, sizeof (flag), &flag) <
1239 	0)
1240       {
1241 	HP5400_DBG (DBG_MSG, "failed to cancel scan flag\n");
1242 	return -1;
1243       }
1244   }
1245 
1246   {				/* Try to set it to make scan succeed, URB 55  */
1247     char data[4] = { 0x02, 0x03, 0x03, 0x3C };
1248     if (hp5400_command_write (iHandle, CMD_UNKNOWN3, sizeof (data), data) < 0)
1249       {
1250 	HP5400_DBG (DBG_MSG, "failed to set unknown1\n");
1251 	return -1;
1252       }
1253   }
1254 
1255   {				/* Try to set it to make scan succeed, URB 59 */
1256     char flag = 0x04;
1257     if (hp5400_command_write (iHandle, CMD_UNKNOWN2, sizeof (flag), &flag) <
1258 	0)
1259       {
1260 	HP5400_DBG (DBG_MSG, "failed to set unknown2\n");
1261 	return -1;
1262       }
1263   }
1264 
1265   {				/* URB 67 *//* Reference DPI = 300 currently */
1266     short dpi = htons (HW_LPI);
1267     if (hp5400_command_write (iHandle, CMD_SETDPI, sizeof (dpi), &dpi) < 0)
1268       {
1269 	HP5400_DBG (DBG_MSG, "failed to set dpi\n");
1270 	return -1;
1271       }
1272   }
1273 
1274   if (scantype != SCAN_TYPE_CALIBRATION)
1275     {				/* Setup scan offsets - Should only apply to non-calibration scans */
1276       short offsets[2];
1277 
1278       offsets [0] = htons (0x0054);
1279       offsets [1] = htons (0x0282);
1280 
1281       if (hp5400_command_write
1282 	  (iHandle, CMD_SETOFFSET, sizeof (offsets), offsets) < 0)
1283 	{
1284 	  HP5400_DBG (DBG_MSG, "failed to set offsets\n");
1285 	  return -1;
1286 	}
1287     }
1288 
1289   HP5400_DBG (DBG_MSG, "Scan request: \n  ");
1290   {
1291     size_t i;
1292     for (i = 0; i < sizeof (*req); i++)
1293       {
1294 	HP5400_DBG (DBG_MSG, "%02X ", ((unsigned char *) req)[i]);
1295       }
1296     HP5400_DBG (DBG_MSG, "\n");
1297   }
1298 
1299   if (hp5400_command_write
1300       (iHandle,
1301        (scantype !=
1302 	SCAN_TYPE_CALIBRATION) ? CMD_SCANREQUEST2 : CMD_SCANREQUEST,
1303        sizeof (*req), req) < 0)
1304     {
1305       HP5400_DBG (DBG_MSG, "failed to send scan request\n");
1306       return -1;
1307     }
1308 
1309   {				/* Try to set it to make scan succeed, URB 71 */
1310     char flag = code;		/* Start scan with light on or off as requested */
1311     if (hp5400_command_write (iHandle, CMD_STARTSCAN, sizeof (flag), &flag) <
1312 	0)
1313       {
1314 	HP5400_DBG (DBG_MSG, "failed to set gamma flag\n");
1315 	return -1;
1316       }
1317   }
1318 
1319   if (hp5400_command_read (iHandle, CMD_SCANRESPONSE, sizeof (res), &res) < 0)
1320     {
1321       HP5400_DBG (DBG_MSG, "failed to read scan response\n");
1322       return -1;
1323     }
1324 
1325   HP5400_DBG (DBG_MSG, "Scan response: \n  ");
1326   {
1327     size_t i;
1328     for (i = 0; i < sizeof (res); i++)
1329       {
1330 	HP5400_DBG (DBG_MSG, "%02X ", ((unsigned char *) &res)[i]);
1331       }
1332     HP5400_DBG (DBG_MSG, "\n");
1333   }
1334 
1335   HP5400_DBG (DBG_MSG, "Bytes to transfer: %d\nBitmap resolution: %d x %d\n",
1336        htonl (res.transfersize), htonl (res.xsize), htons (res.ysize));
1337 
1338   HP5400_DBG (DBG_MSG, "Proceeding to scan\n");
1339 
1340   if (htonl (res.transfersize) == 0)
1341     {
1342       HP5400_DBG (DBG_MSG, "Hmm, size is zero. Obviously a problem. Aborting...\n");
1343       return -1;
1344     }
1345 
1346   {
1347     char x1 = 0x14, x2 = 0x24;
1348 
1349     float pixels = ((float) htons (req->lenx) * (float) htons (req->leny)) *
1350       ((float) htons (req->dpix) * (float) htons (req->dpiy)) /
1351       ((float) HW_LPI * (float) HW_LPI);
1352     int bpp = (int) ((float) htonl (res.transfersize) / pixels + 0.5);
1353     int planes = (bpp == 1) ? 1 : 3;
1354     bpp /= planes;
1355 
1356     HP5400_DBG (DBG_MSG, "bpp = %d / ( (%d * %d) * (%d * %d) / (%d * %d) ) = %d\n",
1357 	 htonl (res.transfersize),
1358 	 htons (req->lenx), htons (req->leny),
1359 	 htons (req->dpix), htons (req->dpiy), HW_LPI, HW_LPI, bpp);
1360 
1361     hp5400_command_write_noverify (iHandle, CMD_INITBULK1, &x1, 1);
1362     hp5400_command_write_noverify (iHandle, CMD_INITBULK2, &x2, 1);
1363 
1364     if (bpp > 2)		/* Bug!! */
1365       bpp = 2;
1366 
1367     CircBufferInit (pHWParams->iXferHandle, &pHWParams->pipe,
1368 		    htonl (res.xsize), bpp, iColourOffset, 0xF000,
1369 		    htonl (res.transfersize) + 3 * htons (res.ysize));
1370   }
1371 
1372   if (result)			/* copy ScanResult to parent if they asked for it */
1373     memcpy (result, &res, sizeof (*result));
1374 
1375   return 0;
1376 }
1377 
1378 HP5400_SANE_STATIC
1379 void
FinishScan(THWParams * pHWParams)1380 FinishScan (THWParams * pHWParams)
1381 {
1382   int iHandle = pHWParams->iXferHandle;
1383 
1384   CircBufferExit (&pHWParams->pipe);
1385 
1386   {				/* Finish scan request */
1387     char flag = 0x40;
1388     if (hp5400_command_write (iHandle, CMD_STOPSCAN, sizeof (flag), &flag) <
1389 	0)
1390       {
1391 	HP5400_DBG (DBG_MSG, "failed to set gamma flag\n");
1392 	return;
1393       }
1394   }
1395 }
1396 
1397 HP5400_SANE_STATIC
1398 int
HP5400Open(THWParams * params,const char * filename)1399 HP5400Open (THWParams * params, const char *filename)
1400 {
1401   int iHandle = hp5400_open (filename);
1402   char szVersion[32];
1403   int i;
1404 #ifndef NO_STRING_VERSION_MATCH
1405   int versionMatched;
1406 #endif
1407 
1408   if (iHandle < 0)
1409     {
1410       HP5400_DBG (DBG_MSG, "hp5400_open failed\n");
1411       return -1;
1412     }
1413 
1414   params->iXferHandle = 0;
1415 
1416   /* read version info */
1417   if (hp5400_command_read
1418       (iHandle, CMD_GETVERSION, sizeof (szVersion), szVersion) < 0)
1419     {
1420       HP5400_DBG (DBG_MSG, "failed to read version string\n");
1421       goto hp5400_close_exit;
1422     }
1423 
1424 	  HP5400_DBG (DBG_MSG, "version String :\n");
1425     for (i=0; i < 32; i++) {
1426       HP5400_DBG (DBG_MSG, "%c\n", szVersion[i]);
1427     }
1428     HP5400_DBG (DBG_MSG, "\n");
1429 
1430 #ifndef NO_STRING_VERSION_MATCH
1431   i = 0;
1432   versionMatched = 0;
1433   while ( !versionMatched && (i < numVersions) ) {
1434 	if (!strncmp (szVersion + 1, MatchVersions[i] .strVersion, strlen(MatchVersions[i] .strVersion) - 4)) {
1435 		versionMatched = 1;
1436 	}
1437   	i++;
1438   }
1439   if ( !versionMatched ) {
1440 	HP5400_DBG (DBG_MSG,
1441 	       "Sorry, unknown scanner version. Attempted match on :\n");
1442 	i = 0;
1443 	while ( i < numVersions ) {
1444 		HP5400_DBG (DBG_MSG, "* '%s'\n", MatchVersions[i] .strVersion);
1445 		i++;
1446 	}
1447 	HP5400_DBG (DBG_MSG, "Version is '%s'\n", szVersion);
1448 	goto hp5400_close_exit;
1449     }
1450 #else
1451   HP5400_DBG (DBG_MSG, "Warning, Version match is disabled. Version is '%s'\n",
1452        szVersion);
1453 #endif /* NO_STRING_VERSION_MATCH */
1454 
1455   params->iXferHandle = iHandle;
1456 
1457   /* Start the lamp warming up */
1458   /* No point checking the return value, we don't care anyway */
1459   WriteByte (iHandle, 0x0000, 0x01);
1460 
1461   /* Success */
1462   return 0;
1463 
1464 hp5400_close_exit:
1465   hp5400_close (iHandle);
1466   return -1;
1467 }
1468 
1469 HP5400_SANE_STATIC
1470 void
HP5400Close(THWParams * params)1471 HP5400Close (THWParams * params)
1472 {
1473   hp5400_close (params->iXferHandle);
1474 }
1475 
1476 HP5400_SANE_STATIC
1477 int
HP5400Detect(const char * filename,int (* _ReportDevice)(TScannerModel * pModel,const char * pszDeviceName))1478 HP5400Detect (const char *filename,
1479 	      int (*_ReportDevice) (TScannerModel * pModel,
1480 				    const char *pszDeviceName))
1481 {
1482   int iHandle = hp5400_open (filename);
1483 
1484   char szVersion[32];
1485   int ret = 0;
1486 #ifndef NO_STRING_VERSION_MATCH
1487   int versionMatched = 0;
1488   int i = 0;
1489 #endif
1490 
1491   if (iHandle < 0)
1492     {
1493       HP5400_DBG (DBG_MSG, "hp5400_open failed\n");
1494       return -1;
1495     }
1496 
1497   /* read version info */
1498   if (hp5400_command_read
1499       (iHandle, CMD_GETVERSION, sizeof (szVersion), szVersion) < 0)
1500     {
1501       HP5400_DBG (DBG_MSG, "failed to read version string\n");
1502       ret = -1;
1503       goto hp5400_close_exit;
1504     }
1505 
1506 #ifndef NO_STRING_VERSION_MATCH
1507   i = 0;
1508   versionMatched = 0;
1509   while ( !versionMatched && (i < numVersions) ) {
1510 	if (!memcmp (szVersion + 1, MatchVersions[i] .strVersion, strlen (MatchVersions[i] .strVersion) - 4)) {
1511 		versionMatched = 1;
1512 	}
1513   	i++;
1514   }
1515   if ( !versionMatched ) {
1516 	HP5400_DBG (DBG_MSG,
1517 	       "Sorry, unknown scanner version. Attempted match on :\n");
1518 	i = 0;
1519 	while ( i < numVersions ) {
1520 		HP5400_DBG (DBG_MSG, "* '%s'\n", MatchVersions[i] .strVersion);
1521 		i++;
1522 	}
1523 	HP5400_DBG (DBG_MSG, "Version is '%s'\n", szVersion);
1524 	goto hp5400_close_exit;
1525     }
1526 #else
1527   HP5400_DBG (DBG_MSG, "Warning, Version match is disabled. Version is '%s'\n",
1528        szVersion);
1529 #endif /* NO_STRING_VERSION_MATCH */
1530 
1531   if (_ReportDevice)
1532     _ReportDevice (&Model_HP54xx, filename);
1533 
1534 hp5400_close_exit:
1535   hp5400_close (iHandle);
1536   return ret;
1537 }
1538 
1539 #ifdef STANDALONE
1540 int
main(int argc,char * argv[])1541 main (int argc, char *argv[])
1542 {
1543   THWParams scanner;
1544 
1545   assert (sizeof (struct ScanRequest) == 32);
1546   assert (sizeof (struct ScanResponse) == 16);
1547 
1548   hp5400_dbg_start();
1549 
1550   HP5400_DBG (DBG_MSG,
1551        "HP5400/5470C sample scan utility, by Martijn van Oosterhout <kleptog@svana.org>\n");
1552   HP5400_DBG (DBG_MSG,
1553        "Based on the testutils by Bertrik Sikken (bertrik@zonnet.nl)\n");
1554 
1555   if ((argc == 6) && (!strcmp (argv[1], "-decode")))
1556     {
1557       int width = atoi (argv[3]);
1558       int height = atoi (argv[4]);
1559       FILE *temp = fopen (argv[2], "r+b");
1560       if (temp)
1561 	{
1562 	  int planes = 3;
1563 	  int bpp = 1;
1564 	  fseek (temp, 0, SEEK_SET);
1565 	  DecodeImage (temp, planes, bpp, planes * bpp * width, height,
1566 		       argv[5]);
1567 	  fclose (temp);
1568 	}
1569       return 1;
1570     }
1571 
1572   if (HP5400Open (&scanner, NULL) < 0)
1573     {
1574       return 1;
1575     }
1576 
1577   PreviewScan (scanner.iXferHandle);
1578 
1579   HP5400Close (&scanner);
1580   fprintf (stderr, "Note: output is in output.ppm\n");
1581   return 0;
1582 }
1583 
1584 #endif
1585