1 /************************************************************************************\
3 pml.c - HP SANE backend for multi-function peripherals (libsane-hpaio)
5 (c) 2001-2005 Copyright Hewlett-Packard Development Company, LP
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:
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
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.
24 Contributing Author(s): David Paschal, Don Welch, David Suffield
26 \************************************************************************************/
36 #define DEBUG_DECLARE_ONLY
37 #include "sanei_debug.h"
39 int __attribute__ ((visibility ("hidden"))) PmlSetID( PmlObject_t obj, char * oid )
41 int len = 0; /* TODO: Do we need this parameter? */
43 //DBG( 0, "PmlSetID(obj=0x%8.8X)\n", obj );
53 if( len > PML_MAX_OID_LEN )
58 /* TODO: Disable trap (if enabled) on old OID. */
60 memcpy( obj->oid, oid, len );
63 obj->numberOfValidValues = 0;
65 /* TODO: Clear out other trap-related fields. */
67 //DBG( 0, "PmlSetID(obj=0x%8.8X) returns OK.\n", obj );
71 static PmlValue_t PmlGetLastValue( PmlObject_t obj )
73 if( obj->numberOfValidValues <= 0 )
77 return &obj->value[obj->indexOfLastValue];
80 static PmlValue_t PmlPrepareNextValue( PmlObject_t obj )
82 obj->indexOfLastValue = ( obj->indexOfLastValue + 1 ) %
84 if( obj->numberOfValidValues < PML_MAX_OID_VALUES )
86 obj->numberOfValidValues++;
88 return &obj->value[obj->indexOfLastValue];
91 static int PmlSetPrefixValue( PmlObject_t obj,
98 PmlValue_t v = PmlPrepareNextValue( obj );
101 /*DBG( 0, "PmlSetPrefixValue(obj=0x%8.8X,type=0x%4.4X,"
102 "lenPrefix=%d,lenValue=%d)\n",
110 ( lenPrefix + lenValue )>PML_MAX_VALUE_LEN )
112 /*DBG( 0, "PmlSetPrefixValue(obj=0x%8.8X): "
113 "invalid lenPrefix=%d and/or lenValue=%d!\n",
121 v->len = lenPrefix + lenValue;
124 memcpy( v->value, prefix, lenPrefix );
128 memcpy( v->value + lenPrefix, value, lenValue );
130 v->value[lenPrefix + lenValue] = 0;
134 /*DBG( 0, "PmlSetPrefixValue(obj=0x%8.8X) returns %d.\n",
140 int __attribute__ ((visibility ("hidden"))) PmlSetValue( PmlObject_t obj, int type, char * value, int len )
142 return PmlSetPrefixValue( obj, type, 0, 0, value, len );
145 int __attribute__ ((visibility ("hidden"))) PmlSetIntegerValue( PmlObject_t obj, int type, int value )
147 char buffer[sizeof( int )];
148 int len = sizeof( int ), i = len - 1;
152 buffer[i] = value & 0xFF;
160 for( ; !buffer[i] && i < ( len ); i++ )
163 return PmlSetPrefixValue( obj, type, buffer + i, len - i, 0, 0 );
166 static int PmlGetPrefixValue( PmlObject_t obj,
174 PmlValue_t v = PmlGetLastValue( obj );
184 if( !prefix && !buffer )
189 if( lenPrefix < 0 || maxlen < 0 )
194 if( v->len > lenPrefix + maxlen )
198 if( v->len < lenPrefix )
205 memcpy( prefix, v->value, lenPrefix );
207 len = v->len - lenPrefix;
210 memcpy( buffer, v->value + lenPrefix, len );
220 int __attribute__ ((visibility ("hidden"))) PmlGetValue(PmlObject_t obj, int *pType, char *buffer, int maxlen)
222 return PmlGetPrefixValue( obj, pType, 0, 0, buffer, maxlen );
225 int __attribute__ ((visibility ("hidden"))) PmlGetStringValue( PmlObject_t obj,
231 unsigned char prefix[2];
233 if( PmlGetPrefixValue( obj, &type, 0, 0, 0, 0 ) == ERROR )
238 len = PmlGetPrefixValue( obj, &type, (char *)prefix, 2, buffer, maxlen );
245 *pSymbolSet = ( ( prefix[0] << 8 ) | prefix[1] );
251 int __attribute__ ((visibility ("hidden"))) PmlGetIntegerValue( PmlObject_t obj, int * pType, int * pValue )
254 unsigned char svalue[sizeof( int )];
255 int accum = 0, i, len;
262 len = PmlGetPrefixValue( obj, pType, 0, 0, (char *)svalue, sizeof( int ) );
268 for( i = 0; i < len; i++ )
270 accum = ( ( accum << 8 ) | ( svalue[i] & 0xFF ) );
280 static int PmlSetStatus( PmlObject_t obj, int status )
282 obj->status = status;
287 static int PmlGetStatus( PmlObject_t obj )
292 int __attribute__ ((visibility ("hidden"))) PmlRequestSet( int deviceid, int channelid, PmlObject_t obj )
294 unsigned char data[PML_MAX_DATALEN];
295 int datalen=0, status=ERROR, type, result, pml_result;
297 PmlSetStatus(obj, PML_ERROR);
299 datalen = PmlGetValue(obj, &type, (char *)data, sizeof(data));
301 result = hpmud_set_pml(deviceid, channelid, obj->oid, type, data, datalen, &pml_result);
303 PmlSetStatus(obj, pml_result);
305 if (result == HPMUD_R_OK)
308 return status; /* OK = valid I/O result */
311 int __attribute__ ((visibility ("hidden"))) PmlRequestSetRetry( int deviceid, int channelid, PmlObject_t obj, int count, int delay )
325 if ((r = PmlRequestSet(deviceid, channelid, obj)) == ERROR)
327 if (PmlGetStatus(obj) == PML_ERROR_ACTION_CAN_NOT_BE_PERFORMED_NOW && count > 0)
336 /* Check PML result. */
337 if (PmlGetStatus(obj) & PML_ERROR)
339 DBG(6, "PML set failed: oid=%s count=%d delay=%d %s %d\n", obj->oid, count, delay, __FILE__, __LINE__);
346 return stat; /* OK = valid I/O result AND PML result */
349 int __attribute__ ((visibility ("hidden"))) PmlRequestGet( int deviceid, int channelid, PmlObject_t obj )
351 unsigned char data[PML_MAX_DATALEN];
352 int datalen=0, stat=ERROR, type, pml_result;
353 enum HPMUD_RESULT result;
355 result = hpmud_get_pml(deviceid, channelid, obj->oid, data, sizeof(data), &datalen, &type, &pml_result);
357 PmlSetStatus(obj, pml_result);
359 if (result == HPMUD_R_OK)
361 PmlSetValue(obj, type, (char *)data, datalen);
369 * Phase 2 rewrite. des
372 static int is_zero(char *buf, int size)
376 for (i=0; i<size; i++)
384 /* Unlock Scanner. */
385 static int clr_scan_token(HPAIO_RECORD *hpaio)
387 int len, i, stat=ERROR;
388 int max = sizeof(hpaio->pml.scanToken);
390 if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objScanToken) == ERROR)
392 len = PmlGetValue(hpaio->pml.objScanToken, 0, hpaio->pml.scanToken, max);
394 if (len > 0 && !is_zero(hpaio->pml.scanToken, len))
397 len = (len > max) ? max : len;
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)
403 if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objScanToken) == ERROR)
407 hpaio->pml.lenScanToken = len;
415 static int set_scan_token(HPAIO_RECORD *hpaio)
419 /* Make sure token==0. */
420 if (clr_scan_token(hpaio) == ERROR)
423 if (hpaio->pml.lenScanToken > 0)
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)
428 if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objScanToken) == ERROR)
437 static int set_scan_parameters(HPAIO_RECORD *hpaio)
439 int pixelDataType, stat=ERROR;
440 struct PmlResolution resolution;
441 int copierReduction = 100;
444 hpaio->effectiveScanMode = hpaio->currentScanMode;
445 hpaio->effectiveResolution = hpaio->currentResolution;
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)
452 /* Set pixel data type. */
453 switch(hpaio->currentScanMode)
455 case SCAN_MODE_LINEART:
456 pixelDataType = PML_DATA_TYPE_LINEART;
458 case SCAN_MODE_GRAYSCALE:
459 pixelDataType = PML_DATA_TYPE_GRAYSCALE;
461 case SCAN_MODE_COLOR:
463 pixelDataType = PML_DATA_TYPE_COLOR;
466 PmlSetIntegerValue(hpaio->pml.objPixelDataType, PML_TYPE_ENUMERATION, pixelDataType);
467 if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objPixelDataType) == ERROR)
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)
477 /* Set compression. */
478 switch(hpaio->currentCompression)
480 case COMPRESSION_NONE:
481 compression = PML_COMPRESSION_NONE;
484 compression = PML_COMPRESSION_MH;
487 compression = PML_COMPRESSION_MR;
489 case COMPRESSION_MMR:
490 compression = PML_COMPRESSION_MMR;
492 case COMPRESSION_JPEG:
494 compression = PML_COMPRESSION_JPEG;
498 PmlSetIntegerValue(hpaio->pml.objCompression, PML_TYPE_ENUMERATION, compression);
499 if (PmlRequestSet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objCompression) == ERROR)
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)
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))
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)
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)
529 static int pml_to_sane_status(HPAIO_RECORD *hpaio)
531 int stat=SANE_STATUS_IO_ERROR, status;
533 if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objScannerStatus) == ERROR)
535 PmlGetIntegerValue(hpaio->pml.objScannerStatus, 0, &status);
537 DBG(6, "PML scannerStatus=%x: %s %d\n", status, __FILE__, __LINE__);
539 if(status & PML_SCANNER_STATUS_FEEDER_JAM)
541 stat = SANE_STATUS_JAMMED;
543 else if(status & PML_SCANNER_STATUS_FEEDER_OPEN)
545 stat = SANE_STATUS_COVER_OPEN;
547 else if(status & PML_SCANNER_STATUS_FEEDER_EMPTY)
549 if(hpaio->currentAdfMode == ADF_MODE_FLATBED || (hpaio->currentBatchScan == SANE_FALSE && hpaio->currentAdfMode == ADF_MODE_AUTO))
551 stat = SANE_STATUS_GOOD;
555 stat = SANE_STATUS_NO_DOCS;
558 else if(status & PML_SCANNER_STATUS_INVALID_MEDIA_SIZE)
560 stat = SANE_STATUS_INVAL;
564 stat = SANE_STATUS_IO_ERROR;
568 stat = SANE_STATUS_GOOD;
575 static int check_pml_done(HPAIO_RECORD *hpaio)
577 int stat=ERROR, state;
579 /* See if pml side is done scanning. */
580 if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState) == ERROR)
582 PmlGetIntegerValue(hpaio->pml.objUploadState, 0, &state);
583 hpaio->upload_state = state;
585 if (state == PML_UPLOAD_STATE_DONE || state == PML_UPLOAD_STATE_NEWPAGE)
587 else if (state != PML_UPLOAD_STATE_ACTIVE)
589 else if (hpaio->ip_done && hpaio->mfpdtf_done)
591 if (hpaio->pml_timeout_cnt++ > 15)
593 bug("check_pml_done timeout cnt=%d: %s %d\n", hpaio->pml_timeout_cnt, __FILE__, __LINE__);
606 int __attribute__ ((visibility ("hidden"))) pml_start(HPAIO_RECORD *hpaio)
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;
616 if (hpaio->cmd_channelid < 0)
618 if (hpmud_open_channel(hpaio->deviceid, "HP-MESSAGE", &hpaio->cmd_channelid) != HPMUD_R_OK)
620 bug("failed to open pml channel: %s %d\n", __FILE__, __LINE__);
623 SendScanEvent(hpaio->deviceuri, EVENT_START_SCAN_JOB);
627 if (hpaio->scan_channelid < 0)
629 if (hpmud_open_channel(hpaio->deviceid, "HP-SCAN", &hpaio->scan_channelid) != HPMUD_R_OK)
631 bug("failed to open scan channel: %s %d\n", __FILE__, __LINE__);
637 r = pml_to_sane_status(hpaio);
638 if (r != SANE_STATUS_GOOD)
644 /* Make sure scanner is idle. */
645 if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState) == ERROR)
647 stat=SANE_STATUS_IO_ERROR;
650 PmlGetIntegerValue(hpaio->pml.objUploadState, 0, &state);
651 DBG(6, "PML uploadState=%d before scan: %s %d\n", state, __FILE__, __LINE__);
654 case PML_UPLOAD_STATE_IDLE:
655 if (set_scan_token(hpaio) == ERROR)
657 if (set_scan_parameters(hpaio) == ERROR)
660 case PML_UPLOAD_STATE_NEWPAGE:
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)
667 case PML_UPLOAD_STATE_START:
668 case PML_UPLOAD_STATE_ACTIVE:
669 goto bugout; /* scanner is busy */
670 case PML_UPLOAD_STATE_ABORTED:
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)
679 hpaio->scanParameters = hpaio->prescanParameters;
680 memset(xforms, 0, sizeof(xforms));
681 traits.iPixelsPerRow = -1;
683 switch(hpaio->effectiveScanMode)
685 case SCAN_MODE_LINEART:
686 hpaio->scanParameters.format = SANE_FRAME_GRAY;
687 hpaio->scanParameters.depth = 1;
688 traits.iBitsPerPixel = 1;
690 case SCAN_MODE_GRAYSCALE:
691 hpaio->scanParameters.format = SANE_FRAME_GRAY;
692 hpaio->scanParameters.depth = 8;
693 traits.iBitsPerPixel = 8;
695 case SCAN_MODE_COLOR:
697 hpaio->scanParameters.format = SANE_FRAME_RGB;
698 hpaio->scanParameters.depth = 8;
699 traits.iBitsPerPixel = 24;
702 traits.lHorizDPI = hpaio->effectiveResolution << 16;
703 traits.lVertDPI = hpaio->effectiveResolution << 16;
704 traits.lNumRows = -1;
705 traits.iNumPages = 1;
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)
713 /* Look for a confirmation that the scan started or failed. */
714 for(i=0; i < PML_START_SCAN_WAIT_ACTIVE_MAX_RETRIES; i++)
716 if (PmlRequestGet(hpaio->deviceid, hpaio->cmd_channelid, hpaio->pml.objUploadState) == ERROR)
718 stat=SANE_STATUS_IO_ERROR;
721 PmlGetIntegerValue(hpaio->pml.objUploadState, 0, &state);
723 if(state == PML_UPLOAD_STATE_ACTIVE)
726 if(state != PML_UPLOAD_STATE_START)
732 if (state != PML_UPLOAD_STATE_ACTIVE)
734 /* Found and error, see if we can classify it otherwise use default. */
735 r = hpaioScannerToSaneError(hpaio);
736 if (r != SANE_STATUS_GOOD)
741 /* For older all-in-ones open the scan channel now. */
744 if (hpaio->scan_channelid < 0)
746 if (hpmud_open_channel(hpaio->deviceid, "HP-SCAN", &hpaio->scan_channelid) != HPMUD_R_OK)
751 /* Find mfpdtf "New Page" block. */
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 */
757 ph = (MFPDTF_FIXED_HEADER *)hpaio->inBuffer;
758 if ((ph->DataType == DT_SCAN) && (ph->PageFlag & PF_NEW_PAGE))
759 break; /* found it */
762 index = sizeof(MFPDTF_FIXED_HEADER);
763 ps = (MFPDTF_START_PAGE *)(hpaio->inBuffer + index);
764 if (ps->ID != ID_START_PAGE)
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);
773 /* Set up image-processing pipeline. */
776 case MFPDTF_RASTER_MH:
777 pXform->aXformInfo[IP_FAX_FORMAT].dword = IP_FAX_MH;
778 ADD_XFORM( X_FAX_DECODE );
780 case MFPDTF_RASTER_MR:
781 pXform->aXformInfo[IP_FAX_FORMAT].dword = IP_FAX_MR;
782 ADD_XFORM( X_FAX_DECODE );
784 case MFPDTF_RASTER_MMR:
785 pXform->aXformInfo[IP_FAX_FORMAT].dword = IP_FAX_MMR; /* possible lineart compression */
786 ADD_XFORM( X_FAX_DECODE );
788 case MFPDTF_RASTER_BITMAP:
789 case MFPDTF_RASTER_GRAYMAP:
790 case MFPDTF_RASTER_RGB:
793 case MFPDTF_RASTER_JPEG:
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 );
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__);
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;
814 hpaio->page_done = 0;
815 hpaio->mfpdtf_timeout_cnt = 0;
816 hpaio->pml_timeout_cnt = 0;
818 hpaio->scanParameters.pixels_per_line = traits.iPixelsPerRow;
819 hpaio->scanParameters.lines = traits.lNumRows;
821 if(hpaio->scanParameters.lines < 0)
823 hpaio->scanParameters.lines = MILLIMETERS_TO_PIXELS(hpaio->bryRange.max, hpaio->effectiveResolution);
826 int mmWidth = PIXELS_TO_MILLIMETERS(traits.iPixelsPerRow, hpaio->effectiveResolution);
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 )
832 pXform->aXformInfo[IP_CROP_RIGHT].dword = MILLIMETERS_TO_PIXELS( mmWidth-hpaio->effectiveBrx, hpaio->effectiveResolution );
834 pXform->aXformInfo[IP_CROP_TOP].dword = MILLIMETERS_TO_PIXELS( hpaio->effectiveTly, hpaio->effectiveResolution );
835 if( hpaio->currentLengthMeasurement != LENGTH_MEASUREMENT_UNLIMITED )
837 hpaio->scanParameters.lines = pXform->aXformInfo[IP_CROP_MAXOUTROWS].dword =
838 MILLIMETERS_TO_PIXELS(hpaio->effectiveBry - hpaio->effectiveTly, hpaio->effectiveResolution);
840 hpaio->scanParameters.pixels_per_line -= pXform->aXformInfo[IP_CROP_LEFT].dword + pXform->aXformInfo[IP_CROP_RIGHT].dword;
843 if( hpaio->currentLengthMeasurement == LENGTH_MEASUREMENT_PADDED )
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;
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 )
860 wResult = ipOpen( pXform - xforms, xforms, 0, &hpaio->hJob );
862 if( wResult != IP_DONE || !hpaio->hJob )
864 stat = SANE_STATUS_INVAL;
868 traits.iComponentsPerPixel = ( ( traits.iBitsPerPixel % 3 ) ? 1 : 3 );
869 wResult = ipSetDefaultInputTraits( hpaio->hJob, &traits );
871 if( wResult != IP_DONE )
873 stat = SANE_STATUS_INVAL;
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));
880 if( hpaio->currentLengthMeasurement == LENGTH_MEASUREMENT_UNKNOWN || hpaio->currentLengthMeasurement == LENGTH_MEASUREMENT_UNLIMITED )
882 hpaio->scanParameters.lines = -1;
885 stat = SANE_STATUS_GOOD;
891 int __attribute__ ((visibility ("hidden"))) pml_read(HPAIO_RECORD *hpaio, SANE_Byte *data, SANE_Int maxLength, SANE_Int *pLength)
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;
901 DBG(8, "sane_hpaio_read called handle=%p data=%p maxLength=%d length=%d: %s %d\n", hpaio, data, maxLength, *pLength, __FILE__, __LINE__);
903 /* Process any bytes in current record. */
904 if (hpaio->RecordIndex < hpaio->RecordSize)
906 inputAvail = hpaio->RecordSize - hpaio->RecordIndex;
907 input = hpaio->inBuffer + hpaio->BlockIndex + hpaio->RecordIndex + sizeof(MFPDTF_RASTER);
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))
913 bug("ipConvert error=%x: %s %d\n", wResult, __FILE__, __LINE__);
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 */
921 else if (hpaio->BlockIndex < hpaio->BlockSize)
923 /* Process next record in current mfpdtf block. */
924 pd = (MFPDTF_RASTER *)(hpaio->inBuffer + hpaio->BlockIndex);
925 if (pd->ID == ID_RASTER_DATA)
928 hpaio->RecordSize = le16toh(pd->Size);
929 hpaio->RecordIndex = 0;
931 else if (pd->ID == ID_END_PAGE)
933 /* End Page Record */
934 hpaio->page_done = 1;
935 hpaio->BlockIndex += sizeof(MFPDTF_END_PAGE); /* bump index to next record */
939 bug("unknown mfpdtf record id=%d: pml_read %s %d\n", pd->ID, __FILE__, __LINE__);
943 else if (!hpaio->mfpdtf_done)
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 */
949 hpaio->BlockSize = 0;
950 hpaio->BlockIndex = 0;
954 if (hpaio->page_done || hpaio->pml_done)
955 hpaio->mfpdtf_done = 1; /* normal timeout */
956 else if (hpaio->mfpdtf_timeout_cnt++ > 5)
958 bug("read_mfpdtf_block timeout cnt=%d: %s %d\n", hpaio->mfpdtf_timeout_cnt, __FILE__, __LINE__);
963 if (check_pml_done(hpaio) == ERROR)
969 hpaio->mfpdtf_timeout_cnt = 0;
971 if (bsize > sizeof(MFPDTF_FIXED_HEADER))
973 hpaio->BlockSize = bsize; /* set for next sane_read */
974 hpaio->BlockIndex = sizeof(MFPDTF_FIXED_HEADER);
978 else if ((hpaio->page_done || hpaio->pml_done) && !hpaio->ip_done)
980 /* No more scan data, flush ipconvert pipeline. */
982 wResult = ipConvert(hpaio->hJob, inputAvail, input, &inputUsed, &inputNextPos, outputAvail, output, &outputUsed, &outputThisPos);
983 if (wResult & (IP_INPUT_ERROR | IP_FATAL_ERROR))
985 bug("hpaio: ipConvert error=%x\n", wResult);
988 *pLength = outputUsed;
992 else if (!hpaio->pml_done)
994 if (check_pml_done(hpaio) == ERROR)
998 if(hpaio->ip_done && hpaio->mfpdtf_done && hpaio->pml_done)
999 stat = SANE_STATUS_EOF; /* done scan_read */
1001 stat = SANE_STATUS_GOOD; /* repeat scan_read */
1004 if (stat != SANE_STATUS_GOOD)
1008 ipClose(hpaio->hJob);
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);
1016 DBG(8, "sane_hpaio_read returned output=%p outputUsed=%d length=%d status=%d: %s %d\n", output, outputUsed, *pLength, stat, __FILE__, __LINE__);
1021 int __attribute__ ((visibility ("hidden"))) pml_cancel(HPAIO_RECORD *hpaio)
1023 int oldStuff = (hpaio->preDenali || hpaio->fromDenali || hpaio->denali) ? 1 : 0;
1027 ipClose(hpaio->hJob);
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)
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))
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);
1043 if (hpaio->scan_channelid >= 0)
1045 hpmud_close_channel(hpaio->deviceid, hpaio->scan_channelid);
1046 hpaio->scan_channelid = -1;
1048 if (hpaio->cmd_channelid >= 0)
1050 hpmud_close_channel(hpaio->deviceid, hpaio->cmd_channelid);
1051 hpaio->cmd_channelid = -1;
1052 SendScanEvent(hpaio->deviceuri, EVENT_END_SCAN_JOB);