Tizen 2.1 base
[platform/upstream/hplip.git] / scan / sane / pml.c
1 /************************************************************************************\
2
3   pml.c - HP SANE backend for multi-function peripherals (libsane-hpaio)
4
5   (c) 2001-2005 Copyright Hewlett-Packard Development Company, LP
6
7   Permission is hereby granted, free of charge, to any person obtaining a copy 
8   of this software and associated documentation files (the "Software"), to deal 
9   in the Software without restriction, including without limitation the rights 
10   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
11   of the Software, and to permit persons to whom the Software is furnished to do 
12   so, subject to the following conditions:
13
14   The above copyright notice and this permission notice shall be included in all
15   copies or substantial portions of the Software.
16
17   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
18   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
19   FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
20   COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
21   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
22   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24   Contributing Author(s): David Paschal, Don Welch, David Suffield
25
26 \************************************************************************************/
27
28 #include <string.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include "hpmud.h"
32 #include "io.h"
33 #include "common.h"
34 #include "pml.h"
35
36 #define DEBUG_DECLARE_ONLY
37 #include "sanei_debug.h"
38
39 int __attribute__ ((visibility ("hidden"))) PmlSetID( PmlObject_t obj, char * oid )
40 {
41     int len = 0;    /* TODO: Do we need this parameter? */
42
43     //DBG( 0,  "PmlSetID(obj=0x%8.8X)\n", obj );
44
45     if( !len )
46     {
47         len = strlen( oid );
48         if( !len )
49         {
50             len++;
51         }
52     }
53     if( len > PML_MAX_OID_LEN )
54     {
55         return ERROR;
56     }
57
58     /* TODO: Disable trap (if enabled) on old OID. */
59
60     memcpy( obj->oid, oid, len );
61     obj->oid[len] = 0;
62
63     obj->numberOfValidValues = 0;
64
65     /* TODO: Clear out other trap-related fields. */
66
67     //DBG( 0,  "PmlSetID(obj=0x%8.8X) returns OK.\n", obj );
68     return OK;
69 }
70
71 static PmlValue_t PmlGetLastValue( PmlObject_t obj )
72 {
73     if( obj->numberOfValidValues <= 0 )
74     {
75         return 0;
76     }
77     return &obj->value[obj->indexOfLastValue];
78 }
79
80 static PmlValue_t PmlPrepareNextValue( PmlObject_t obj )
81 {
82     obj->indexOfLastValue = ( obj->indexOfLastValue + 1 ) %
83                             PML_MAX_OID_VALUES;
84     if( obj->numberOfValidValues < PML_MAX_OID_VALUES )
85     {
86         obj->numberOfValidValues++;
87     }
88     return &obj->value[obj->indexOfLastValue];
89 }
90
91 static int PmlSetPrefixValue( PmlObject_t obj,
92                            int type,
93                            char * prefix,
94                            int lenPrefix,
95                            char * value,
96                            int lenValue )
97 {
98     PmlValue_t v = PmlPrepareNextValue( obj );
99     int r = ERROR;
100
101     /*DBG( 0,  "PmlSetPrefixValue(obj=0x%8.8X,type=0x%4.4X,"
102                     "lenPrefix=%d,lenValue=%d)\n",
103                     obj,
104                     type,
105                     lenPrefix,
106                     lenValue );*/
107
108     if( lenPrefix < 0 ||
109         lenValue<0 ||
110         ( lenPrefix + lenValue )>PML_MAX_VALUE_LEN )
111     {
112         /*DBG( 0, "PmlSetPrefixValue(obj=0x%8.8X): "
113                        "invalid lenPrefix=%d and/or lenValue=%d!\n",
114                        obj,
115                        lenPrefix,
116                        lenValue );*/
117         goto abort;
118     }
119
120     v->type = type;
121     v->len = lenPrefix + lenValue;
122     if( lenPrefix )
123     {
124         memcpy( v->value, prefix, lenPrefix );
125     }
126     if( lenValue )
127     {
128         memcpy( v->value + lenPrefix, value, lenValue );
129     }
130     v->value[lenPrefix + lenValue] = 0;
131
132     r = OK;
133 abort:
134     /*DBG( 0,  "PmlSetPrefixValue(obj=0x%8.8X) returns %d.\n",
135                     obj,
136                     r );*/
137     return r;
138 }
139
140 int __attribute__ ((visibility ("hidden"))) PmlSetValue( PmlObject_t obj, int type, char * value, int len )
141 {
142     return PmlSetPrefixValue( obj, type, 0, 0, value, len );
143 }
144
145 int __attribute__ ((visibility ("hidden"))) PmlSetIntegerValue( PmlObject_t obj, int type, int value )
146 {
147     char buffer[sizeof( int )];
148     int len = sizeof( int ), i = len - 1;
149
150     while( 1 )
151     {
152         buffer[i] = value & 0xFF;
153         value >>= 8;
154         if( !i )
155         {
156             break;
157         }
158         i--;
159     }
160     for( ; !buffer[i] && i < ( len ); i++ )
161         ;
162
163     return PmlSetPrefixValue( obj, type, buffer + i, len - i, 0, 0 );
164 }
165
166 static int PmlGetPrefixValue( PmlObject_t obj,
167                            int * pType,
168                            char * prefix,
169                            int lenPrefix,
170                            char * buffer,
171                            int maxlen )
172 {
173     int len;
174     PmlValue_t v = PmlGetLastValue( obj );
175
176     if( !v )
177     {
178         return ERROR;
179     }
180     if( pType )
181     {
182         *pType = v->type;
183     }
184     if( !prefix && !buffer )
185     {
186         return OK;
187     }
188
189     if( lenPrefix < 0 || maxlen < 0 )
190     {
191         return ERROR;
192     }
193
194     if( v->len > lenPrefix + maxlen )
195     {
196         return ERROR;
197     }
198     if( v->len < lenPrefix )
199     {
200         return ERROR;
201     }
202
203     if( lenPrefix )
204     {
205         memcpy( prefix, v->value, lenPrefix );
206     }
207     len = v->len - lenPrefix;
208     if( len )
209     {
210         memcpy( buffer, v->value + lenPrefix, len );
211     }
212     if( len < maxlen )
213     {
214         buffer[len] = 0;
215     }
216
217     return len;
218 }
219
220 int __attribute__ ((visibility ("hidden"))) PmlGetValue(PmlObject_t obj, int *pType, char *buffer, int maxlen)
221 {
222     return PmlGetPrefixValue( obj, pType, 0, 0, buffer, maxlen );
223 }
224
225 int __attribute__ ((visibility ("hidden"))) PmlGetStringValue( PmlObject_t obj,
226                            int * pSymbolSet,
227                            char * buffer,
228                            int maxlen )
229 {
230     int type, len;
231     unsigned char prefix[2];
232
233     if( PmlGetPrefixValue( obj, &type, 0, 0, 0, 0 ) == ERROR )
234     {
235         return ERROR;
236     }
237
238     len = PmlGetPrefixValue( obj, &type, (char *)prefix, 2, buffer, maxlen );
239     if( len == ERROR )
240     {
241         return ERROR;
242     }
243     if( pSymbolSet )
244     {
245         *pSymbolSet = ( ( prefix[0] << 8 ) | prefix[1] );
246     }
247
248     return len;
249 }
250
251 int __attribute__ ((visibility ("hidden"))) PmlGetIntegerValue( PmlObject_t obj, int * pType, int * pValue )
252 {
253     int type;
254     unsigned char svalue[sizeof( int )];
255     int accum = 0, i, len;
256
257     if( !pType )
258     {
259         pType = &type;
260     }
261
262     len = PmlGetPrefixValue( obj, pType, 0, 0, (char *)svalue, sizeof( int ) );
263     /*if( len == ERROR )
264             {
265                 return ERROR;
266             }*/
267
268     for( i = 0; i < len; i++ )
269     {
270         accum = ( ( accum << 8 ) | ( svalue[i] & 0xFF ) );
271     }
272     if( pValue )
273     {
274         *pValue = accum;
275     }
276
277     return OK;
278 }
279
280 static int PmlSetStatus( PmlObject_t obj, int status )
281 {
282     obj->status = status;
283
284     return status;
285 }
286
287 static int PmlGetStatus( PmlObject_t obj )
288 {
289     return obj->status;
290 }
291
292 int __attribute__ ((visibility ("hidden"))) PmlRequestSet( int deviceid, int channelid, PmlObject_t obj )
293 {
294     unsigned char data[PML_MAX_DATALEN];
295     int datalen=0, status=ERROR, type, result, pml_result;
296
297     PmlSetStatus(obj, PML_ERROR);
298                 
299     datalen = PmlGetValue(obj, &type, (char *)data, sizeof(data));
300
301     result = hpmud_set_pml(deviceid, channelid, obj->oid, type, data, datalen, &pml_result); 
302
303     PmlSetStatus(obj, pml_result);
304
305     if (result == HPMUD_R_OK)
306         status = OK;
307
308     return status;  /* OK = valid I/O result */
309 }
310
311 int __attribute__ ((visibility ("hidden"))) PmlRequestSetRetry( int deviceid, int channelid, PmlObject_t obj, int count, int delay )
312 {
313    int stat=ERROR, r;
314
315    if(count <= 0)
316    {
317       count = 10;
318    }
319    if(delay <= 0)
320    {
321       delay = 1;
322    }
323    while( 1 )
324    {
325       if ((r = PmlRequestSet(deviceid, channelid, obj)) == ERROR)
326          goto bugout;
327       if (PmlGetStatus(obj) == PML_ERROR_ACTION_CAN_NOT_BE_PERFORMED_NOW && count > 0)
328       {
329          sleep(delay);
330          count--;
331          continue;
332       }
333       break;
334    }
335
336    /* Check PML result. */
337    if (PmlGetStatus(obj) & PML_ERROR)
338    {
339       DBG(6, "PML set failed: oid=%s count=%d delay=%d %s %d\n", obj->oid, count, delay, __FILE__, __LINE__);
340       goto bugout;
341    }
342
343    stat = OK; 
344
345 bugout:
346    return stat;  /* OK = valid I/O result AND PML result */
347 }
348
349 int __attribute__ ((visibility ("hidden"))) PmlRequestGet( int deviceid, int channelid, PmlObject_t obj ) 
350 {
351     unsigned char data[PML_MAX_DATALEN];
352     int datalen=0, stat=ERROR, type, pml_result;
353     enum HPMUD_RESULT result;
354
355     result = hpmud_get_pml(deviceid, channelid, obj->oid, data, sizeof(data), &datalen, &type, &pml_result); 
356
357     PmlSetStatus(obj, pml_result);
358
359     if (result == HPMUD_R_OK)
360     {
361        PmlSetValue(obj, type, (char *)data, datalen);
362        stat = OK;
363     }
364
365     return stat; 
366 }
367
368 /*
369  * Phase 2 rewrite. des
370  */
371
372 static int is_zero(char *buf, int size)
373 {
374    int i;
375
376    for (i=0; i<size; i++)
377    {
378       if (buf[i] != 0)
379          return 0;  /* no */
380    }
381    return 1; /* yes */
382 }
383
384 /* Unlock Scanner. */
385 static int clr_scan_token(HPAIO_RECORD *hpaio)
386 {
387    int len, i, stat=ERROR;
388    int max = sizeof(hpaio->pml.scanToken);
389
390    if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objScanToken) == ERROR)
391       goto bugout;
392    len = PmlGetValue(hpaio->pml.objScanToken, 0, hpaio->pml.scanToken, max);
393
394    if (len > 0 && !is_zero(hpaio->pml.scanToken, len))     
395    {
396       /* Zero token. */
397       len = (len > max) ? max : len; 
398       for(i=0; i<len; i++)
399          hpaio->pml.scanToken[i] = 0;
400       hpaio->pml.lenScanToken = len;
401       if (PmlSetValue(hpaio->pml.objScanToken, PML_TYPE_BINARY, hpaio->pml.scanToken, len) == ERROR)
402          goto bugout;
403       if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objScanToken) == ERROR)
404          goto bugout;
405    }
406
407    hpaio->pml.lenScanToken = len;
408    stat = OK;
409
410 bugout:
411    return stat;
412 }
413
414 /* Lock Scanner. */
415 static int set_scan_token(HPAIO_RECORD *hpaio)
416 {
417    int stat=ERROR;
418
419    /* Make sure token==0. */
420    if (clr_scan_token(hpaio) == ERROR)
421       goto bugout;
422
423    if (hpaio->pml.lenScanToken > 0)
424    {
425       strncpy(hpaio->pml.scanToken, "555", hpaio->pml.lenScanToken);
426       if (PmlSetValue(hpaio->pml.objScanToken, PML_TYPE_BINARY, hpaio->pml.scanToken, hpaio->pml.lenScanToken) == ERROR)
427          goto bugout;
428       if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objScanToken) == ERROR)
429          goto bugout;
430    }
431    stat = OK;
432
433 bugout:
434    return stat;
435 }
436
437 static int set_scan_parameters(HPAIO_RECORD *hpaio)
438 {
439    int pixelDataType, stat=ERROR;
440    struct PmlResolution resolution;
441    int copierReduction = 100;
442    int compression;
443
444    hpaio->effectiveScanMode = hpaio->currentScanMode;
445    hpaio->effectiveResolution = hpaio->currentResolution;
446
447    /* Set upload timeout. */
448    PmlSetIntegerValue(hpaio->pml.objUploadTimeout, PML_TYPE_SIGNED_INTEGER, PML_UPLOAD_TIMEOUT);
449    if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadTimeout) == ERROR)
450       goto bugout;
451
452    /* Set pixel data type. */
453    switch(hpaio->currentScanMode)
454    {
455       case SCAN_MODE_LINEART:
456          pixelDataType = PML_DATA_TYPE_LINEART;
457          break;
458       case SCAN_MODE_GRAYSCALE:
459          pixelDataType = PML_DATA_TYPE_GRAYSCALE;
460          break;
461       case SCAN_MODE_COLOR:
462       default:
463          pixelDataType = PML_DATA_TYPE_COLOR;
464          break;
465    }
466    PmlSetIntegerValue(hpaio->pml.objPixelDataType, PML_TYPE_ENUMERATION, pixelDataType);
467    if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objPixelDataType) == ERROR)
468       goto bugout;
469
470    /* Set resolution. */
471    BEND_SET_LONG(resolution.x, hpaio->currentResolution << 16);
472    BEND_SET_LONG(resolution.y, hpaio->currentResolution << 16);
473    PmlSetValue(hpaio->pml.objResolution, PML_TYPE_BINARY, (char *)&resolution, sizeof(resolution));
474    if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objResolution) == ERROR)
475       goto bugout;
476
477    /* Set compression. */
478    switch(hpaio->currentCompression)
479    {
480       case COMPRESSION_NONE:
481          compression = PML_COMPRESSION_NONE;
482          break;
483       case COMPRESSION_MH:
484          compression = PML_COMPRESSION_MH;
485          break;
486       case COMPRESSION_MR:
487          compression = PML_COMPRESSION_MR;
488          break;
489       case COMPRESSION_MMR:
490          compression = PML_COMPRESSION_MMR;
491          break;
492       case COMPRESSION_JPEG:
493       default:
494          compression = PML_COMPRESSION_JPEG;
495          break;
496    }
497             
498    PmlSetIntegerValue(hpaio->pml.objCompression, PML_TYPE_ENUMERATION, compression);
499    if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objCompression) == ERROR)
500       goto bugout;
501
502    /* Set JPEG compression factor. */
503    PmlSetIntegerValue(hpaio->pml.objCompressionFactor, PML_TYPE_SIGNED_INTEGER, hpaio->currentJpegCompressionFactor);
504    if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objCompressionFactor) == ERROR)
505       goto bugout;
506
507 #if 0  /* Removed, let host side perform contrast adjustments. des */
508    /* Set scan contrast. */
509    if (SANE_OPTION_IS_ACTIVE(hpaio->option[OPTION_CONTRAST].cap))
510    {
511       /* Note although settable, contrast is ignored by LJ3320, CLJ2840, LJ3055, LJ3050. */
512       PmlSetIntegerValue(hpaio->pml.objContrast, PML_TYPE_SIGNED_INTEGER, hpaio->currentContrast);
513       if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objContrast) == ERROR)
514          goto bugout;
515    }
516 #endif
517
518    /* Set copier reduction. */
519    PmlSetIntegerValue(hpaio->pml.objCopierReduction, PML_TYPE_SIGNED_INTEGER, copierReduction);
520    if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objCopierReduction) == ERROR)
521       goto bugout;
522
523    stat = OK;
524
525 bugout:
526    return stat;
527 }
528
529 static int pml_to_sane_status(HPAIO_RECORD *hpaio)
530 {
531    int stat=SANE_STATUS_IO_ERROR, status;
532
533    if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objScannerStatus) == ERROR)
534       goto bugout;
535    PmlGetIntegerValue(hpaio->pml.objScannerStatus, 0, &status);
536
537    DBG(6, "PML scannerStatus=%x: %s %d\n", status, __FILE__, __LINE__);
538
539    if(status & PML_SCANNER_STATUS_FEEDER_JAM)
540    {
541       stat = SANE_STATUS_JAMMED;
542    }
543    else if(status & PML_SCANNER_STATUS_FEEDER_OPEN)
544    {
545       stat = SANE_STATUS_COVER_OPEN;
546    }
547    else if(status & PML_SCANNER_STATUS_FEEDER_EMPTY)
548    {
549       if(hpaio->currentAdfMode == ADF_MODE_FLATBED || (hpaio->currentBatchScan == SANE_FALSE && hpaio->currentAdfMode == ADF_MODE_AUTO))
550       {
551          stat = SANE_STATUS_GOOD;
552       }
553       else
554       {
555          stat = SANE_STATUS_NO_DOCS;
556       }
557    }
558    else if(status & PML_SCANNER_STATUS_INVALID_MEDIA_SIZE)
559    {
560       stat = SANE_STATUS_INVAL;
561    }
562    else if(status)
563    {
564       stat = SANE_STATUS_IO_ERROR;
565    }
566    else
567    {
568       stat = SANE_STATUS_GOOD;
569    }
570
571 bugout:
572     return stat;
573 }
574
575 static int check_pml_done(HPAIO_RECORD *hpaio)
576 {
577    int stat=ERROR, state;
578
579    /* See if pml side is done scanning. */
580    if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState) == ERROR)
581       goto bugout;
582    PmlGetIntegerValue(hpaio->pml.objUploadState, 0, &state);
583    hpaio->upload_state = state;
584            
585    if (state == PML_UPLOAD_STATE_DONE || state == PML_UPLOAD_STATE_NEWPAGE)
586       hpaio->pml_done=1;
587    else if (state != PML_UPLOAD_STATE_ACTIVE)
588       goto bugout;
589    else if (hpaio->ip_done && hpaio->mfpdtf_done)
590    {
591       if (hpaio->pml_timeout_cnt++ > 15)
592       {
593          bug("check_pml_done timeout cnt=%d: %s %d\n", hpaio->pml_timeout_cnt, __FILE__, __LINE__);
594          goto bugout;
595       }
596       else
597          sleep(1);
598    }
599
600    stat = OK;
601
602 bugout:
603    return stat;
604 }
605
606 int __attribute__ ((visibility ("hidden"))) pml_start(HPAIO_RECORD *hpaio)
607 {
608    MFPDTF_FIXED_HEADER *ph;
609    MFPDTF_START_PAGE *ps;
610    IP_IMAGE_TRAITS traits;
611    IP_XFORM_SPEC xforms[IP_MAX_XFORMS], * pXform = xforms;
612    int stat = SANE_STATUS_DEVICE_BUSY;
613    int i, bsize, state, wResult, index, r;
614    int oldStuff = (hpaio->preDenali || hpaio->fromDenali || hpaio->denali) ? 1 : 0;
615
616    if (hpaio->cmd_channelid < 0)
617    {
618       if (hpmud_open_channel(hpaio->deviceid, "HP-MESSAGE", &hpaio->cmd_channelid) != HPMUD_R_OK)
619       {
620          bug("failed to open pml channel: %s %d\n", __FILE__, __LINE__);
621          goto bugout;
622       }
623       SendScanEvent(hpaio->deviceuri, EVENT_START_SCAN_JOB); 
624    }
625    if (!oldStuff)
626    {
627       if (hpaio->scan_channelid < 0)
628       {
629          if (hpmud_open_channel(hpaio->deviceid, "HP-SCAN", &hpaio->scan_channelid) != HPMUD_R_OK)
630          {
631             bug("failed to open scan channel: %s %d\n", __FILE__, __LINE__);
632             goto bugout;
633          }
634       }
635    }
636
637    r = pml_to_sane_status(hpaio);
638    if (r != SANE_STATUS_GOOD)
639    {
640       stat = r;
641       goto bugout;
642    }
643
644    /* Make sure scanner is idle. */
645    if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState) == ERROR)
646    {
647       stat=SANE_STATUS_IO_ERROR;
648       goto bugout;
649    }
650    PmlGetIntegerValue(hpaio->pml.objUploadState, 0, &state);
651    DBG(6, "PML uploadState=%d before scan: %s %d\n", state, __FILE__, __LINE__);
652    switch (state)
653    {
654       case PML_UPLOAD_STATE_IDLE:
655          if (set_scan_token(hpaio) == ERROR)
656             goto bugout;
657          if (set_scan_parameters(hpaio) == ERROR)
658             goto bugout;
659          break;
660       case PML_UPLOAD_STATE_NEWPAGE:
661          break;
662       case PML_UPLOAD_STATE_DONE:
663          PmlSetIntegerValue(hpaio->pml.objUploadState, PML_TYPE_ENUMERATION, PML_UPLOAD_STATE_IDLE);
664          if (PmlRequestSetRetry(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState, 0, 0) == ERROR)
665             goto bugout;
666          break;
667       case PML_UPLOAD_STATE_START:
668       case PML_UPLOAD_STATE_ACTIVE:
669          goto bugout;                /* scanner is busy */
670       case PML_UPLOAD_STATE_ABORTED:
671       default:
672          stat = hpaioScannerToSaneError(hpaio);
673          PmlSetIntegerValue(hpaio->pml.objUploadState, PML_TYPE_ENUMERATION, PML_UPLOAD_STATE_IDLE);
674          if (PmlRequestSetRetry(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState, 0, 0) == ERROR)
675             goto bugout;
676          break;
677    }
678          
679    hpaio->scanParameters = hpaio->prescanParameters;
680    memset(xforms, 0, sizeof(xforms));
681    traits.iPixelsPerRow = -1;
682     
683    switch(hpaio->effectiveScanMode)
684    {
685        case SCAN_MODE_LINEART:
686            hpaio->scanParameters.format = SANE_FRAME_GRAY;
687            hpaio->scanParameters.depth = 1;
688            traits.iBitsPerPixel = 1;
689            break;
690        case SCAN_MODE_GRAYSCALE:
691            hpaio->scanParameters.format = SANE_FRAME_GRAY;
692            hpaio->scanParameters.depth = 8;
693            traits.iBitsPerPixel = 8;
694            break;
695        case SCAN_MODE_COLOR:
696        default:
697            hpaio->scanParameters.format = SANE_FRAME_RGB;
698            hpaio->scanParameters.depth = 8;
699            traits.iBitsPerPixel = 24;
700            break;
701    }
702    traits.lHorizDPI = hpaio->effectiveResolution << 16;
703    traits.lVertDPI = hpaio->effectiveResolution << 16;
704    traits.lNumRows = -1;
705    traits.iNumPages = 1;
706    traits.iPageNum = 1;
707
708    /* Start scanning. */
709    PmlSetIntegerValue(hpaio->pml.objUploadState, PML_TYPE_ENUMERATION, PML_UPLOAD_STATE_START);
710    if (PmlRequestSetRetry(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState, 0, 0) == ERROR)
711       goto bugout;
712
713    /* Look for a confirmation that the scan started or failed. */
714    for(i=0; i < PML_START_SCAN_WAIT_ACTIVE_MAX_RETRIES; i++)
715    {
716       if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState) == ERROR)
717       {
718          stat=SANE_STATUS_IO_ERROR;
719          goto bugout;
720       }
721       PmlGetIntegerValue(hpaio->pml.objUploadState, 0, &state);
722             
723       if(state == PML_UPLOAD_STATE_ACTIVE)
724          break;
725
726       if(state != PML_UPLOAD_STATE_START)
727          break;        /* bail */
728
729       sleep(1);
730    }
731
732    if (state != PML_UPLOAD_STATE_ACTIVE)
733    {
734       /* Found and error, see if we can classify it otherwise use default. */
735       r = hpaioScannerToSaneError(hpaio);
736       if (r != SANE_STATUS_GOOD) 
737          stat = r;
738       goto bugout;
739    }
740
741    /* For older all-in-ones open the scan channel now. */
742    if (oldStuff)
743    {
744       if (hpaio->scan_channelid < 0)
745       {
746          if (hpmud_open_channel(hpaio->deviceid, "HP-SCAN", &hpaio->scan_channelid) != HPMUD_R_OK)
747             goto bugout;
748       }
749    }
750
751    /* Find mfpdtf "New Page" block. */
752    while (1)
753    {
754      if ((bsize = read_mfpdtf_block(hpaio->deviceid, hpaio->scan_channelid, (char *)hpaio->inBuffer, sizeof(hpaio->inBuffer), 45)) <= 0)
755          goto bugout;  /* i/o error or timeout */
756
757       ph = (MFPDTF_FIXED_HEADER *)hpaio->inBuffer;
758       if ((ph->DataType == DT_SCAN) && (ph->PageFlag & PF_NEW_PAGE))
759          break;  /* found it */
760    }
761
762    index = sizeof(MFPDTF_FIXED_HEADER);
763    ps = (MFPDTF_START_PAGE *)(hpaio->inBuffer + index);
764    if (ps->ID != ID_START_PAGE)
765       goto bugout; 
766
767    /* Read SOP record and set image pipeline input traits. */
768    traits.iPixelsPerRow = le16toh(ps->BlackPixelsPerRow);
769    traits.iBitsPerPixel = le16toh(ps->BlackBitsPerPixel);
770    traits.lHorizDPI = le16toh(ps->BlackHorzDPI);
771    traits.lVertDPI = le16toh(ps->BlackVertDPI);
772
773    /* Set up image-processing pipeline. */
774    switch(ps->Code)
775    {
776       case MFPDTF_RASTER_MH:
777          pXform->aXformInfo[IP_FAX_FORMAT].dword = IP_FAX_MH;
778          ADD_XFORM( X_FAX_DECODE );
779          break;
780       case MFPDTF_RASTER_MR:
781          pXform->aXformInfo[IP_FAX_FORMAT].dword = IP_FAX_MR;
782          ADD_XFORM( X_FAX_DECODE );
783          break;
784       case MFPDTF_RASTER_MMR:
785          pXform->aXformInfo[IP_FAX_FORMAT].dword = IP_FAX_MMR;   /* possible lineart compression */
786          ADD_XFORM( X_FAX_DECODE );
787          break;
788       case MFPDTF_RASTER_BITMAP:
789       case MFPDTF_RASTER_GRAYMAP:
790       case MFPDTF_RASTER_RGB:
791          /* rawDecode */ 
792          break;
793       case MFPDTF_RASTER_JPEG:
794          /* jpegDecode */
795          pXform->aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword = hpaio->fromDenali;
796          ADD_XFORM( X_JPG_DECODE );
797          pXform->aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword = IP_CNV_YCC_TO_SRGB;
798          pXform->aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword = 0x00010000;
799          ADD_XFORM( X_CNV_COLOR_SPACE );
800          break;
801       default:
802          /* Skip processing for unknown encodings. */
803          bug("unknown image encoding sane_start: name=%s sop=%d %s %d\n", hpaio->saneDevice.name, ps->Code, __FILE__, __LINE__);
804    }
805
806    index += sizeof(MFPDTF_START_PAGE);
807    hpaio->BlockSize = bsize;
808    hpaio->BlockIndex = index; 
809    hpaio->RecordSize = 0;
810    hpaio->RecordIndex = 0; 
811    hpaio->mfpdtf_done = 0;
812    hpaio->pml_done = 0;
813    hpaio->ip_done = 0;
814    hpaio->page_done = 0;
815    hpaio->mfpdtf_timeout_cnt = 0;
816    hpaio->pml_timeout_cnt = 0;
817
818    hpaio->scanParameters.pixels_per_line = traits.iPixelsPerRow;
819    hpaio->scanParameters.lines = traits.lNumRows;
820     
821    if(hpaio->scanParameters.lines < 0)
822    {
823       hpaio->scanParameters.lines = MILLIMETERS_TO_PIXELS(hpaio->bryRange.max, hpaio->effectiveResolution);
824    }
825
826    int mmWidth = PIXELS_TO_MILLIMETERS(traits.iPixelsPerRow, hpaio->effectiveResolution);
827
828    /* Set up X_CROP xform. */
829    pXform->aXformInfo[IP_CROP_LEFT].dword = MILLIMETERS_TO_PIXELS( hpaio->effectiveTlx, hpaio->effectiveResolution );
830    if( hpaio->effectiveBrx < hpaio->brxRange.max && hpaio->effectiveBrx < mmWidth )
831    {
832       pXform->aXformInfo[IP_CROP_RIGHT].dword = MILLIMETERS_TO_PIXELS( mmWidth-hpaio->effectiveBrx, hpaio->effectiveResolution );
833    }
834    pXform->aXformInfo[IP_CROP_TOP].dword = MILLIMETERS_TO_PIXELS( hpaio->effectiveTly, hpaio->effectiveResolution );
835    if( hpaio->currentLengthMeasurement != LENGTH_MEASUREMENT_UNLIMITED )
836    {
837       hpaio->scanParameters.lines = pXform->aXformInfo[IP_CROP_MAXOUTROWS].dword = 
838           MILLIMETERS_TO_PIXELS(hpaio->effectiveBry - hpaio->effectiveTly, hpaio->effectiveResolution);
839    }
840    hpaio->scanParameters.pixels_per_line -= pXform->aXformInfo[IP_CROP_LEFT].dword + pXform->aXformInfo[IP_CROP_RIGHT].dword;
841    ADD_XFORM( X_CROP );
842
843    if( hpaio->currentLengthMeasurement == LENGTH_MEASUREMENT_PADDED )
844    {
845        pXform->aXformInfo[IP_PAD_LEFT].dword = 0;
846        pXform->aXformInfo[IP_PAD_RIGHT].dword = 0;
847        pXform->aXformInfo[IP_PAD_TOP].dword = 0;
848        pXform->aXformInfo[IP_PAD_BOTTOM].dword = 0;
849        pXform->aXformInfo[IP_PAD_VALUE].dword = ( hpaio->effectiveScanMode == SCAN_MODE_LINEART ) ? PAD_VALUE_LINEART : PAD_VALUE_GRAYSCALE_COLOR;
850        pXform->aXformInfo[IP_PAD_MIN_HEIGHT].dword = hpaio->scanParameters.lines;
851        ADD_XFORM( X_PAD );
852    }
853
854    /* If we didn't set up any xforms by now, then add the dummy "skel" xform to simplify our subsequent code path. */
855    if( pXform == xforms )
856    {
857       ADD_XFORM( X_SKEL );
858    }
859
860    wResult = ipOpen( pXform - xforms, xforms, 0, &hpaio->hJob );
861     
862    if( wResult != IP_DONE || !hpaio->hJob )
863    {
864       stat = SANE_STATUS_INVAL;
865       goto bugout;
866    }
867
868    traits.iComponentsPerPixel = ( ( traits.iBitsPerPixel % 3 ) ? 1 : 3 );
869    wResult = ipSetDefaultInputTraits( hpaio->hJob, &traits );
870     
871    if( wResult != IP_DONE )
872    {
873       stat = SANE_STATUS_INVAL;
874       goto bugout;
875    }
876
877    hpaio->scanParameters.bytes_per_line = 
878           BYTES_PER_LINE(hpaio->scanParameters.pixels_per_line, hpaio->scanParameters.depth * (hpaio->scanParameters.format == SANE_FRAME_RGB ? 3 : 1));
879     
880    if( hpaio->currentLengthMeasurement == LENGTH_MEASUREMENT_UNKNOWN || hpaio->currentLengthMeasurement == LENGTH_MEASUREMENT_UNLIMITED )
881    {
882       hpaio->scanParameters.lines = -1;
883    }
884
885    stat = SANE_STATUS_GOOD;
886
887 bugout:
888    return stat;
889 }
890
891 int __attribute__ ((visibility ("hidden"))) pml_read(HPAIO_RECORD *hpaio, SANE_Byte *data, SANE_Int maxLength, SANE_Int *pLength)
892 {
893    MFPDTF_RASTER *pd;
894    int stat=SANE_STATUS_IO_ERROR;
895    unsigned int outputAvail=maxLength, outputUsed=0, outputThisPos;
896    unsigned char *output = data;
897    unsigned int inputAvail=0, inputUsed=0, inputNextPos;
898    unsigned char *input;
899    int bsize, wResult;
900
901    DBG(8, "sane_hpaio_read called handle=%p data=%p maxLength=%d length=%d: %s %d\n", hpaio, data, maxLength, *pLength, __FILE__, __LINE__);
902
903    /* Process any bytes in current record. */
904    if (hpaio->RecordIndex < hpaio->RecordSize)
905    {
906       inputAvail = hpaio->RecordSize - hpaio->RecordIndex;
907       input = hpaio->inBuffer + hpaio->BlockIndex + hpaio->RecordIndex + sizeof(MFPDTF_RASTER);
908
909       /* Transform input data to output. Note, output buffer may consume more bytes than input buffer (ie: jpeg to raster). */
910       wResult = ipConvert(hpaio->hJob, inputAvail, input, &inputUsed, &inputNextPos, outputAvail, output, &outputUsed, &outputThisPos);
911       if(wResult & (IP_INPUT_ERROR | IP_FATAL_ERROR))
912       {
913          bug("ipConvert error=%x: %s %d\n", wResult, __FILE__, __LINE__);
914          goto bugout;
915       }
916       *pLength = outputUsed;
917       hpaio->RecordIndex += inputUsed;  /* bump record index */
918       if (hpaio->RecordIndex >= hpaio->RecordSize)
919          hpaio->BlockIndex += sizeof(MFPDTF_RASTER) + hpaio->RecordSize;  /* bump block index to next record */
920    }
921    else if (hpaio->BlockIndex < hpaio->BlockSize)
922    {
923       /* Process next record in current mfpdtf block. */
924       pd = (MFPDTF_RASTER *)(hpaio->inBuffer + hpaio->BlockIndex);
925       if (pd->ID == ID_RASTER_DATA)
926       {
927          /* Raster Record */
928          hpaio->RecordSize = le16toh(pd->Size);
929          hpaio->RecordIndex = 0;
930       }
931       else if (pd->ID == ID_END_PAGE)
932       {
933          /* End Page Record */
934          hpaio->page_done = 1;
935          hpaio->BlockIndex += sizeof(MFPDTF_END_PAGE);  /* bump index to next record */
936       }  
937       else
938       {
939          bug("unknown mfpdtf record id=%d: pml_read %s %d\n", pd->ID, __FILE__, __LINE__);
940          goto bugout;
941       }
942    } 
943    else if (!hpaio->mfpdtf_done)
944    {
945       /* Read new mfpdtf block. */
946       if ((bsize = read_mfpdtf_block(hpaio->deviceid, hpaio->scan_channelid, (char *)hpaio->inBuffer, sizeof(hpaio->inBuffer), 1)) < 0)
947          goto bugout;  /* i/o error */
948
949       hpaio->BlockSize = 0;
950       hpaio->BlockIndex = 0;
951
952       if (bsize == 0)
953       {
954          if (hpaio->page_done || hpaio->pml_done)
955             hpaio->mfpdtf_done = 1;  /* normal timeout */
956          else if (hpaio->mfpdtf_timeout_cnt++ > 5)
957          {
958             bug("read_mfpdtf_block timeout cnt=%d: %s %d\n", hpaio->mfpdtf_timeout_cnt, __FILE__, __LINE__);
959             goto bugout;
960          }
961          else
962          { 
963             if (check_pml_done(hpaio) == ERROR)
964                goto bugout;
965          }
966       }
967       else
968       {
969          hpaio->mfpdtf_timeout_cnt = 0;
970
971          if (bsize > sizeof(MFPDTF_FIXED_HEADER))
972          {
973             hpaio->BlockSize = bsize;  /* set for next sane_read */
974             hpaio->BlockIndex = sizeof(MFPDTF_FIXED_HEADER);
975          }
976       }
977    } 
978    else if ((hpaio->page_done || hpaio->pml_done) && !hpaio->ip_done)
979    {
980       /* No more scan data, flush ipconvert pipeline. */
981       input = NULL;
982       wResult = ipConvert(hpaio->hJob, inputAvail, input, &inputUsed, &inputNextPos, outputAvail, output, &outputUsed, &outputThisPos);
983       if (wResult & (IP_INPUT_ERROR | IP_FATAL_ERROR))
984       {
985          bug("hpaio: ipConvert error=%x\n", wResult);
986          goto bugout;
987       }
988       *pLength = outputUsed;
989       if (outputUsed == 0)
990          hpaio->ip_done = 1;
991    }
992    else if (!hpaio->pml_done)
993    {
994       if (check_pml_done(hpaio) == ERROR)
995          goto bugout;
996    }
997
998    if(hpaio->ip_done && hpaio->mfpdtf_done && hpaio->pml_done)
999       stat = SANE_STATUS_EOF;  /* done scan_read */
1000    else
1001       stat = SANE_STATUS_GOOD; /* repeat scan_read */ 
1002
1003  bugout:
1004     if (stat != SANE_STATUS_GOOD)
1005     {
1006        if (hpaio->hJob)
1007        {
1008           ipClose(hpaio->hJob); 
1009           hpaio->hJob = 0;
1010        }   
1011     }
1012
1013     //   bug("ipConvert result: inputAvail=%d input=%p inputUsed=%d inputNextPos=%d outputAvail=%d output=%p outputUsed=%d outputThisPos=%d\n", 
1014     //                                                 inputAvail, input, inputUsed, inputNextPos, outputAvail, output, outputUsed, outputThisPos);
1015
1016     DBG(8, "sane_hpaio_read returned output=%p outputUsed=%d length=%d status=%d: %s %d\n", output, outputUsed, *pLength, stat, __FILE__, __LINE__);
1017
1018     return stat;
1019 }
1020
1021 int __attribute__ ((visibility ("hidden"))) pml_cancel(HPAIO_RECORD *hpaio)
1022 {
1023    int oldStuff = (hpaio->preDenali || hpaio->fromDenali || hpaio->denali) ? 1 : 0;
1024
1025    if(hpaio->hJob)
1026    {
1027       ipClose(hpaio->hJob);
1028       hpaio->hJob = 0;
1029    }
1030  
1031    /* If batch mode and page remains in ADF, leave pml/scan channels open. */
1032    if(hpaio->currentBatchScan == SANE_TRUE && hpaio->upload_state == PML_UPLOAD_STATE_NEWPAGE)
1033       return OK;
1034
1035    /* If newer scanner or old scanner and ADF is empty, set to scanner to idle and unlock the scanner. */
1036    if(!oldStuff || (oldStuff && hpaio->upload_state != PML_UPLOAD_STATE_NEWPAGE))
1037    {
1038       PmlSetIntegerValue(hpaio->pml.objUploadState, PML_TYPE_ENUMERATION, PML_UPLOAD_STATE_IDLE);
1039       if (PmlRequestSetRetry(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState, 0, 0) != ERROR)
1040          clr_scan_token(hpaio);
1041    }
1042
1043    if (hpaio->scan_channelid >= 0)
1044    {
1045       hpmud_close_channel(hpaio->deviceid, hpaio->scan_channelid);
1046       hpaio->scan_channelid = -1;
1047    }
1048    if (hpaio->cmd_channelid >= 0)
1049    {
1050       hpmud_close_channel(hpaio->deviceid, hpaio->cmd_channelid);
1051       hpaio->cmd_channelid = -1;
1052       SendScanEvent(hpaio->deviceuri, EVENT_END_SCAN_JOB);
1053    }
1054
1055    return OK;
1056 }