1
/************************************************************************************\
3
marvell.c - HP SANE backend support for Marvell based multi-function peripherals
5
(c) 2008 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
Author: David Suffield, Yashwant Sahu
26
\************************************************************************************/
32
#include <sys/socket.h>
38
#include <sys/types.h>
52
#define DEBUG_DECLARE_ONLY
53
#include "sanei_debug.h"
55
static struct marvell_session *session = NULL; /* assume one sane_open per process */
57
static int bb_load(struct marvell_session *ps, const char *so)
63
/* Load hpmud manually with symbols exported. Otherwise the plugin will not find it. */
64
if ((ps->hpmud_handle = dlopen("libhpmud.so", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
66
BUG("unable to load restricted library: %s\n", dlerror());
70
/* Load math library manually with symbols exported (Ubuntu 8.04). Otherwise the plugin will not find it. */
71
if ((ps->math_handle = dlopen("libm.so", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
73
if ((ps->math_handle = dlopen("libm.so.6", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
75
BUG("unable to load restricted library: %s\n", dlerror());
80
if (hpmud_get_conf("[dirs]", "home", home, sizeof(home)) != HPMUD_R_OK)
82
snprintf(sz, sizeof(sz), "%s/scan/plugins/%s", home, so);
83
if ((ps->bb_handle = dlopen(sz, RTLD_NOW|RTLD_GLOBAL)) == NULL)
85
BUG("unable to load restricted library %s: %s\n", sz, dlerror());
86
SendScanEvent(ps->uri, EVENT_PLUGIN_FAIL);
90
if ((ps->bb_open = dlsym(ps->bb_handle, "bb_open")) == NULL)
92
BUG("unable to load restricted library %s: %s\n", sz, dlerror());
95
if ((ps->bb_close = dlsym(ps->bb_handle, "bb_close")) == NULL)
97
BUG("unable to load restricted library %s: %s\n", sz, dlerror());
100
if ((ps->bb_get_parameters = dlsym(ps->bb_handle, "bb_get_parameters")) == NULL)
102
BUG("unable to load restricted library %s: %s\n", sz, dlerror());
105
if ((ps->bb_is_paper_in_adf = dlsym(ps->bb_handle, "bb_is_paper_in_adf")) == NULL)
107
BUG("unable to load restricted library %s: %s\n", sz, dlerror());
110
if ((ps->bb_start_scan = dlsym(ps->bb_handle, "bb_start_scan")) == NULL)
112
BUG("unable to load restricted library %s: %s\n", sz, dlerror());
115
if ((ps->bb_end_scan = dlsym(ps->bb_handle, "bb_end_scan")) == NULL)
117
BUG("unable to load restricted library %s: %s\n", sz, dlerror());
120
if ((ps->bb_get_image_data = dlsym(ps->bb_handle, "bb_get_image_data")) == NULL)
122
BUG("unable to load restricted library %s: %s\n", sz, dlerror());
125
if ((ps->bb_end_page = dlsym(ps->bb_handle, "bb_end_page")) == NULL)
127
BUG("unable to load restricted library %s: %s\n", sz, dlerror());
137
static int bb_unload(struct marvell_session *ps)
141
dlclose(ps->bb_handle);
142
ps->bb_handle = NULL;
144
if (ps->hpmud_handle)
146
dlclose(ps->hpmud_handle);
147
ps->hpmud_handle = NULL;
151
dlclose(ps->math_handle);
152
ps->math_handle = NULL;
157
/* Get raw data (ie: uncompressed data) from image processor. */
158
static int get_ip_data(struct marvell_session *ps, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length)
160
int ip_ret=IP_INPUT_ERROR;
161
unsigned int outputAvail=maxLength, outputUsed=0, outputThisPos;
162
unsigned char *input, *output = data;
163
unsigned int inputAvail, inputUsed=0, inputNextPos;
167
BUG("invalid ipconvert state\n");
171
if (ps->bb_get_image_data(ps, outputAvail))
176
inputAvail = ps->cnt;
181
input = NULL; /* no more scan data, flush ipconvert pipeline */
185
/* Transform input data to output. Note, output buffer may consume more bytes than input buffer (ie: jpeg to raster). */
186
ip_ret = ipConvert(ps->ip_handle, inputAvail, input, &inputUsed, &inputNextPos, outputAvail, output, &outputUsed, &outputThisPos);
188
DBG6("input=%p inputAvail=%d inputUsed=%d inputNextPos=%d output=%p outputAvail=%d outputUsed=%d outputThisPos=%d ret=%x\n", input,
189
inputAvail, inputUsed, inputNextPos, output, outputAvail, outputUsed, outputThisPos, ip_ret);
192
*length = outputUsed;
194
/* For sane do not send output data simultaneously with IP_DONE. */
195
if (ip_ret & IP_DONE && outputUsed)
202
static int init_options(struct marvell_session *ps)
204
ps->option[MARVELL_OPTION_COUNT].name = "option-cnt";
205
ps->option[MARVELL_OPTION_COUNT].title = SANE_TITLE_NUM_OPTIONS;
206
ps->option[MARVELL_OPTION_COUNT].desc = SANE_DESC_NUM_OPTIONS;
207
ps->option[MARVELL_OPTION_COUNT].type = SANE_TYPE_INT;
208
ps->option[MARVELL_OPTION_COUNT].unit = SANE_UNIT_NONE;
209
ps->option[MARVELL_OPTION_COUNT].size = sizeof(SANE_Int);
210
ps->option[MARVELL_OPTION_COUNT].cap = SANE_CAP_SOFT_DETECT;
211
ps->option[MARVELL_OPTION_COUNT].constraint_type = SANE_CONSTRAINT_NONE;
213
ps->option[MARVELL_OPTION_GROUP_SCAN_MODE].name = "mode-group";
214
ps->option[MARVELL_OPTION_GROUP_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
215
ps->option[MARVELL_OPTION_GROUP_SCAN_MODE].type = SANE_TYPE_GROUP;
217
ps->option[MARVELL_OPTION_SCAN_MODE].name = SANE_NAME_SCAN_MODE;
218
ps->option[MARVELL_OPTION_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
219
ps->option[MARVELL_OPTION_SCAN_MODE].desc = SANE_DESC_SCAN_MODE;
220
ps->option[MARVELL_OPTION_SCAN_MODE].type = SANE_TYPE_STRING;
221
ps->option[MARVELL_OPTION_SCAN_MODE].unit = SANE_UNIT_NONE;
222
ps->option[MARVELL_OPTION_SCAN_MODE].size = MAX_STRING_SIZE;
223
ps->option[MARVELL_OPTION_SCAN_MODE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
224
ps->option[MARVELL_OPTION_SCAN_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
225
ps->option[MARVELL_OPTION_SCAN_MODE].constraint.string_list = ps->scan_mode_list;
227
ps->option[MARVELL_OPTION_INPUT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
228
ps->option[MARVELL_OPTION_INPUT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
229
ps->option[MARVELL_OPTION_INPUT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
230
ps->option[MARVELL_OPTION_INPUT_SOURCE].type = SANE_TYPE_STRING;
231
ps->option[MARVELL_OPTION_INPUT_SOURCE].unit = SANE_UNIT_NONE;
232
ps->option[MARVELL_OPTION_INPUT_SOURCE].size = MAX_STRING_SIZE;
233
ps->option[MARVELL_OPTION_INPUT_SOURCE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
234
ps->option[MARVELL_OPTION_INPUT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
235
ps->option[MARVELL_OPTION_INPUT_SOURCE].constraint.string_list = ps->input_source_list;
237
ps->option[MARVELL_OPTION_SCAN_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
238
ps->option[MARVELL_OPTION_SCAN_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
239
ps->option[MARVELL_OPTION_SCAN_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
240
ps->option[MARVELL_OPTION_SCAN_RESOLUTION].type = SANE_TYPE_INT;
241
ps->option[MARVELL_OPTION_SCAN_RESOLUTION].unit = SANE_UNIT_DPI;
242
ps->option[MARVELL_OPTION_SCAN_RESOLUTION].size = sizeof(SANE_Int);
243
ps->option[MARVELL_OPTION_SCAN_RESOLUTION].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
244
ps->option[MARVELL_OPTION_SCAN_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
245
ps->option[MARVELL_OPTION_SCAN_RESOLUTION].constraint.word_list = ps->resolution_list;
247
ps->option[MARVELL_OPTION_GROUP_ADVANCED].name = "advanced-group";
248
ps->option[MARVELL_OPTION_GROUP_ADVANCED].title = STR_TITLE_ADVANCED;
249
ps->option[MARVELL_OPTION_GROUP_ADVANCED].type = SANE_TYPE_GROUP;
250
ps->option[MARVELL_OPTION_GROUP_ADVANCED].cap = SANE_CAP_ADVANCED;
252
ps->option[MARVELL_OPTION_CONTRAST].name = SANE_NAME_CONTRAST;
253
ps->option[MARVELL_OPTION_CONTRAST].title = SANE_TITLE_CONTRAST;
254
ps->option[MARVELL_OPTION_CONTRAST].desc = SANE_DESC_CONTRAST;
255
ps->option[MARVELL_OPTION_CONTRAST].type = SANE_TYPE_INT;
256
ps->option[MARVELL_OPTION_CONTRAST].unit = SANE_UNIT_NONE;
257
ps->option[MARVELL_OPTION_CONTRAST].size = sizeof(SANE_Int);
258
ps->option[MARVELL_OPTION_CONTRAST].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
259
ps->option[MARVELL_OPTION_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
260
ps->option[MARVELL_OPTION_CONTRAST].constraint.range = &ps->contrast_range;
261
ps->contrast_range.min = MARVELL_CONTRAST_MIN;
262
ps->contrast_range.max = MARVELL_CONTRAST_MAX;
263
ps->contrast_range.quant = 0;
265
ps->option[MARVELL_OPTION_GROUP_GEOMETRY].name = "geometry-group";
266
ps->option[MARVELL_OPTION_GROUP_GEOMETRY].title = STR_TITLE_GEOMETRY;
267
ps->option[MARVELL_OPTION_GROUP_GEOMETRY].type = SANE_TYPE_GROUP;
268
ps->option[MARVELL_OPTION_GROUP_GEOMETRY].cap = SANE_CAP_ADVANCED;
270
ps->option[MARVELL_OPTION_TL_X].name = SANE_NAME_SCAN_TL_X;
271
ps->option[MARVELL_OPTION_TL_X].title = SANE_TITLE_SCAN_TL_X;
272
ps->option[MARVELL_OPTION_TL_X].desc = SANE_DESC_SCAN_TL_X;
273
ps->option[MARVELL_OPTION_TL_X].type = SANE_TYPE_FIXED;
274
ps->option[MARVELL_OPTION_TL_X].unit = SANE_UNIT_MM;
275
ps->option[MARVELL_OPTION_TL_X].size = sizeof(SANE_Int);
276
ps->option[MARVELL_OPTION_TL_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
277
ps->option[MARVELL_OPTION_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
278
ps->option[MARVELL_OPTION_TL_X].constraint.range = &ps->tlxRange;
279
ps->tlxRange.min = 0;
280
ps->tlxRange.quant = 0;
282
ps->option[MARVELL_OPTION_TL_Y].name = SANE_NAME_SCAN_TL_Y;
283
ps->option[MARVELL_OPTION_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
284
ps->option[MARVELL_OPTION_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
285
ps->option[MARVELL_OPTION_TL_Y].type = SANE_TYPE_FIXED;
286
ps->option[MARVELL_OPTION_TL_Y].unit = SANE_UNIT_MM;
287
ps->option[MARVELL_OPTION_TL_Y].size = sizeof(SANE_Int);
288
ps->option[MARVELL_OPTION_TL_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
289
ps->option[MARVELL_OPTION_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
290
ps->option[MARVELL_OPTION_TL_Y].constraint.range = &ps->tlyRange;
291
ps->tlyRange.min = 0;
292
ps->tlyRange.quant = 0;
294
ps->option[MARVELL_OPTION_BR_X].name = SANE_NAME_SCAN_BR_X;
295
ps->option[MARVELL_OPTION_BR_X].title = SANE_TITLE_SCAN_BR_X;
296
ps->option[MARVELL_OPTION_BR_X].desc = SANE_DESC_SCAN_BR_X;
297
ps->option[MARVELL_OPTION_BR_X].type = SANE_TYPE_FIXED;
298
ps->option[MARVELL_OPTION_BR_X].unit = SANE_UNIT_MM;
299
ps->option[MARVELL_OPTION_BR_X].size = sizeof(SANE_Int);
300
ps->option[MARVELL_OPTION_BR_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
301
ps->option[MARVELL_OPTION_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
302
ps->option[MARVELL_OPTION_BR_X].constraint.range = &ps->brxRange;
303
ps->brxRange.min = 0;
304
ps->brxRange.quant = 0;
306
ps->option[MARVELL_OPTION_BR_Y].name = SANE_NAME_SCAN_BR_Y;
307
ps->option[MARVELL_OPTION_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
308
ps->option[MARVELL_OPTION_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
309
ps->option[MARVELL_OPTION_BR_Y].type = SANE_TYPE_FIXED;
310
ps->option[MARVELL_OPTION_BR_Y].unit = SANE_UNIT_MM;
311
ps->option[MARVELL_OPTION_BR_Y].size = sizeof(SANE_Int);
312
ps->option[MARVELL_OPTION_BR_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
313
ps->option[MARVELL_OPTION_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
314
ps->option[MARVELL_OPTION_BR_Y].constraint.range = &ps->bryRange;
315
ps->bryRange.min = 0;
316
ps->bryRange.quant = 0;
321
/* Verify current x/y extents and set effective extents. */
322
static int set_extents(struct marvell_session *ps)
326
if ((ps->currentBrx > ps->currentTlx) && (ps->currentBrx - ps->currentTlx >= ps->min_width) && (ps->currentBrx - ps->currentTlx <= ps->tlxRange.max))
328
ps->effectiveTlx = ps->currentTlx;
329
ps->effectiveBrx = ps->currentBrx;
333
ps->effectiveTlx = 0; /* current setting is not valid, zero it */
334
ps->effectiveBrx = 0;
337
if ((ps->currentBry > ps->currentTly) && (ps->currentBry - ps->currentTly > ps->min_height) && (ps->currentBry - ps->currentTly <= ps->tlyRange.max))
339
ps->effectiveTly = ps->currentTly;
340
ps->effectiveBry = ps->currentBry;
344
ps->effectiveTly = 0; /* current setting is not valid, zero it */
345
ps->effectiveBry = 0;
351
static struct marvell_session *create_session()
353
struct marvell_session *ps;
355
if ((ps = malloc(sizeof(struct marvell_session))) == NULL)
357
BUG("malloc failed: %m\n");
360
memset(ps, 0, sizeof(struct marvell_session));
372
SANE_Status marvell_open(SANE_String_Const device, SANE_Handle *handle)
374
struct hpmud_model_attributes ma;
375
int stat = SANE_STATUS_IO_ERROR;
378
DBG8("sane_hpaio_open(%s)\n", device);
382
BUG("session in use\n");
383
return SANE_STATUS_DEVICE_BUSY;
386
if ((session = create_session()) == NULL)
387
return SANE_STATUS_NO_MEM;
389
/* Set session to specified device. */
390
snprintf(session->uri, sizeof(session->uri)-1, "hp:%s", device); /* prepend "hp:" */
392
/* Get actual model attributes from models.dat. */
393
hpmud_query_model(session->uri, &ma);
394
session->scan_type = ma.scantype;
395
session->scansrc = ma.scansrc;
399
case HPMUD_SCANTYPE_MARVELL:
400
session->version = MARVELL_1;
402
case HPMUD_SCANTYPE_MARVELL2:
403
session->version = MARVELL_2;
406
session->version = MARVELL_1;
409
if (hpmud_open_device(session->uri, ma.mfp_mode, &session->dd) != HPMUD_R_OK)
411
BUG("unable to open device %s\n", session->uri);
416
return SANE_STATUS_IO_ERROR;
419
if (hpmud_open_channel(session->dd, HPMUD_S_MARVELL_SCAN_CHANNEL, &session->cd) != HPMUD_R_OK)
421
BUG("unable to open %s channel %s\n", HPMUD_S_MARVELL_SCAN_CHANNEL, session->uri);
422
stat = SANE_STATUS_DEVICE_BUSY;
426
if (bb_load(session, "bb_marvell.so"))
428
stat = SANE_STATUS_IO_ERROR;
432
/* Init sane option descriptors. */
433
init_options(session);
435
if (session->bb_open(session))
437
stat = SANE_STATUS_IO_ERROR;
441
/* Set supported Scan Modes and set sane option. */
443
session->scan_mode_list[i] = SANE_VALUE_SCAN_MODE_LINEART;
444
session->scan_mode_map[i++] = CE_BLACK_AND_WHITE1;
445
session->scan_mode_list[i] = SANE_VALUE_SCAN_MODE_GRAY;
446
session->scan_mode_map[i++] = CE_GRAY8;
447
session->scan_mode_list[i] = SANE_VALUE_SCAN_MODE_COLOR;
448
session->scan_mode_map[i++] = CE_RGB24;
449
marvell_control_option(session, MARVELL_OPTION_SCAN_MODE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
452
/* Determine scan input source. */
454
/* Some of the marvell devices supports both flatbed and ADF, No command to get the src types supported */
455
/* Getting from the model file */
456
if ( session->scansrc & HPMUD_SCANSRC_ADF)
458
session->input_source_list[i] = STR_ADF_MODE_ADF;
459
session->input_source_map[i++] = IS_ADF;
460
DBG8("scan src HPMUD_SCANSRC_ADF \n");
462
if ( session->scansrc & HPMUD_SCANSRC_FLATBED)
464
session->input_source_list[i] = STR_ADF_MODE_FLATBED;
465
session->input_source_map[i++] = IS_PLATEN;
466
DBG8("scan src HPMUD_SCANSRC_FLATBED \n");
468
/* Values if un specified in the, value is 0, get ADF state from the printer */
469
if (session->scansrc == HPMUD_SCANSRC_NA)
471
if (session->bb_is_paper_in_adf(session) == 2)
473
session->input_source_list[i] = STR_ADF_MODE_FLATBED;
474
session->input_source_map[i++] = IS_PLATEN;
475
DBG8("scan src b_is_paper_in_adf value 2 \n");
479
session->input_source_list[i] = STR_ADF_MODE_ADF;
480
session->input_source_map[i++] = IS_ADF;
481
DBG8("scan src b_is_paper_in_adf value not 2 \n");
485
marvell_control_option(session, MARVELL_OPTION_INPUT_SOURCE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
487
/* Set supported resolutions. */
489
session->resolution_list[i++] = 75;
490
session->resolution_list[i++] = 100;
491
session->resolution_list[i++] = 150;
492
session->resolution_list[i++] = 200;
493
session->resolution_list[i++] = 300;
494
session->resolution_list[i++] = 600;
495
session->resolution_list[i++] = 1200;
496
session->resolution_list[0] = i-1; /* length of word_list */
497
marvell_control_option(session, MARVELL_OPTION_SCAN_RESOLUTION, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
499
/* Set supported contrast. */
500
marvell_control_option(session, MARVELL_OPTION_CONTRAST, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
502
/* Set x,y extents. See bb_open(). */
503
marvell_control_option(session, MARVELL_OPTION_TL_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
504
marvell_control_option(session, MARVELL_OPTION_TL_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
505
marvell_control_option(session, MARVELL_OPTION_BR_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
506
marvell_control_option(session, MARVELL_OPTION_BR_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
508
*handle = (SANE_Handle *)session;
510
stat = SANE_STATUS_GOOD;
514
if (stat != SANE_STATUS_GOOD)
520
hpmud_close_channel(session->dd, session->cd);
522
hpmud_close_device(session->dd);
531
void marvell_close(SANE_Handle handle)
533
struct marvell_session *ps = (struct marvell_session *)handle;
535
DBG8("sane_hpaio_close()\n");
537
if (ps == NULL || ps != session)
539
BUG("invalid sane_close\n");
549
hpmud_close_channel(ps->dd, ps->cd);
550
hpmud_close_device(ps->dd);
557
const SANE_Option_Descriptor *marvell_get_option_descriptor(SANE_Handle handle, SANE_Int option)
559
struct marvell_session *ps = (struct marvell_session *)handle;
561
DBG8("sane_hpaio_get_option_descriptor(option=%s)\n", ps->option[option].name);
563
if (option < 0 || option >= MARVELL_OPTION_MAX)
566
return &ps->option[option];
569
SANE_Status marvell_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int *set_result)
571
struct marvell_session *ps = (struct marvell_session *)handle;
572
SANE_Int *int_value = value, mset_result=0;
573
int i, stat=SANE_STATUS_INVAL;
578
case MARVELL_OPTION_COUNT:
579
if (action == SANE_ACTION_GET_VALUE)
581
*int_value = MARVELL_OPTION_MAX;
582
stat = SANE_STATUS_GOOD;
585
case MARVELL_OPTION_SCAN_MODE:
586
if (action == SANE_ACTION_GET_VALUE)
588
for (i=0; ps->scan_mode_list[i]; i++)
590
if (ps->current_scan_mode == ps->scan_mode_map[i])
592
strcpy(value, ps->scan_mode_list[i]);
593
stat = SANE_STATUS_GOOD;
598
else if (action == SANE_ACTION_SET_VALUE)
600
for (i=0; ps->scan_mode_list[i]; i++)
602
if (strcasecmp(ps->scan_mode_list[i], value) == 0)
604
ps->current_scan_mode = ps->scan_mode_map[i];
605
mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
606
stat = SANE_STATUS_GOOD;
613
ps->current_scan_mode = ps->scan_mode_map[0];
614
stat = SANE_STATUS_GOOD;
617
case MARVELL_OPTION_INPUT_SOURCE:
618
if (action == SANE_ACTION_GET_VALUE)
620
for (i=0; ps->input_source_list[i]; i++)
622
if (ps->current_input_source == ps->input_source_map[i])
624
strcpy(value, ps->input_source_list[i]);
625
stat = SANE_STATUS_GOOD;
630
else if (action == SANE_ACTION_SET_VALUE)
632
for (i=0; ps->input_source_list[i]; i++)
634
if (strcasecmp(ps->input_source_list[i], value) == 0)
636
ps->current_input_source = ps->input_source_map[i];
637
stat = SANE_STATUS_GOOD;
644
ps->current_input_source = ps->input_source_map[0];
645
stat = SANE_STATUS_GOOD;
648
case MARVELL_OPTION_SCAN_RESOLUTION:
649
if (action == SANE_ACTION_GET_VALUE)
651
*int_value = ps->current_resolution;
652
stat = SANE_STATUS_GOOD;
654
else if (action == SANE_ACTION_SET_VALUE)
656
for (i=1; i <= ps->resolution_list[0]; i++)
658
if (ps->resolution_list[i] == *int_value)
660
ps->current_resolution = *int_value;
661
mset_result |= SANE_INFO_RELOAD_PARAMS;
662
stat = SANE_STATUS_GOOD;
669
ps->current_resolution = 75;
670
stat = SANE_STATUS_GOOD;
673
case MARVELL_OPTION_CONTRAST:
674
if (action == SANE_ACTION_GET_VALUE)
676
*int_value = ps->current_contrast;
677
stat = SANE_STATUS_GOOD;
679
else if (action == SANE_ACTION_SET_VALUE)
681
if (*int_value >= MARVELL_CONTRAST_MIN && *int_value <= MARVELL_CONTRAST_MAX)
683
ps->current_contrast = *int_value;
684
stat = SANE_STATUS_GOOD;
690
ps->current_contrast = MARVELL_CONTRAST_DEFAULT;
691
stat = SANE_STATUS_GOOD;
694
case MARVELL_OPTION_TL_X:
695
if (action == SANE_ACTION_GET_VALUE)
697
*int_value = ps->currentTlx;
698
stat = SANE_STATUS_GOOD;
700
else if (action == SANE_ACTION_SET_VALUE)
702
if (*int_value >= ps->tlxRange.min && *int_value <= ps->tlxRange.max)
704
ps->currentTlx = *int_value;
705
mset_result |= SANE_INFO_RELOAD_PARAMS;
706
stat = SANE_STATUS_GOOD;
712
ps->currentTlx = ps->tlxRange.min;
713
stat = SANE_STATUS_GOOD;
716
case MARVELL_OPTION_TL_Y:
717
if (action == SANE_ACTION_GET_VALUE)
719
*int_value = ps->currentTly;
720
stat = SANE_STATUS_GOOD;
722
else if (action == SANE_ACTION_SET_VALUE)
724
if (*int_value >= ps->tlyRange.min && *int_value <= ps->tlyRange.max)
727
ps->currentTly = *int_value;
728
mset_result |= SANE_INFO_RELOAD_PARAMS;
729
stat = SANE_STATUS_GOOD;
735
ps->currentTly = ps->tlyRange.min;
736
stat = SANE_STATUS_GOOD;
739
case MARVELL_OPTION_BR_X:
740
if (action == SANE_ACTION_GET_VALUE)
742
*int_value = ps->currentBrx;
743
stat = SANE_STATUS_GOOD;
745
else if (action == SANE_ACTION_SET_VALUE)
747
if (*int_value >= ps->brxRange.min && *int_value <= ps->brxRange.max)
749
ps->currentBrx = *int_value;
750
mset_result |= SANE_INFO_RELOAD_PARAMS;
751
stat = SANE_STATUS_GOOD;
757
ps->currentBrx = ps->brxRange.max;
758
stat = SANE_STATUS_GOOD;
761
case MARVELL_OPTION_BR_Y:
762
if (action == SANE_ACTION_GET_VALUE)
764
*int_value = ps->currentBry;
765
stat = SANE_STATUS_GOOD;
767
else if (action == SANE_ACTION_SET_VALUE)
769
if (*int_value >= ps->bryRange.min && *int_value <= ps->bryRange.max)
771
ps->currentBry = *int_value;
772
mset_result |= SANE_INFO_RELOAD_PARAMS;
773
stat = SANE_STATUS_GOOD;
776
BUG("value=%d brymin=%d brymax=%d\n", *int_value, ps->bryRange.min, ps->bryRange.max);
780
ps->currentBry = ps->bryRange.max;
781
stat = SANE_STATUS_GOOD;
789
*set_result = mset_result;
791
if (stat != SANE_STATUS_GOOD)
793
BUG("control_option failed: option=%s action=%s\n", ps->option[option].name,
794
action==SANE_ACTION_GET_VALUE ? "get" : action==SANE_ACTION_SET_VALUE ? "set" : "auto");
797
DBG8("sane_hpaio_control_option (option=%s action=%s value=%s)\n", ps->option[option].name,
798
action==SANE_ACTION_GET_VALUE ? "get" : action==SANE_ACTION_SET_VALUE ? "set" : "auto",
799
value ? ps->option[option].type == SANE_TYPE_STRING ? (char *)value : psnprintf(sz, sizeof(sz), "%d", *(int *)value) : "na");
804
SANE_Status marvell_get_parameters(SANE_Handle handle, SANE_Parameters *params)
806
struct marvell_session *ps = (struct marvell_session *)handle;
810
ps->bb_get_parameters(ps, params, ps->ip_handle ? 1 : 0);
812
DBG8("sane_hpaio_get_parameters(): format=%d, last_frame=%d, lines=%d, depth=%d, pixels_per_line=%d, bytes_per_line=%d\n",
813
params->format, params->last_frame, params->lines, params->depth, params->pixels_per_line, params->bytes_per_line);
815
return SANE_STATUS_GOOD;
818
SANE_Status marvell_start(SANE_Handle handle)
820
struct marvell_session *ps = (struct marvell_session *)handle;
822
IP_IMAGE_TRAITS traits;
823
IP_XFORM_SPEC xforms[IP_MAX_XFORMS], *pXform=xforms;
825
// int tmo=EXCEPTION_TIMEOUT*2;
827
DBG8("sane_hpaio_start()\n");
828
ps->is_user_cancel = 0;
832
BUG("invalid extents: tlx=%d brx=%d tly=%d bry=%d minwidth=%d minheight%d maxwidth=%d maxheight=%d\n",
833
ps->currentTlx, ps->currentTly, ps->currentBrx, ps->currentBry, ps->min_width, ps->min_height, ps->tlxRange.max, ps->tlyRange.max);
834
stat = SANE_STATUS_INVAL;
838
/* If input is ADF and ADF is empty, return SANE_STATUS_NO_DOCS. */
839
if (ps->current_input_source == IS_ADF)
841
ret = ps->bb_is_paper_in_adf(ps); /* 0 = no paper in adf, 1 = paper in adf, 2 = no adf, -1 = error */
844
stat = SANE_STATUS_NO_DOCS; /* done scanning */
845
SendScanEvent(ps->uri, EVENT_SCAN_ADF_NO_DOCS);
850
stat = SANE_STATUS_IO_ERROR;
854
/* Start scan and get actual image traits. */
855
if (ps->bb_start_scan(ps))
857
stat = SANE_STATUS_IO_ERROR;
861
SendScanEvent(ps->uri, EVENT_START_SCAN_JOB);
862
memset(xforms, 0, sizeof(xforms));
864
/* Setup image-processing pipeline for xform. */
865
if (ps->current_scan_mode == CE_BLACK_AND_WHITE1)
867
pXform->aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword = 127;
868
ADD_XFORM(X_GRAY_2_BI);
871
/* Setup x/y cropping for xform. (Actually we let cm1017 do it's own cropping) */
872
pXform->aXformInfo[IP_CROP_LEFT].dword = 0;
873
pXform->aXformInfo[IP_CROP_RIGHT].dword = 0;
874
pXform->aXformInfo[IP_CROP_TOP].dword = 0;
875
pXform->aXformInfo[IP_CROP_MAXOUTROWS].dword = 0;
878
/* Setup x/y padding for xform. (Actually we let cm1017 do it's own padding) */
879
pXform->aXformInfo[IP_PAD_LEFT].dword = 0; /* # of pixels to add to left side */
880
pXform->aXformInfo[IP_PAD_RIGHT].dword = 0; /* # of pixels to add to right side */
881
pXform->aXformInfo[IP_PAD_TOP].dword = 0; /* # of rows to add to top */
882
pXform->aXformInfo[IP_PAD_BOTTOM].dword = 0; /* # of rows to add to bottom */
883
pXform->aXformInfo[IP_PAD_VALUE].dword = ps->current_scan_mode == CE_BLACK_AND_WHITE1 ? 0 : -1; /* lineart white = 0, rgb white = -1 */
884
pXform->aXformInfo[IP_PAD_MIN_HEIGHT].dword = 0;
887
/* Open image processor. */
888
if ((ret = ipOpen(pXform-xforms, xforms, 0, &ps->ip_handle)) != IP_DONE)
890
BUG("unable open image processor: err=%d\n", ret);
891
stat = SANE_STATUS_INVAL;
895
/* Get actual input image attributes. See bb_start_scan(). */
896
ps->bb_get_parameters(ps, &pp, 1);
898
/* Now set known input image attributes. */
899
traits.iPixelsPerRow = pp.pixels_per_line;
900
switch(ps->current_scan_mode)
902
case CE_BLACK_AND_WHITE1: /* lineart */
904
traits.iBitsPerPixel = 8; /* grayscale */
908
traits.iBitsPerPixel = 24; /* color */
911
traits.lHorizDPI = ps->current_resolution << 16;
912
traits.lVertDPI = ps->current_resolution << 16;
913
traits.lNumRows = pp.lines;
914
traits.iNumPages = 1;
916
traits.iComponentsPerPixel = ((traits.iBitsPerPixel % 3) ? 1 : 3);
917
ipSetDefaultInputTraits(ps->ip_handle, &traits);
919
/* Get output image attributes from the image processor. */
920
ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits); /* get valid image traits */
922
stat = SANE_STATUS_GOOD;
925
if (stat != SANE_STATUS_GOOD)
929
ipClose(ps->ip_handle);
932
ps->bb_end_scan(ps, stat == SANE_STATUS_IO_ERROR ? 1: 0);
938
SANE_Status marvell_read(SANE_Handle handle, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length)
940
struct marvell_session *ps = (struct marvell_session *)handle;
941
int ret, stat=SANE_STATUS_IO_ERROR;
942
// int tmo=EXCEPTION_TIMEOUT;
944
DBG8("sane_hpaio_read() handle=%p data=%p maxLength=%d\n", (void *)handle, data, maxLength);
946
ret = get_ip_data(ps, data, maxLength, length);
948
if(ret & (IP_INPUT_ERROR | IP_FATAL_ERROR))
950
BUG("ipConvert error=%x\n", ret);
956
stat = SANE_STATUS_EOF;
957
SendScanEvent(ps->uri, EVENT_END_SCAN_JOB);
960
stat = SANE_STATUS_GOOD;
963
if (stat != SANE_STATUS_GOOD)
967
/* 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. */
968
ipClose(ps->ip_handle);
971
//If user has cancelled scan from device
972
if (ps->is_user_cancel)
974
//Don't do anything. sane_hpaio_cancel() will be invoked automatically
975
SendScanEvent(ps->uri, EVENT_SCAN_CANCEL);
976
return SANE_STATUS_CANCELLED;
981
ps->bb_end_page(ps, stat == SANE_STATUS_IO_ERROR ? 1: 0);
985
DBG8("-sane_hpaio_read() output=%p bytes_read=%d maxLength=%d status=%d\n", data, *length, maxLength, stat);
990
void marvell_cancel(SANE_Handle handle)
992
struct marvell_session *ps = (struct marvell_session *)handle;
994
DBG8("sane_hpaio_cancel()\n");
997
* Sane_cancel is always called at the end of the scan job. Note that on a multiple page scan job
998
* sane_cancel is called only once.
1000
ps->is_user_cancel = 1 ;
1004
ipClose(ps->ip_handle);
1007
ps->bb_end_scan(ps, 0);