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, ¶ms, &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