1 /************************************************************************************
3 ledm.c - HP SANE backend support for LEDM based multi-function peripherals
4 (c) 2010 Copyright Hewlett-Packard Development Company, LP
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10 of the Software, and to permit persons to whom the Software is furnished to do
11 so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 Primary Author: Naga Samrat Chowary, Narla
24 Contributing Authors: Yashwant Kumar Sahu,Sarbeswar Meher
26 *************************************************************************************/
44 # include "saneopts.h"
47 # define DEBUG_DECLARE_ONLY
48 # include "sanei_debug.h"
50 static struct ledm_session *session = NULL;
52 /* Verify current x/y extents and set effective extents. */
53 static int set_extents(struct ledm_session *ps)
57 if ((ps->currentBrx > ps->currentTlx) && (ps->currentBrx - ps->currentTlx >= ps->min_width) && (ps->currentBrx - ps->currentTlx <= ps->tlxRange.max))
59 ps->effectiveTlx = ps->currentTlx;
60 ps->effectiveBrx = ps->currentBrx;
64 ps->effectiveTlx = 0; /* current setting is not valid, zero it */
68 if ((ps->currentBry > ps->currentTly) && (ps->currentBry - ps->currentTly > ps->min_height) && (ps->currentBry - ps->currentTly <= ps->tlyRange.max))
70 ps->effectiveTly = ps->currentTly;
71 ps->effectiveBry = ps->currentBry;
75 ps->effectiveTly = 0; /* current setting is not valid, zero it */
82 static struct ledm_session *create_session()
84 struct ledm_session *ps;
86 if ((ps = malloc(sizeof(struct ledm_session))) == NULL)
90 memset(ps, 0, sizeof(struct ledm_session));
99 /* Get raw data (ie: uncompressed data) from image processor. */
100 static int get_ip_data(struct ledm_session *ps, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length)
102 int ip_ret=IP_INPUT_ERROR;
103 unsigned int outputAvail=maxLength, outputUsed=0, outputThisPos;
104 unsigned char *input, *output = data;
105 unsigned int inputAvail, inputUsed=0, inputNextPos;
114 eof=bb_get_image_data(ps, outputAvail);
118 inputAvail = ps->cnt;
119 input = &ps->buf[ps->index];
128 /* Transform input data to output. Note, output buffer may consume more bytes than input buffer (ie: jpeg to raster). */
129 ip_ret = ipConvert(ps->ip_handle, inputAvail, input, &inputUsed, &inputNextPos, outputAvail, output, &outputUsed, &outputThisPos);
132 DBG6("cnt=%d index=%d input=%p inputAvail=%d inputUsed=%d inputNextPos=%d output=%p outputAvail=%d outputUsed=%d outputThisPos=%d\n", ps->cnt, ps->index, input,
133 inputAvail, inputUsed, inputNextPos, output, outputAvail, outputUsed, outputThisPos);
137 if (inputAvail == inputUsed)
139 ps->index = ps->cnt = 0; //
143 ps->cnt -= inputUsed; // save left over buffer for next soap_read
144 ps->index += inputUsed;
149 *length = outputUsed;
151 /* For sane do not send output data simultaneously with IP_DONE. */
152 if (ip_ret & IP_DONE && outputUsed)
160 static int set_scan_mode_side_effects(struct ledm_session *ps, enum COLOR_ENTRY scanMode)
164 memset(ps->compressionList, 0, sizeof(ps->compressionList));
165 memset(ps->compressionMap, 0, sizeof(ps->compressionMap));
169 case CE_K1: /* same as GRAY8 */
173 // ps->compressionList[j] = STR_COMPRESSION_NONE;
174 // ps->compressionMap[j++] = SF_RAW;
175 ps->compressionList[j] = STR_COMPRESSION_JPEG;
176 ps->compressionMap[j++] = SF_JPEG;
177 ps->currentCompression = SF_JPEG;
178 ps->option[LEDM_OPTION_JPEG_QUALITY].cap |= SANE_CAP_SOFT_SELECT; /* enable jpeg quality */
183 } /* set_scan_mode_side_effects */
185 static int set_input_source_side_effects(struct ledm_session *ps, enum INPUT_SOURCE source)
190 ps->min_width = ps->platen_min_width;
191 ps->min_height = ps->platen_min_height;
192 ps->tlxRange.max = ps->platen_tlxRange.max;
193 ps->brxRange.max = ps->platen_brxRange.max;
194 ps->tlyRange.max = ps->platen_tlyRange.max;
195 ps->bryRange.max = ps->platen_bryRange.max;
200 ps->min_width = ps->adf_min_width;
201 ps->min_height = ps->adf_min_height;
202 ps->tlxRange.max = ps->adf_tlxRange.max;
203 ps->brxRange.max = ps->adf_brxRange.max;
204 ps->tlyRange.max = ps->adf_tlyRange.max;
205 ps->bryRange.max = ps->adf_bryRange.max;
210 } /* set_input_source_side_effects */
212 static int init_options(struct ledm_session *ps)
214 ps->option[LEDM_OPTION_COUNT].name = "option-cnt";
215 ps->option[LEDM_OPTION_COUNT].title = SANE_TITLE_NUM_OPTIONS;
216 ps->option[LEDM_OPTION_COUNT].desc = SANE_DESC_NUM_OPTIONS;
217 ps->option[LEDM_OPTION_COUNT].type = SANE_TYPE_INT;
218 ps->option[LEDM_OPTION_COUNT].unit = SANE_UNIT_NONE;
219 ps->option[LEDM_OPTION_COUNT].size = sizeof(SANE_Int);
220 ps->option[LEDM_OPTION_COUNT].cap = SANE_CAP_SOFT_DETECT;
221 ps->option[LEDM_OPTION_COUNT].constraint_type = SANE_CONSTRAINT_NONE;
223 ps->option[LEDM_OPTION_GROUP_SCAN_MODE].name = "mode-group";
224 ps->option[LEDM_OPTION_GROUP_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
225 ps->option[LEDM_OPTION_GROUP_SCAN_MODE].type = SANE_TYPE_GROUP;
227 ps->option[LEDM_OPTION_SCAN_MODE].name = SANE_NAME_SCAN_MODE;
228 ps->option[LEDM_OPTION_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
229 ps->option[LEDM_OPTION_SCAN_MODE].desc = SANE_DESC_SCAN_MODE;
230 ps->option[LEDM_OPTION_SCAN_MODE].type = SANE_TYPE_STRING;
231 ps->option[LEDM_OPTION_SCAN_MODE].unit = SANE_UNIT_NONE;
232 ps->option[LEDM_OPTION_SCAN_MODE].size = MAX_STRING_SIZE;
233 ps->option[LEDM_OPTION_SCAN_MODE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
234 ps->option[LEDM_OPTION_SCAN_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
235 ps->option[LEDM_OPTION_SCAN_MODE].constraint.string_list = ps->scanModeList;
237 ps->option[LEDM_OPTION_INPUT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
238 ps->option[LEDM_OPTION_INPUT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
239 ps->option[LEDM_OPTION_INPUT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
240 ps->option[LEDM_OPTION_INPUT_SOURCE].type = SANE_TYPE_STRING;
241 ps->option[LEDM_OPTION_INPUT_SOURCE].unit = SANE_UNIT_NONE;
242 ps->option[LEDM_OPTION_INPUT_SOURCE].size = MAX_STRING_SIZE;
243 ps->option[LEDM_OPTION_INPUT_SOURCE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
244 ps->option[LEDM_OPTION_INPUT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
245 ps->option[LEDM_OPTION_INPUT_SOURCE].constraint.string_list = ps->inputSourceList;
247 ps->option[LEDM_OPTION_SCAN_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
248 ps->option[LEDM_OPTION_SCAN_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
249 ps->option[LEDM_OPTION_SCAN_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
250 ps->option[LEDM_OPTION_SCAN_RESOLUTION].type = SANE_TYPE_INT;
251 ps->option[LEDM_OPTION_SCAN_RESOLUTION].unit = SANE_UNIT_DPI;
252 ps->option[LEDM_OPTION_SCAN_RESOLUTION].size = sizeof(SANE_Int);
253 ps->option[LEDM_OPTION_SCAN_RESOLUTION].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
254 ps->option[LEDM_OPTION_SCAN_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
255 ps->option[LEDM_OPTION_SCAN_RESOLUTION].constraint.word_list = ps->resolutionList;
257 ps->option[LEDM_OPTION_GROUP_ADVANCED].name = "advanced-group";
258 ps->option[LEDM_OPTION_GROUP_ADVANCED].title = STR_TITLE_ADVANCED;
259 ps->option[LEDM_OPTION_GROUP_ADVANCED].type = SANE_TYPE_GROUP;
260 ps->option[LEDM_OPTION_GROUP_ADVANCED].cap = SANE_CAP_ADVANCED;
262 ps->option[LEDM_OPTION_CONTRAST].name = SANE_NAME_CONTRAST;
263 ps->option[LEDM_OPTION_CONTRAST].title = SANE_TITLE_CONTRAST;
264 ps->option[LEDM_OPTION_CONTRAST].desc = SANE_DESC_CONTRAST;
265 ps->option[LEDM_OPTION_CONTRAST].type = SANE_TYPE_INT;
266 ps->option[LEDM_OPTION_CONTRAST].unit = SANE_UNIT_NONE;
267 ps->option[LEDM_OPTION_CONTRAST].size = sizeof(SANE_Int);
268 ps->option[LEDM_OPTION_CONTRAST].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
269 ps->option[LEDM_OPTION_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
270 ps->option[LEDM_OPTION_CONTRAST].constraint.range = &ps->contrastRange;
271 ps->contrastRange.min = LEDM_CONTRAST_MIN;
272 ps->contrastRange.max = LEDM_CONTRAST_MAX;
273 ps->contrastRange.quant = 0;
275 ps->option[LEDM_OPTION_COMPRESSION].name = STR_NAME_COMPRESSION;
276 ps->option[LEDM_OPTION_COMPRESSION].title = STR_TITLE_COMPRESSION;
277 ps->option[LEDM_OPTION_COMPRESSION].desc = STR_DESC_COMPRESSION;
278 ps->option[LEDM_OPTION_COMPRESSION].type = SANE_TYPE_STRING;
279 ps->option[LEDM_OPTION_COMPRESSION].unit = SANE_UNIT_NONE;
280 ps->option[LEDM_OPTION_COMPRESSION].size = MAX_STRING_SIZE;
281 ps->option[LEDM_OPTION_COMPRESSION].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
282 ps->option[LEDM_OPTION_COMPRESSION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
283 ps->option[LEDM_OPTION_COMPRESSION].constraint.string_list = ps->compressionList;
285 ps->option[LEDM_OPTION_JPEG_QUALITY].name = STR_NAME_JPEG_QUALITY;
286 ps->option[LEDM_OPTION_JPEG_QUALITY].title = STR_TITLE_JPEG_QUALITY;
287 ps->option[LEDM_OPTION_JPEG_QUALITY].desc = STR_DESC_JPEG_QUALITY;
288 ps->option[LEDM_OPTION_JPEG_QUALITY].type = SANE_TYPE_INT;
289 ps->option[LEDM_OPTION_JPEG_QUALITY].unit = SANE_UNIT_NONE;
290 ps->option[LEDM_OPTION_JPEG_QUALITY].size = sizeof(SANE_Int);
291 ps->option[LEDM_OPTION_JPEG_QUALITY].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
292 ps->option[LEDM_OPTION_JPEG_QUALITY].constraint_type = SANE_CONSTRAINT_RANGE;
293 ps->option[LEDM_OPTION_JPEG_QUALITY].constraint.range = &ps->jpegQualityRange;
294 ps->jpegQualityRange.min = MIN_JPEG_COMPRESSION_FACTOR;
295 ps->jpegQualityRange.max = MAX_JPEG_COMPRESSION_FACTOR;
296 ps->jpegQualityRange.quant = 0;
298 ps->option[LEDM_OPTION_GROUP_GEOMETRY].name = "geometry-group";
299 ps->option[LEDM_OPTION_GROUP_GEOMETRY].title = STR_TITLE_GEOMETRY;
300 ps->option[LEDM_OPTION_GROUP_GEOMETRY].type = SANE_TYPE_GROUP;
301 ps->option[LEDM_OPTION_GROUP_GEOMETRY].cap = SANE_CAP_ADVANCED;
303 ps->option[LEDM_OPTION_TL_X].name = SANE_NAME_SCAN_TL_X;
304 ps->option[LEDM_OPTION_TL_X].title = SANE_TITLE_SCAN_TL_X;
305 ps->option[LEDM_OPTION_TL_X].desc = SANE_DESC_SCAN_TL_X;
306 ps->option[LEDM_OPTION_TL_X].type = SANE_TYPE_FIXED;
307 ps->option[LEDM_OPTION_TL_X].unit = SANE_UNIT_MM;
308 ps->option[LEDM_OPTION_TL_X].size = sizeof(SANE_Int);
309 ps->option[LEDM_OPTION_TL_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
310 ps->option[LEDM_OPTION_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
311 ps->option[LEDM_OPTION_TL_X].constraint.range = &ps->tlxRange;
312 ps->tlxRange.min = 0;
313 ps->tlxRange.quant = 0;
315 ps->option[LEDM_OPTION_TL_Y].name = SANE_NAME_SCAN_TL_Y;
316 ps->option[LEDM_OPTION_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
317 ps->option[LEDM_OPTION_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
318 ps->option[LEDM_OPTION_TL_Y].type = SANE_TYPE_FIXED;
319 ps->option[LEDM_OPTION_TL_Y].unit = SANE_UNIT_MM;
320 ps->option[LEDM_OPTION_TL_Y].size = sizeof(SANE_Int);
321 ps->option[LEDM_OPTION_TL_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
322 ps->option[LEDM_OPTION_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
323 ps->option[LEDM_OPTION_TL_Y].constraint.range = &ps->tlyRange;
324 ps->tlyRange.min = 0;
325 ps->tlyRange.quant = 0;
327 ps->option[LEDM_OPTION_BR_X].name = SANE_NAME_SCAN_BR_X;
328 ps->option[LEDM_OPTION_BR_X].title = SANE_TITLE_SCAN_BR_X;
329 ps->option[LEDM_OPTION_BR_X].desc = SANE_DESC_SCAN_BR_X;
330 ps->option[LEDM_OPTION_BR_X].type = SANE_TYPE_FIXED;
331 ps->option[LEDM_OPTION_BR_X].unit = SANE_UNIT_MM;
332 ps->option[LEDM_OPTION_BR_X].size = sizeof(SANE_Int);
333 ps->option[LEDM_OPTION_BR_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
334 ps->option[LEDM_OPTION_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
335 ps->option[LEDM_OPTION_BR_X].constraint.range = &ps->brxRange;
336 ps->brxRange.min = 0;
337 ps->brxRange.quant = 0;
339 ps->option[LEDM_OPTION_BR_Y].name = SANE_NAME_SCAN_BR_Y;
340 ps->option[LEDM_OPTION_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
341 ps->option[LEDM_OPTION_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
342 ps->option[LEDM_OPTION_BR_Y].type = SANE_TYPE_FIXED;
343 ps->option[LEDM_OPTION_BR_Y].unit = SANE_UNIT_MM;
344 ps->option[LEDM_OPTION_BR_Y].size = sizeof(SANE_Int);
345 ps->option[LEDM_OPTION_BR_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
346 ps->option[LEDM_OPTION_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
347 ps->option[LEDM_OPTION_BR_Y].constraint.range = &ps->bryRange;
348 ps->bryRange.min = 0;
349 ps->bryRange.quant = 0;
354 /*----------------------------------- LEDM API Calls ------------------------------------*/
356 SANE_Status __attribute__ ((visibility ("hidden"))) ledm_open(SANE_String_Const device, SANE_Handle *handle)
358 struct hpmud_model_attributes ma;
359 int stat = SANE_STATUS_IO_ERROR;
363 return SANE_STATUS_DEVICE_BUSY;
365 if((session = create_session()) == NULL)
366 return SANE_STATUS_NO_MEM;
368 /* Set session to specified device. */
369 snprintf(session->uri, sizeof(session->uri)-1, "hp:%s", device); /* prepend "hp:" */
371 /* Get actual model attributes from models.dat. */
372 hpmud_query_model(session->uri, &ma);
373 session->scan_type = ma.scantype;
375 if (hpmud_open_device(session->uri, ma.mfp_mode, &session->dd) != HPMUD_R_OK)
377 stat = SANE_STATUS_IO_ERROR;
381 init_options(session);
383 if (bb_open(session))
385 stat = SANE_STATUS_IO_ERROR;
389 /* Set supported Scan Modes as determined by bb_open. */
390 ledm_control_option(session, LEDM_OPTION_SCAN_MODE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
392 /* Set scan input sources as determined by bb_open. */
393 ledm_control_option(session, LEDM_OPTION_INPUT_SOURCE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
395 /* Set supported resolutions. */
396 ledm_control_option(session, LEDM_OPTION_SCAN_RESOLUTION, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
398 /* Set supported contrast. */
399 ledm_control_option(session, LEDM_OPTION_CONTRAST, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
401 /* Set supported compression. (Note, cm1017 may say it supports MMR, but it doesn't) */
402 ledm_control_option(session, LEDM_OPTION_COMPRESSION, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
404 /* Determine supported jpeg quality factor as determined by bb_open. */
405 ledm_control_option(session, LEDM_OPTION_JPEG_QUALITY, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
407 /* Set x,y extents. See bb_open */
408 ledm_control_option(session, LEDM_OPTION_TL_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
409 ledm_control_option(session, LEDM_OPTION_TL_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
410 ledm_control_option(session, LEDM_OPTION_BR_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
411 ledm_control_option(session, LEDM_OPTION_BR_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
413 *handle = (SANE_Handle *)session;
415 stat = SANE_STATUS_GOOD;
419 if (stat != SANE_STATUS_GOOD)
424 hpmud_close_channel(session->dd, session->cd);
426 hpmud_close_device(session->dd);
435 const SANE_Option_Descriptor *ledm_get_option_descriptor(SANE_Handle handle, SANE_Int option)
437 struct ledm_session *ps = (struct ledm_session *)handle;
439 DBG8("sane_hpaio_get_option_descriptor(option=%s)\n", ps->option[option].name);
441 if (option < 0 || option >= LEDM_OPTION_MAX)
444 return &ps->option[option];
445 } /* ledm_get_option_descriptor */
447 SANE_Status ledm_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int *set_result)
449 struct ledm_session *ps = (struct ledm_session *)handle;
450 SANE_Int *int_value = value, mset_result=0;
451 int i, stat=SANE_STATUS_INVAL;
455 case LEDM_OPTION_COUNT:
456 if (action == SANE_ACTION_GET_VALUE)
458 *int_value = LEDM_OPTION_MAX;
459 stat = SANE_STATUS_GOOD;
462 case LEDM_OPTION_SCAN_MODE:
463 if(action == SANE_ACTION_GET_VALUE)
465 for(i=0; ps->scanModeList[i]; i++)
467 if(ps->currentScanMode == ps->scanModeMap[i])
469 strcpy(value, ps->scanModeList[i]);
470 stat = SANE_STATUS_GOOD;
475 else if (action == SANE_ACTION_SET_VALUE)
477 for (i=0; ps->scanModeList[i]; i++)
479 if (strcasecmp(ps->scanModeList[i], value) == 0)
481 ps->currentScanMode = ps->scanModeMap[i];
482 set_scan_mode_side_effects(ps, ps->currentScanMode);
483 mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
484 stat = SANE_STATUS_GOOD;
491 ps->currentScanMode = CE_COLOR8;
492 set_scan_mode_side_effects(ps, ps->currentScanMode);
493 stat = SANE_STATUS_GOOD;
496 case LEDM_OPTION_INPUT_SOURCE:
497 if (action == SANE_ACTION_GET_VALUE)
499 for (i=0; ps->inputSourceList[i]; i++)
501 if (ps->currentInputSource == ps->inputSourceMap[i])
503 strcpy(value, ps->inputSourceList[i]);
504 stat = SANE_STATUS_GOOD;
509 else if (action == SANE_ACTION_SET_VALUE)
511 for (i=0; ps->inputSourceList[i]; i++)
513 if (strcasecmp(ps->inputSourceList[i], value) == 0)
515 ps->currentInputSource = ps->inputSourceMap[i];
516 set_input_source_side_effects(ps, ps->currentInputSource);
517 if(ps->currentInputSource == IS_PLATEN)
519 i = session->platen_resolutionList[0] + 1;
520 while(i--) session->resolutionList[i] = session->platen_resolutionList[i];
524 i = session->adf_resolutionList[0] + 1;
525 while(i--) session->resolutionList[i] = session->adf_resolutionList[i];
527 ps->currentResolution = session->resolutionList[1];
528 mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
529 stat = SANE_STATUS_GOOD;
536 ps->currentInputSource = IS_PLATEN;
537 set_input_source_side_effects(ps, ps->currentInputSource);
538 mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
539 stat = SANE_STATUS_GOOD;
542 case LEDM_OPTION_SCAN_RESOLUTION:
543 if (action == SANE_ACTION_GET_VALUE)
545 *int_value = ps->currentResolution;
546 stat = SANE_STATUS_GOOD;
548 else if (action == SANE_ACTION_SET_VALUE)
550 for (i=1; i <= ps->resolutionList[0]; i++)
552 if (ps->resolutionList[i] == *int_value)
554 ps->currentResolution = *int_value;
555 if(ps->currentResolution == 4800) SendScanEvent(ps->uri, EVENT_SIZE_WARNING);
556 mset_result |= SANE_INFO_RELOAD_PARAMS;
557 stat = SANE_STATUS_GOOD;
564 ps->currentResolution = 75;
565 stat = SANE_STATUS_GOOD;
568 case LEDM_OPTION_CONTRAST:
569 if (action == SANE_ACTION_GET_VALUE)
571 *int_value = ps->currentContrast;
572 stat = SANE_STATUS_GOOD;
574 else if (action == SANE_ACTION_SET_VALUE)
576 if (*int_value >= LEDM_CONTRAST_MIN && *int_value <= LEDM_CONTRAST_MAX)
578 ps->currentContrast = *int_value;
579 stat = SANE_STATUS_GOOD;
585 ps->currentContrast = LEDM_CONTRAST_DEFAULT;
586 stat = SANE_STATUS_GOOD;
589 case LEDM_OPTION_COMPRESSION:
590 if (action == SANE_ACTION_GET_VALUE)
592 for (i=0; ps->compressionList[i]; i++)
594 if (ps->currentCompression == ps->compressionMap[i])
596 strcpy(value, ps->compressionList[i]);
597 stat = SANE_STATUS_GOOD;
602 else if (action == SANE_ACTION_SET_VALUE)
604 for (i=0; ps->compressionList[i]; i++)
606 if (strcasecmp(ps->compressionList[i], value) == 0)
608 ps->currentCompression = ps->compressionMap[i];
609 stat = SANE_STATUS_GOOD;
616 ps->currentCompression = SF_JPEG;
617 stat = SANE_STATUS_GOOD;
620 case LEDM_OPTION_JPEG_QUALITY:
621 if (action == SANE_ACTION_GET_VALUE)
623 *int_value = ps->currentJpegQuality;
624 stat = SANE_STATUS_GOOD;
626 else if (action == SANE_ACTION_SET_VALUE)
628 if (*int_value >= MIN_JPEG_COMPRESSION_FACTOR && *int_value <= MAX_JPEG_COMPRESSION_FACTOR)
630 ps->currentJpegQuality = *int_value;
631 stat = SANE_STATUS_GOOD;
637 ps->currentJpegQuality = SAFER_JPEG_COMPRESSION_FACTOR;
638 stat = SANE_STATUS_GOOD;
641 case LEDM_OPTION_TL_X:
642 if (action == SANE_ACTION_GET_VALUE)
644 *int_value = ps->currentTlx;
645 stat = SANE_STATUS_GOOD;
647 else if (action == SANE_ACTION_SET_VALUE)
649 if (*int_value >= ps->tlxRange.min && *int_value <= ps->tlxRange.max)
651 ps->currentTlx = *int_value;
652 mset_result |= SANE_INFO_RELOAD_PARAMS;
653 stat = SANE_STATUS_GOOD;
659 ps->currentTlx = ps->tlxRange.min;
660 stat = SANE_STATUS_GOOD;
663 case LEDM_OPTION_TL_Y:
664 if (action == SANE_ACTION_GET_VALUE)
666 *int_value = ps->currentTly;
667 stat = SANE_STATUS_GOOD;
669 else if (action == SANE_ACTION_SET_VALUE)
671 if (*int_value >= ps->tlyRange.min && *int_value <= ps->tlyRange.max)
674 ps->currentTly = *int_value;
675 mset_result |= SANE_INFO_RELOAD_PARAMS;
676 stat = SANE_STATUS_GOOD;
682 ps->currentTly = ps->tlyRange.min;
683 stat = SANE_STATUS_GOOD;
686 case LEDM_OPTION_BR_X:
687 if (action == SANE_ACTION_GET_VALUE)
689 *int_value = ps->currentBrx;
690 stat = SANE_STATUS_GOOD;
692 else if (action == SANE_ACTION_SET_VALUE)
694 if (*int_value >= ps->brxRange.min && *int_value <= ps->brxRange.max)
696 ps->currentBrx = *int_value;
697 mset_result |= SANE_INFO_RELOAD_PARAMS;
698 stat = SANE_STATUS_GOOD;
704 ps->currentBrx = ps->brxRange.max;
705 stat = SANE_STATUS_GOOD;
708 case LEDM_OPTION_BR_Y:
709 if (action == SANE_ACTION_GET_VALUE)
711 *int_value = ps->currentBry;
712 stat = SANE_STATUS_GOOD;
714 else if (action == SANE_ACTION_SET_VALUE)
716 if (*int_value >= ps->bryRange.min && *int_value <= ps->bryRange.max)
718 ps->currentBry = *int_value;
719 mset_result |= SANE_INFO_RELOAD_PARAMS;
720 stat = SANE_STATUS_GOOD;
726 ps->currentBry = ps->bryRange.max;
727 stat = SANE_STATUS_GOOD;
735 *set_result = mset_result;
737 if (stat != SANE_STATUS_GOOD)
739 BUG("control_option failed: option=%s action=%s\n", ps->option[option].name, action==SANE_ACTION_GET_VALUE ? "get" : action==SANE_ACTION_SET_VALUE ? "set" : "auto");
743 } /* ledm_control_option */
745 SANE_Status ledm_get_parameters(SANE_Handle handle, SANE_Parameters *params)
747 struct ledm_session *ps = (struct ledm_session *)handle;
751 /* Get scan parameters for sane client. */
752 bb_get_parameters(ps, params, ps->ip_handle ? SPO_STARTED : SPO_BEST_GUESS);
754 DBG8("sane_hpaio_get_parameters(): format=%d, last_frame=%d, lines=%d, depth=%d, pixels_per_line=%d, bytes_per_line=%d\n",
755 params->format, params->last_frame, params->lines, params->depth, params->pixels_per_line, params->bytes_per_line);
757 return SANE_STATUS_GOOD;
758 } /* ledm_get_parameters */
760 SANE_Status ledm_start(SANE_Handle handle)
762 struct ledm_session *ps = (struct ledm_session *)handle;
764 IP_IMAGE_TRAITS traits;
765 IP_XFORM_SPEC xforms[IP_MAX_XFORMS], *pXform=xforms;
768 DBG8("sane_hpaio_start()\n");
770 ps -> user_cancel = 0;
776 stat = SANE_STATUS_INVAL;
780 /* If input is ADF and ADF is empty, return SANE_STATUS_NO_DOCS. */
781 if (ps->currentInputSource==IS_ADF || ps->currentInputSource ==IS_ADF_DUPLEX)
783 ret = bb_is_paper_in_adf(ps); /* 0 = no paper in adf, 1 = paper in adf, -1 = error */
786 stat = SANE_STATUS_NO_DOCS; /* done scanning */
787 SendScanEvent (ps->uri, EVENT_SCAN_ADF_NO_DOCS);
792 stat = SANE_STATUS_IO_ERROR;
797 /* Start scan and get actual image traits. */
798 stat = bb_start_scan(ps);
799 if (stat != SANE_STATUS_GOOD)
804 stat = SANE_STATUS_GOOD ;
808 SendScanEvent(ps->uri, EVENT_START_SCAN_JOB);
810 memset(xforms, 0, sizeof(xforms));
812 /* Setup image-processing pipeline for xform. */
813 if (ps->currentScanMode == CE_COLOR8 || ps->currentScanMode == CE_GRAY8)
815 switch(ps->currentCompression)
818 pXform->aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword = 0; /* 0=no */
819 ADD_XFORM(X_JPG_DECODE);
820 pXform->aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword = IP_CNV_YCC_TO_SRGB;
821 pXform->aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword = 0x00010000;
822 ADD_XFORM(X_CNV_COLOR_SPACE);
830 { /* Must be BLACK_AND_WHITE1 (Lineart). */
831 switch(ps->currentCompression)
834 pXform->aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword = 0; /* 0=no */
835 ADD_XFORM(X_JPG_DECODE);
836 pXform->aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword = 127;
837 ADD_XFORM(X_GRAY_2_BI);
840 pXform->aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword = 127;
841 ADD_XFORM(X_GRAY_2_BI);
847 /* Setup x/y cropping for xform. (Actually we let cm1017 do it's own cropping) */
848 pXform->aXformInfo[IP_CROP_LEFT].dword = 0;
849 pXform->aXformInfo[IP_CROP_RIGHT].dword = 0;
850 pXform->aXformInfo[IP_CROP_TOP].dword = 0;
851 pXform->aXformInfo[IP_CROP_MAXOUTROWS].dword = 0;
854 /* Setup x/y padding for xform. (Actually we let cm1017 do it's own padding) */
855 pXform->aXformInfo[IP_PAD_LEFT].dword = 0; /* # of pixels to add to left side */
856 pXform->aXformInfo[IP_PAD_RIGHT].dword = 0; /* # of pixels to add to right side */
857 pXform->aXformInfo[IP_PAD_TOP].dword = 0; /* # of rows to add to top */
858 pXform->aXformInfo[IP_PAD_BOTTOM].dword = 0; /* # of rows to add to bottom */
859 pXform->aXformInfo[IP_PAD_VALUE].dword = ps->currentScanMode == CE_K1 ? 0 : -1; /* lineart white = 0, rgb white = -1 */
860 pXform->aXformInfo[IP_PAD_MIN_HEIGHT].dword = 0;
863 /* Open image processor. */
864 if ((ret = ipOpen(pXform-xforms, xforms, 0, &ps->ip_handle)) != IP_DONE)
866 stat = SANE_STATUS_INVAL;
870 /* Get scan parameters for image processor. */
871 if (ps->currentCompression == SF_RAW)
872 bb_get_parameters(ps, &pp, SPO_STARTED_JR); /* hpraw, use actual parameters */
874 bb_get_parameters(ps, &pp, SPO_BEST_GUESS); /* jpeg, use best guess */
875 traits.iPixelsPerRow = pp.pixels_per_line;
876 switch(ps->currentScanMode)
878 case CE_K1: /* lineart (let IP create Mono from Gray8) */
880 traits.iBitsPerPixel = 8; /* grayscale */
884 traits.iBitsPerPixel = 24; /* color */
887 traits.lHorizDPI = ps->currentResolution << 16;
888 traits.lVertDPI = ps->currentResolution << 16;
889 traits.lNumRows = pp.lines;
890 traits.iNumPages = 1;
892 traits.iComponentsPerPixel = ((traits.iBitsPerPixel % 3) ? 1 : 3);
893 ipSetDefaultInputTraits(ps->ip_handle, &traits);
895 /* If jpeg get output image attributes from the image processor. */
896 if (ps->currentCompression == SF_JPEG)
898 /* Enable parsed header flag. */
899 ipResultMask(ps->ip_handle, IP_PARSED_HEADER);
901 /* Wait for image processor to process header so we know the exact size of the image for sane_get_params. */
904 ret = get_ip_data(ps, NULL, 0, NULL);
906 if (ret & (IP_INPUT_ERROR | IP_FATAL_ERROR | IP_DONE))
908 stat = SANE_STATUS_IO_ERROR;
912 if (ret & IP_PARSED_HEADER)
914 ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits); /* get valid image traits */
915 ipResultMask(ps->ip_handle, 0); /* disable parsed header flag */
921 ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits); /* get valid image traits */
923 stat = SANE_STATUS_GOOD;
926 if (stat != SANE_STATUS_GOOD)
930 ipClose(ps->ip_handle);
933 bb_end_scan(ps, stat == SANE_STATUS_IO_ERROR ? 1: 0);
938 SANE_Status ledm_read(SANE_Handle handle, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length)
940 struct ledm_session *ps = (struct ledm_session *)handle;
941 int ret, stat=SANE_STATUS_IO_ERROR;
945 SendScanEvent(ps->uri, EVENT_SCAN_CANCEL);
946 return SANE_STATUS_CANCELLED;
949 ret = get_ip_data(ps, data, maxLength, length);
951 if(ret & (IP_INPUT_ERROR | IP_FATAL_ERROR))
958 stat = SANE_STATUS_EOF;
959 SendScanEvent(ps->uri, EVENT_END_SCAN_JOB);
961 else stat= SANE_STATUS_GOOD;
964 if (stat != SANE_STATUS_GOOD)
968 /* Note always call ipClose when SANE_STATUS_EOF, do not depend on sane_cancel because sane_cancel is only called at the end of a batch job. */
969 ipClose(ps->ip_handle);
975 DBG8("-sane_hpaio_read() output=%p bytes_read=%d maxLength=%d status=%d\n", data, *length, maxLength, stat);
980 void ledm_cancel(SANE_Handle handle)
982 struct ledm_session *ps = (struct ledm_session *)handle;
984 DBG8("sane_hpaio_cancel()\n");
986 ps -> user_cancel = 1;
987 /* Sane_cancel is always called at the end of the scan job.
988 Note that on a multiple page scan job sane_cancel is called only once */
992 ipClose(ps->ip_handle);
998 void ledm_close(SANE_Handle handle)
1000 struct ledm_session *ps = (struct ledm_session *)handle;
1002 if (ps == NULL || ps != session)
1004 BUG("invalid sane_close\n");
1011 hpmud_close_device(ps->dd);