Tizen 2.1 base
[platform/upstream/hplip.git] / scan / sane / marvell.c
1 /************************************************************************************\
2
3   marvell.c - HP SANE backend support for Marvell based multi-function peripherals
4
5   (c) 2008 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   Author: David Suffield, Yashwant Sahu
25
26 \************************************************************************************/
27
28 #ifndef _GNU_SOURCE
29 #define _GNU_SOURCE
30 #endif
31
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include <stdarg.h>
35 #include <syslog.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <math.h>
42 #include <dlfcn.h>
43 #include "sane.h"
44 #include "saneopts.h"
45 #include "hpmud.h"
46 #include "hpip.h"
47 #include "common.h"
48 #include "marvell.h"
49 #include "marvelli.h"
50 #include "io.h"
51
52 #define DEBUG_DECLARE_ONLY
53 #include "sanei_debug.h"
54
55 static struct marvell_session *session = NULL;   /* assume one sane_open per process */
56
57 static int bb_load(struct marvell_session *ps, const char *so)
58 {
59    char home[128];
60    char sz[255]; 
61    int stat=1;
62
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)
65    {
66       BUG("unable to load restricted library: %s\n", dlerror());
67       goto bugout;
68    } 
69
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)
72    {
73       if ((ps->math_handle = dlopen("libm.so.6", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
74       {
75          BUG("unable to load restricted library: %s\n", dlerror());
76          goto bugout;
77       }
78    } 
79
80    if (hpmud_get_conf("[dirs]", "home", home, sizeof(home)) != HPMUD_R_OK)
81       goto bugout;
82    snprintf(sz, sizeof(sz), "%s/scan/plugins/%s", home, so);
83    if ((ps->bb_handle = dlopen(sz, RTLD_NOW|RTLD_GLOBAL)) == NULL)
84    {
85       BUG("unable to load restricted library %s: %s\n", sz, dlerror());
86       SendScanEvent(ps->uri, EVENT_PLUGIN_FAIL);
87       goto bugout;
88    } 
89    
90    if ((ps->bb_open = dlsym(ps->bb_handle, "bb_open")) == NULL)
91    {
92       BUG("unable to load restricted library %s: %s\n", sz, dlerror());
93       goto bugout;
94    } 
95    if ((ps->bb_close = dlsym(ps->bb_handle, "bb_close")) == NULL)
96    {
97       BUG("unable to load restricted library %s: %s\n", sz, dlerror());
98       goto bugout;
99    } 
100    if ((ps->bb_get_parameters = dlsym(ps->bb_handle, "bb_get_parameters")) == NULL)
101    {
102       BUG("unable to load restricted library %s: %s\n", sz, dlerror());
103       goto bugout;
104    } 
105    if ((ps->bb_is_paper_in_adf = dlsym(ps->bb_handle, "bb_is_paper_in_adf")) == NULL)
106    {
107       BUG("unable to load restricted library %s: %s\n", sz, dlerror());
108       goto bugout;
109    } 
110    if ((ps->bb_start_scan = dlsym(ps->bb_handle, "bb_start_scan")) == NULL)
111    {
112       BUG("unable to load restricted library %s: %s\n", sz, dlerror());
113       goto bugout;
114    } 
115    if ((ps->bb_end_scan = dlsym(ps->bb_handle, "bb_end_scan")) == NULL)
116    {
117       BUG("unable to load restricted library %s: %s\n", sz, dlerror());
118       goto bugout;
119    } 
120    if ((ps->bb_get_image_data = dlsym(ps->bb_handle, "bb_get_image_data")) == NULL)
121    {
122       BUG("unable to load restricted library %s: %s\n", sz, dlerror());
123       goto bugout;
124    } 
125    if ((ps->bb_end_page = dlsym(ps->bb_handle, "bb_end_page")) == NULL)
126    {
127       BUG("unable to load restricted library %s: %s\n", sz, dlerror());
128       goto bugout;
129    } 
130
131    stat=0;
132
133 bugout:
134    return stat;
135 }
136
137 static int bb_unload(struct marvell_session *ps)
138 {
139    if (ps->bb_handle)
140    {   
141       dlclose(ps->bb_handle);
142       ps->bb_handle = NULL;
143    }  
144    if (ps->hpmud_handle)
145    {   
146       dlclose(ps->hpmud_handle);
147       ps->hpmud_handle = NULL;
148    }  
149    if (ps->math_handle)
150    {   
151       dlclose(ps->math_handle);
152       ps->math_handle = NULL;
153    }  
154    return 0;
155 }
156
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)
159 {
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;
164
165    if (!ps->ip_handle)
166    {
167       BUG("invalid ipconvert state\n");
168       goto bugout;
169    }
170    
171    if (ps->bb_get_image_data(ps, outputAvail))
172       goto bugout;
173
174    if (ps->cnt > 0)
175    {
176       inputAvail = ps->cnt;
177       input = ps->buf;
178    }
179    else
180    {
181       input = NULL;   /* no more scan data, flush ipconvert pipeline */
182       inputAvail = 0;
183    }
184
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);
187
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);
190
191    if (data)
192       *length = outputUsed;
193
194    /* For sane do not send output data simultaneously with IP_DONE. */
195    if (ip_ret & IP_DONE && outputUsed)
196       ip_ret &= ~IP_DONE;                               
197
198 bugout:
199    return ip_ret;
200 }
201
202 static int init_options(struct marvell_session *ps)
203 {
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;
212
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;
216
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;
226
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;
236
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;
246
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;
251
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;
264
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;
269
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;
281
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;
293
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;
305
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;
317
318    return 0;
319 }
320
321 /* Verify current x/y extents and set effective extents. */ 
322 static int set_extents(struct marvell_session *ps)
323 {
324    int stat = 0;
325
326    if ((ps->currentBrx > ps->currentTlx) && (ps->currentBrx - ps->currentTlx >= ps->min_width) && (ps->currentBrx - ps->currentTlx <= ps->tlxRange.max))
327    {
328      ps->effectiveTlx = ps->currentTlx;
329      ps->effectiveBrx = ps->currentBrx;
330    }
331    else
332    {
333      ps->effectiveTlx = 0;  /* current setting is not valid, zero it */
334      ps->effectiveBrx = 0;
335      stat = 1;
336    }
337    if ((ps->currentBry > ps->currentTly) && (ps->currentBry - ps->currentTly > ps->min_height) && (ps->currentBry - ps->currentTly <= ps->tlyRange.max))
338    {
339      ps->effectiveTly = ps->currentTly;
340      ps->effectiveBry = ps->currentBry;
341    }
342    else
343    {
344      ps->effectiveTly = 0;  /* current setting is not valid, zero it */
345      ps->effectiveBry = 0;
346      stat = 1;
347    }
348    return stat;
349 }
350
351 static struct marvell_session *create_session()
352 {
353    struct marvell_session *ps;
354
355    if ((ps = malloc(sizeof(struct marvell_session))) == NULL)
356    {
357       BUG("malloc failed: %m\n");
358       return NULL;
359    }
360    memset(ps, 0, sizeof(struct marvell_session));
361    ps->tag = "MARVELL";
362    ps->dd = -1;
363    ps->cd = -1;
364
365    return ps;
366 }
367
368 /*
369  * SANE APIs.
370  */
371
372 SANE_Status marvell_open(SANE_String_Const device, SANE_Handle *handle)
373 {
374    struct hpmud_model_attributes ma;
375    int stat = SANE_STATUS_IO_ERROR;
376    int i;
377
378    DBG8("sane_hpaio_open(%s)\n", device);
379
380    if (session)
381    {
382       BUG("session in use\n");
383       return SANE_STATUS_DEVICE_BUSY;
384    }
385       
386    if ((session = create_session()) == NULL)
387       return SANE_STATUS_NO_MEM;
388     
389    /* Set session to specified device. */
390    snprintf(session->uri, sizeof(session->uri)-1, "hp:%s", device);   /* prepend "hp:" */
391
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;
396    
397    switch (ma.scantype)
398    {
399       case HPMUD_SCANTYPE_MARVELL:
400          session->version = MARVELL_1;
401                  break;
402           case HPMUD_SCANTYPE_MARVELL2:
403          session->version = MARVELL_2;
404                  break;
405           default:
406          session->version = MARVELL_1;
407    };
408
409    if (hpmud_open_device(session->uri, ma.mfp_mode, &session->dd) != HPMUD_R_OK)
410    {
411       BUG("unable to open device %s\n", session->uri);
412       goto bugout;
413
414       free(session);
415       session = NULL;
416       return SANE_STATUS_IO_ERROR;
417    }
418
419    if (hpmud_open_channel(session->dd, HPMUD_S_MARVELL_SCAN_CHANNEL, &session->cd) != HPMUD_R_OK)
420    {
421       BUG("unable to open %s channel %s\n", HPMUD_S_MARVELL_SCAN_CHANNEL, session->uri);
422       stat = SANE_STATUS_DEVICE_BUSY;
423       goto bugout;
424    }
425
426    if (bb_load(session, "bb_marvell.so"))
427    {
428       stat = SANE_STATUS_IO_ERROR;
429       goto bugout;
430    }
431
432    /* Init sane option descriptors. */
433    init_options(session);  
434
435    if (session->bb_open(session))
436    {
437       stat = SANE_STATUS_IO_ERROR;
438       goto bugout;
439    }
440
441    /* Set supported Scan Modes and set sane option. */
442    i=0;
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 */
450
451
452    /* Determine scan input source. */
453    i=0;
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)
457    {
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"); 
461    }
462    if ( session->scansrc & HPMUD_SCANSRC_FLATBED)
463    {
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");
467     }
468     /* Values if un specified in the, value is 0,  get ADF state from the printer */   
469    if (session->scansrc == HPMUD_SCANSRC_NA)
470    {
471      if (session->bb_is_paper_in_adf(session) == 2) 
472      {
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");
476      }
477      else
478      {
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");
482      }
483     }
484
485    marvell_control_option(session, MARVELL_OPTION_INPUT_SOURCE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */  
486
487    /* Set supported resolutions. */
488    i=1;
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 */
498
499    /* Set supported contrast. */
500    marvell_control_option(session, MARVELL_OPTION_CONTRAST, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
501
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 */
507
508    *handle = (SANE_Handle *)session;
509
510    stat = SANE_STATUS_GOOD;
511
512 bugout:
513
514    if (stat != SANE_STATUS_GOOD)
515    {
516       if (session)
517       {
518          bb_unload(session);
519          if (session->cd > 0)
520             hpmud_close_channel(session->dd, session->cd);
521          if (session->dd > 0)
522             hpmud_close_device(session->dd);
523          free(session);
524          session = NULL;
525       }
526    }
527
528    return stat;
529 }
530
531 void marvell_close(SANE_Handle handle)
532 {
533    struct marvell_session *ps = (struct marvell_session *)handle;
534
535    DBG8("sane_hpaio_close()\n"); 
536
537    if (ps == NULL || ps != session)
538    {
539       BUG("invalid sane_close\n");
540       return;
541    }
542
543    ps->bb_close(ps);
544    bb_unload(ps);
545
546    if (ps->dd > 0)
547    {
548       if (ps->cd > 0)
549          hpmud_close_channel(ps->dd, ps->cd);
550       hpmud_close_device(ps->dd);
551    }
552     
553    free(ps);
554    session = NULL;
555 }
556
557 const SANE_Option_Descriptor *marvell_get_option_descriptor(SANE_Handle handle, SANE_Int option)
558 {
559    struct marvell_session *ps = (struct marvell_session *)handle;
560
561    DBG8("sane_hpaio_get_option_descriptor(option=%s)\n", ps->option[option].name);
562
563    if (option < 0 || option >= MARVELL_OPTION_MAX)
564       return NULL;
565
566    return &ps->option[option];
567 }
568
569 SANE_Status marvell_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int *set_result)
570 {
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;
574    char sz[64];
575
576    switch(option)
577    {
578       case MARVELL_OPTION_COUNT:
579          if (action == SANE_ACTION_GET_VALUE)
580          {
581             *int_value = MARVELL_OPTION_MAX;
582             stat = SANE_STATUS_GOOD;
583          }
584          break;
585       case MARVELL_OPTION_SCAN_MODE:
586          if (action == SANE_ACTION_GET_VALUE)
587          {
588             for (i=0; ps->scan_mode_list[i]; i++)
589             {
590                if (ps->current_scan_mode == ps->scan_mode_map[i])
591                {
592                   strcpy(value, ps->scan_mode_list[i]);
593                   stat = SANE_STATUS_GOOD;
594                   break;
595                }
596             }
597          }
598          else if (action == SANE_ACTION_SET_VALUE)
599          {
600             for (i=0; ps->scan_mode_list[i]; i++)
601             {
602                if (strcasecmp(ps->scan_mode_list[i], value) == 0)
603                {
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;
607                   break;
608                }
609             }
610          }
611          else
612          {  /* Set default. */
613             ps->current_scan_mode = ps->scan_mode_map[0];
614             stat = SANE_STATUS_GOOD;
615          }
616          break;
617       case MARVELL_OPTION_INPUT_SOURCE:
618          if (action == SANE_ACTION_GET_VALUE)
619          {
620             for (i=0; ps->input_source_list[i]; i++)
621             {
622                if (ps->current_input_source == ps->input_source_map[i])
623                {
624                   strcpy(value, ps->input_source_list[i]);
625                   stat = SANE_STATUS_GOOD;
626                   break;
627                }
628             }
629          }
630          else if (action == SANE_ACTION_SET_VALUE)
631          {
632             for (i=0; ps->input_source_list[i]; i++)
633             {
634                if (strcasecmp(ps->input_source_list[i], value) == 0)
635                {
636                   ps->current_input_source = ps->input_source_map[i];
637                   stat = SANE_STATUS_GOOD;
638                   break;
639                }
640             }
641          }
642          else
643          {  /* Set default. */
644             ps->current_input_source = ps->input_source_map[0];
645             stat = SANE_STATUS_GOOD;
646          }
647          break;
648       case MARVELL_OPTION_SCAN_RESOLUTION:
649          if (action == SANE_ACTION_GET_VALUE)
650          {
651             *int_value = ps->current_resolution;
652             stat = SANE_STATUS_GOOD;
653          }
654          else if (action == SANE_ACTION_SET_VALUE)
655          {
656             for (i=1; i <= ps->resolution_list[0]; i++)
657             {
658                if (ps->resolution_list[i] == *int_value)
659                {
660                   ps->current_resolution = *int_value;
661                   mset_result |= SANE_INFO_RELOAD_PARAMS;
662                   stat = SANE_STATUS_GOOD;
663                   break;
664                }
665             }
666          }
667          else
668          {  /* Set default. */
669             ps->current_resolution = 75;
670             stat = SANE_STATUS_GOOD;
671          }
672          break;
673       case MARVELL_OPTION_CONTRAST:
674          if (action == SANE_ACTION_GET_VALUE)
675          {
676             *int_value = ps->current_contrast;
677             stat = SANE_STATUS_GOOD;
678          }
679          else if (action == SANE_ACTION_SET_VALUE)
680          {
681             if (*int_value >= MARVELL_CONTRAST_MIN && *int_value <= MARVELL_CONTRAST_MAX)
682             {
683                ps->current_contrast = *int_value;
684                stat = SANE_STATUS_GOOD;
685                break;
686             }
687          }
688          else
689          {  /* Set default. */
690             ps->current_contrast = MARVELL_CONTRAST_DEFAULT;
691             stat = SANE_STATUS_GOOD;
692          }
693          break;
694       case MARVELL_OPTION_TL_X:
695          if (action == SANE_ACTION_GET_VALUE)
696          {
697             *int_value = ps->currentTlx;
698             stat = SANE_STATUS_GOOD;
699          }
700          else if (action == SANE_ACTION_SET_VALUE)
701          {
702             if (*int_value >= ps->tlxRange.min && *int_value <= ps->tlxRange.max)
703             {
704                ps->currentTlx = *int_value;
705                mset_result |= SANE_INFO_RELOAD_PARAMS;
706                stat = SANE_STATUS_GOOD;
707                break;
708             }
709          }
710          else
711          {  /* Set default. */
712             ps->currentTlx = ps->tlxRange.min;
713             stat = SANE_STATUS_GOOD;
714          }
715          break;
716       case MARVELL_OPTION_TL_Y:
717          if (action == SANE_ACTION_GET_VALUE)
718          {
719             *int_value = ps->currentTly;
720             stat = SANE_STATUS_GOOD;
721          }
722          else if (action == SANE_ACTION_SET_VALUE)
723          {
724             if (*int_value >= ps->tlyRange.min && *int_value <= ps->tlyRange.max)
725             {
726                
727                ps->currentTly = *int_value;
728                mset_result |= SANE_INFO_RELOAD_PARAMS;
729                stat = SANE_STATUS_GOOD;
730                break;
731             }
732          }
733          else
734          {  /* Set default. */
735             ps->currentTly = ps->tlyRange.min;
736             stat = SANE_STATUS_GOOD;
737          }
738          break;
739       case MARVELL_OPTION_BR_X:
740          if (action == SANE_ACTION_GET_VALUE)
741          {
742             *int_value = ps->currentBrx;
743             stat = SANE_STATUS_GOOD;
744          }
745          else if (action == SANE_ACTION_SET_VALUE)
746          {
747             if (*int_value >= ps->brxRange.min && *int_value <= ps->brxRange.max)
748             {
749                ps->currentBrx = *int_value;
750                mset_result |= SANE_INFO_RELOAD_PARAMS;
751                stat = SANE_STATUS_GOOD;
752                break;
753             }
754          }
755          else
756          {  /* Set default. */
757             ps->currentBrx = ps->brxRange.max;
758             stat = SANE_STATUS_GOOD;
759          }
760          break;
761       case MARVELL_OPTION_BR_Y:
762          if (action == SANE_ACTION_GET_VALUE)
763          {
764             *int_value = ps->currentBry;
765             stat = SANE_STATUS_GOOD;
766          }
767          else if (action == SANE_ACTION_SET_VALUE)
768          {
769             if (*int_value >= ps->bryRange.min && *int_value <= ps->bryRange.max)
770             {
771                ps->currentBry = *int_value;
772                mset_result |= SANE_INFO_RELOAD_PARAMS;
773                stat = SANE_STATUS_GOOD;
774                break;
775             }
776             BUG("value=%d brymin=%d brymax=%d\n", *int_value, ps->bryRange.min, ps->bryRange.max);
777          }
778          else
779          {  /* Set default. */
780             ps->currentBry = ps->bryRange.max;
781             stat = SANE_STATUS_GOOD;
782          }
783          break;
784       default:
785          break;
786    }
787
788    if (set_result)
789       *set_result = mset_result;
790
791    if (stat != SANE_STATUS_GOOD)
792    {
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");
795    }
796
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");
800
801    return stat;
802 }
803
804 SANE_Status marvell_get_parameters(SANE_Handle handle, SANE_Parameters *params)
805 {
806    struct marvell_session *ps = (struct marvell_session *)handle;
807
808    set_extents(ps);
809
810    ps->bb_get_parameters(ps, params, ps->ip_handle ? 1 : 0);
811
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);
814
815    return SANE_STATUS_GOOD;
816 }
817
818 SANE_Status marvell_start(SANE_Handle handle)
819 {
820    struct marvell_session *ps = (struct marvell_session *)handle;
821    SANE_Parameters pp;
822    IP_IMAGE_TRAITS traits;
823    IP_XFORM_SPEC xforms[IP_MAX_XFORMS], *pXform=xforms;
824    int stat, ret;
825 //   int tmo=EXCEPTION_TIMEOUT*2;
826
827    DBG8("sane_hpaio_start()\n");
828    ps->is_user_cancel = 0;
829    
830    if (set_extents(ps))
831    {
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;
835       goto bugout;
836    }   
837
838    /* If input is ADF and ADF is empty, return SANE_STATUS_NO_DOCS. */
839    if (ps->current_input_source == IS_ADF)
840    {
841       ret = ps->bb_is_paper_in_adf(ps);   /* 0 = no paper in adf, 1 = paper in adf, 2 = no adf, -1 = error */
842       if (ret == 0)
843       {
844          stat = SANE_STATUS_NO_DOCS;     /* done scanning */
845          SendScanEvent(ps->uri, EVENT_SCAN_ADF_NO_DOCS);
846          goto bugout;
847       }
848       else if (ret < 0)
849       {
850          stat = SANE_STATUS_IO_ERROR;
851          goto bugout;
852       }
853    }
854    /* Start scan and get actual image traits. */
855    if (ps->bb_start_scan(ps))
856    {
857       stat = SANE_STATUS_IO_ERROR;
858       goto bugout;
859    }
860
861    SendScanEvent(ps->uri, EVENT_START_SCAN_JOB);
862    memset(xforms, 0, sizeof(xforms));    
863
864    /* Setup image-processing pipeline for xform. */
865    if (ps->current_scan_mode == CE_BLACK_AND_WHITE1)
866    {
867       pXform->aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword = 127;
868       ADD_XFORM(X_GRAY_2_BI);
869    }
870
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;
876    ADD_XFORM(X_CROP);
877
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;
885    ADD_XFORM(X_PAD);
886
887    /* Open image processor. */
888    if ((ret = ipOpen(pXform-xforms, xforms, 0, &ps->ip_handle)) != IP_DONE)
889    {
890       BUG("unable open image processor: err=%d\n", ret);
891       stat = SANE_STATUS_INVAL;
892       goto bugout;
893    }
894
895    /* Get actual input image attributes. See bb_start_scan(). */
896    ps->bb_get_parameters(ps, &pp, 1);
897
898    /* Now set known input image attributes. */
899    traits.iPixelsPerRow = pp.pixels_per_line;
900    switch(ps->current_scan_mode)
901    {
902       case CE_BLACK_AND_WHITE1:         /* lineart */
903       case CE_GRAY8:
904          traits.iBitsPerPixel = 8;     /* grayscale */
905          break;
906       case CE_RGB24:
907       default:
908          traits.iBitsPerPixel = 24;      /* color */
909          break;
910    }
911    traits.lHorizDPI = ps->current_resolution << 16;
912    traits.lVertDPI = ps->current_resolution << 16;
913    traits.lNumRows = pp.lines;
914    traits.iNumPages = 1;
915    traits.iPageNum = 1;
916    traits.iComponentsPerPixel = ((traits.iBitsPerPixel % 3) ? 1 : 3);
917    ipSetDefaultInputTraits(ps->ip_handle, &traits);
918
919    /* Get output image attributes from the image processor. */
920    ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits);  /* get valid image traits */
921
922    stat = SANE_STATUS_GOOD;
923
924 bugout:
925    if (stat != SANE_STATUS_GOOD)
926    {
927       if (ps->ip_handle)
928       {
929          ipClose(ps->ip_handle); 
930          ps->ip_handle = 0;
931       }
932       ps->bb_end_scan(ps, stat == SANE_STATUS_IO_ERROR ? 1: 0);
933    }
934
935    return stat;
936 }
937
938 SANE_Status marvell_read(SANE_Handle handle, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length)
939 {
940    struct marvell_session *ps = (struct marvell_session *)handle;
941    int ret, stat=SANE_STATUS_IO_ERROR;
942 //   int tmo=EXCEPTION_TIMEOUT;
943
944    DBG8("sane_hpaio_read() handle=%p data=%p maxLength=%d\n", (void *)handle, data, maxLength);
945
946    ret = get_ip_data(ps, data, maxLength, length);
947
948    if(ret & (IP_INPUT_ERROR | IP_FATAL_ERROR))
949    {
950       BUG("ipConvert error=%x\n", ret);
951       goto bugout;
952    }
953
954    if (ret & IP_DONE)
955    {
956       stat = SANE_STATUS_EOF;
957       SendScanEvent(ps->uri, EVENT_END_SCAN_JOB);
958    }
959    else
960       stat = SANE_STATUS_GOOD;
961
962 bugout:
963    if (stat != SANE_STATUS_GOOD)
964    {
965       if (ps->ip_handle)
966       {
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);  
969          ps->ip_handle = 0;
970       } 
971        //If user has cancelled scan from device
972       if (ps->is_user_cancel)
973       {
974           //Don't do anything. sane_hpaio_cancel() will be invoked automatically
975           SendScanEvent(ps->uri, EVENT_SCAN_CANCEL);
976           return SANE_STATUS_CANCELLED;
977
978        }
979        else 
980            {
981                ps->bb_end_page(ps, stat == SANE_STATUS_IO_ERROR ? 1: 0);
982            }
983    }
984
985    DBG8("-sane_hpaio_read() output=%p bytes_read=%d maxLength=%d status=%d\n", data, *length, maxLength, stat);
986
987    return stat;
988 }
989
990 void marvell_cancel(SANE_Handle handle)
991 {
992    struct marvell_session *ps = (struct marvell_session *)handle;
993
994    DBG8("sane_hpaio_cancel()\n"); 
995
996    /*
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.
999     */
1000    ps->is_user_cancel = 1 ;
1001    
1002    if (ps->ip_handle)
1003    {
1004       ipClose(ps->ip_handle); 
1005       ps->ip_handle = 0;
1006    }
1007    ps->bb_end_scan(ps, 0);
1008 }
1009