~ubuntu-branches/ubuntu/saucy/hplip/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/try_libhpmud.so.0.dpatch/scan/sane/soapht.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2012-05-26 11:20:39 UTC
  • mfrom: (1.5.6) (31.1.3 precise)
  • Revision ID: package-import@ubuntu.com-20120526112039-bevxczegxnbyr5m7
Tags: 3.12.4-1
* New upstream release
* Switch to source/format 3.0 (quilt) - drop dpatch
* Refreshed debian/patches
* dh_autoreconf debian/autogen.sh & set local-options single-debian-patch
* Update to debian/compat -> 9
* Fix "hardened build flags" patch from Moritz - thanks (Closes: #667828)
* Fix "duplex descriptor uninitialized" patch from Matej (Closes: #583273)
* Fix "please migrate to kde-runtime" patch from Pino (Closes: #666544)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/************************************************************************************\
 
2
 
 
3
  soapht.c - HP SANE backend support for soap based multi-function peripherals
 
4
 
 
5
  (c) 2006,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
  Note when the LJM1522 input source is ADF, all pages loaded in the ADF must be scanned
 
25
  as one complete scan job, otherwise the ADF will jam. This mean if you try to scan
 
26
  one page only when multiple pages are loaded, the second page will jam. This is how the
 
27
  hardware works. The Windows driver has the same limitation.
 
28
 
 
29
  Author: David Suffield
 
30
  Contributor: Sarbeswar Meher
 
31
 
 
32
\************************************************************************************/
 
33
 
 
34
#ifndef _GNU_SOURCE
 
35
#define _GNU_SOURCE
 
36
#endif
 
37
 
 
38
#include <stdarg.h>
 
39
#include <syslog.h>
 
40
#include <stdio.h>
 
41
#include <string.h>
 
42
#include <fcntl.h>
 
43
#include <math.h>
 
44
#include <dlfcn.h>
 
45
#include "sane.h"
 
46
#include "saneopts.h"
 
47
#include "hpmud.h"
 
48
#include "hpip.h"
 
49
#include "common.h"
 
50
#include "soapht.h"
 
51
#include "soaphti.h"
 
52
#include "io.h"
 
53
 
 
54
#define DEBUG_DECLARE_ONLY
 
55
#include "sanei_debug.h"
 
56
 
 
57
static struct soap_session *session = NULL;   /* assume one sane_open per process */
 
58
 
 
59
static int bb_load(struct soap_session *ps, const char *so)
 
60
{
 
61
   char home[128];
 
62
   char sz[255]; 
 
63
   int stat=1;
 
64
 
 
65
   /* Load hpmud manually with symbols exported. Otherwise the plugin will not find it. */ 
 
66
   if ((ps->hpmud_handle = dlopen("libhpmud.so.0", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
 
67
   {
 
68
      BUG("unable to load restricted library: %s\n", dlerror());
 
69
      goto bugout;
 
70
   } 
 
71
 
 
72
   /* Load math library manually with symbols exported (Ubuntu 8.04). Otherwise the plugin will not find it. */ 
 
73
   if ((ps->math_handle = dlopen("libm.so", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
 
74
   {
 
75
      if ((ps->math_handle = dlopen("libm.so.6", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
 
76
      {
 
77
         BUG("unable to load restricted library: %s\n", dlerror());
 
78
         goto bugout;
 
79
      }
 
80
   } 
 
81
 
 
82
   if (hpmud_get_conf("[dirs]", "home", home, sizeof(home)) != HPMUD_R_OK)
 
83
      goto bugout;
 
84
   snprintf(sz, sizeof(sz), "%s/scan/plugins/%s", home, so);
 
85
   if ((ps->bb_handle = dlopen(sz, RTLD_NOW|RTLD_GLOBAL)) == NULL)
 
86
   {
 
87
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
88
      SendScanEvent(ps->uri, EVENT_PLUGIN_FAIL);
 
89
      goto bugout;
 
90
   } 
 
91
   
 
92
   if ((ps->bb_open = dlsym(ps->bb_handle, "bb_open")) == NULL)
 
93
   {
 
94
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
95
      goto bugout;
 
96
   } 
 
97
   if ((ps->bb_close = dlsym(ps->bb_handle, "bb_close")) == NULL)
 
98
   {
 
99
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
100
      goto bugout;
 
101
   } 
 
102
   if ((ps->bb_get_parameters = dlsym(ps->bb_handle, "bb_get_parameters")) == NULL)
 
103
   {
 
104
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
105
      goto bugout;
 
106
   } 
 
107
   if ((ps->bb_is_paper_in_adf = dlsym(ps->bb_handle, "bb_is_paper_in_adf")) == NULL)
 
108
   {
 
109
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
110
      goto bugout;
 
111
   } 
 
112
   if ((ps->bb_start_scan = dlsym(ps->bb_handle, "bb_start_scan")) == NULL)
 
113
   {
 
114
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
115
      goto bugout;
 
116
   } 
 
117
   if ((ps->bb_end_scan = dlsym(ps->bb_handle, "bb_end_scan")) == NULL)
 
118
   {
 
119
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
120
      goto bugout;
 
121
   } 
 
122
   if ((ps->bb_get_image_data = dlsym(ps->bb_handle, "bb_get_image_data")) == NULL)
 
123
   {
 
124
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
125
      goto bugout;
 
126
   } 
 
127
   if ((ps->bb_end_page = dlsym(ps->bb_handle, "bb_end_page")) == NULL)
 
128
   {
 
129
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
130
      goto bugout;
 
131
   } 
 
132
 
 
133
   stat=0;
 
134
 
 
135
bugout:
 
136
   return stat;
 
137
} /* bb_load */
 
138
 
 
139
static int bb_unload(struct soap_session *ps)
 
140
{
 
141
   if (ps->bb_handle)
 
142
   {   
 
143
      dlclose(ps->bb_handle);
 
144
      ps->bb_handle = NULL;
 
145
   }  
 
146
   if (ps->hpmud_handle)
 
147
   {   
 
148
      dlclose(ps->hpmud_handle);
 
149
      ps->hpmud_handle = NULL;
 
150
   }  
 
151
   if (ps->math_handle)
 
152
   {   
 
153
      dlclose(ps->math_handle);
 
154
      ps->math_handle = NULL;
 
155
   }  
 
156
   return 0;
 
157
} /* bb_unload */
 
158
 
 
159
/* Get raw data (ie: uncompressed data) from image processor. */
 
160
static int get_ip_data(struct soap_session *ps, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length)
 
161
{
 
162
   int ip_ret=IP_INPUT_ERROR;
 
163
   unsigned int outputAvail=maxLength, outputUsed=0, outputThisPos;
 
164
   unsigned char *input, *output = data;
 
165
   unsigned int inputAvail, inputUsed=0, inputNextPos;
 
166
 
 
167
   if (!ps->ip_handle)
 
168
   {
 
169
      BUG("invalid ipconvert state\n");
 
170
      goto bugout;
 
171
   }      
 
172
 
 
173
   if (ps->bb_get_image_data(ps, outputAvail))
 
174
      goto bugout;
 
175
 
 
176
   if (ps->cnt > 0)
 
177
   {
 
178
      inputAvail = ps->cnt;
 
179
      input = &ps->buf[ps->index];
 
180
   }
 
181
   else
 
182
   {
 
183
      input = NULL;   /* no more scan data, flush ipconvert pipeline */
 
184
      inputAvail = 0;
 
185
   }
 
186
 
 
187
   /* Transform input data to output. Note, output buffer may consume more bytes than input buffer (ie: jpeg to raster). */
 
188
   ip_ret = ipConvert(ps->ip_handle, inputAvail, input, &inputUsed, &inputNextPos, outputAvail, output, &outputUsed, &outputThisPos);
 
189
 
 
190
   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, 
 
191
         inputAvail, inputUsed, inputNextPos, output, outputAvail, outputUsed, outputThisPos);
 
192
 
 
193
   if (input != NULL)
 
194
   {
 
195
      if (inputAvail == inputUsed)
 
196
      {
 
197
         ps->index = ps->cnt = 0;   /* reset buffer */
 
198
      }
 
199
      else
 
200
      {
 
201
         ps->cnt -= inputUsed;    /* save left over buffer for next soap_read */
 
202
         ps->index += inputUsed;
 
203
      }
 
204
   }
 
205
 
 
206
   if (data)
 
207
      *length = outputUsed;
 
208
 
 
209
   /* For sane do not send output data simultaneously with IP_DONE. */
 
210
   if (ip_ret & IP_DONE && outputUsed)
 
211
      ip_ret &= ~IP_DONE;                               
 
212
 
 
213
bugout:
 
214
   return ip_ret;
 
215
} /* get_ip_data */
 
216
 
 
217
static int set_scan_mode_side_effects(struct soap_session *ps, enum COLOR_ENTRY scanMode)
 
218
{
 
219
   int j=0;
 
220
 
 
221
   memset(ps->compressionList, 0, sizeof(ps->compressionList));
 
222
   memset(ps->compressionMap, 0, sizeof(ps->compressionMap));
 
223
 
 
224
   switch (scanMode)
 
225
   {
 
226
      case CE_BLACK_AND_WHITE1:         /* same as GRAY8 */
 
227
      case CE_GRAY8:
 
228
      case CE_RGB24:
 
229
      default:
 
230
         ps->compressionList[j] = STR_COMPRESSION_NONE; 
 
231
         ps->compressionMap[j++] = SF_HPRAW;
 
232
         ps->compressionList[j] = STR_COMPRESSION_JPEG; 
 
233
         ps->compressionMap[j++] = SF_JFIF;
 
234
         ps->currentCompression = SF_JFIF;
 
235
         ps->option[SOAP_OPTION_JPEG_QUALITY].cap |= SANE_CAP_SOFT_SELECT;   /* enable jpeg quality */        
 
236
         break;
 
237
   }
 
238
 
 
239
   return 0;
 
240
} /* set_scan_mode_side_effects */
 
241
 
 
242
static int set_input_source_side_effects(struct soap_session *ps, enum INPUT_SOURCE source)
 
243
{
 
244
   switch (source)
 
245
   {
 
246
      case IS_PLATEN: 
 
247
         ps->min_width = ps->platen_min_width;
 
248
         ps->min_height = ps->platen_min_height;
 
249
         ps->tlxRange.max = ps->platen_tlxRange.max;
 
250
         ps->brxRange.max = ps->platen_brxRange.max;
 
251
         ps->tlyRange.max = ps->platen_tlyRange.max;
 
252
         ps->bryRange.max = ps->platen_bryRange.max;
 
253
         break;
 
254
      case IS_ADF:
 
255
      case IS_ADF_DUPLEX:
 
256
      default:
 
257
         ps->min_width = ps->adf_min_width;
 
258
         ps->min_height = ps->adf_min_height;
 
259
         ps->tlxRange.max = ps->adf_tlxRange.max;
 
260
         ps->brxRange.max = ps->adf_brxRange.max;
 
261
         ps->tlyRange.max = ps->adf_tlyRange.max;
 
262
         ps->bryRange.max = ps->adf_bryRange.max;
 
263
         break;
 
264
   }
 
265
 
 
266
   return 0;
 
267
} /* set_input_source_side_effects */
 
268
 
 
269
static int init_options(struct soap_session *ps)
 
270
{
 
271
   ps->option[SOAP_OPTION_COUNT].name = "option-cnt";
 
272
   ps->option[SOAP_OPTION_COUNT].title = SANE_TITLE_NUM_OPTIONS;
 
273
   ps->option[SOAP_OPTION_COUNT].desc = SANE_DESC_NUM_OPTIONS;
 
274
   ps->option[SOAP_OPTION_COUNT].type = SANE_TYPE_INT;
 
275
   ps->option[SOAP_OPTION_COUNT].unit = SANE_UNIT_NONE;
 
276
   ps->option[SOAP_OPTION_COUNT].size = sizeof(SANE_Int);
 
277
   ps->option[SOAP_OPTION_COUNT].cap = SANE_CAP_SOFT_DETECT;
 
278
   ps->option[SOAP_OPTION_COUNT].constraint_type = SANE_CONSTRAINT_NONE;
 
279
 
 
280
   ps->option[SOAP_OPTION_GROUP_SCAN_MODE].name = "mode-group";
 
281
   ps->option[SOAP_OPTION_GROUP_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
 
282
   ps->option[SOAP_OPTION_GROUP_SCAN_MODE].type = SANE_TYPE_GROUP;
 
283
 
 
284
   ps->option[SOAP_OPTION_SCAN_MODE].name = SANE_NAME_SCAN_MODE;
 
285
   ps->option[SOAP_OPTION_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
 
286
   ps->option[SOAP_OPTION_SCAN_MODE].desc = SANE_DESC_SCAN_MODE;
 
287
   ps->option[SOAP_OPTION_SCAN_MODE].type = SANE_TYPE_STRING;
 
288
   ps->option[SOAP_OPTION_SCAN_MODE].unit = SANE_UNIT_NONE;
 
289
   ps->option[SOAP_OPTION_SCAN_MODE].size = MAX_STRING_SIZE;
 
290
   ps->option[SOAP_OPTION_SCAN_MODE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
291
   ps->option[SOAP_OPTION_SCAN_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 
292
   ps->option[SOAP_OPTION_SCAN_MODE].constraint.string_list = ps->scanModeList;
 
293
 
 
294
   ps->option[SOAP_OPTION_INPUT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
 
295
   ps->option[SOAP_OPTION_INPUT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
 
296
   ps->option[SOAP_OPTION_INPUT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
 
297
   ps->option[SOAP_OPTION_INPUT_SOURCE].type = SANE_TYPE_STRING;
 
298
   ps->option[SOAP_OPTION_INPUT_SOURCE].unit = SANE_UNIT_NONE;
 
299
   ps->option[SOAP_OPTION_INPUT_SOURCE].size = MAX_STRING_SIZE;
 
300
   ps->option[SOAP_OPTION_INPUT_SOURCE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
301
   ps->option[SOAP_OPTION_INPUT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 
302
   ps->option[SOAP_OPTION_INPUT_SOURCE].constraint.string_list = ps->inputSourceList;
 
303
 
 
304
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
 
305
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
 
306
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
 
307
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].type = SANE_TYPE_INT;
 
308
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].unit = SANE_UNIT_DPI;
 
309
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].size = sizeof(SANE_Int);
 
310
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
311
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
 
312
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].constraint.word_list = ps->resolutionList;
 
313
 
 
314
   ps->option[SOAP_OPTION_GROUP_ADVANCED].name = "advanced-group";
 
315
   ps->option[SOAP_OPTION_GROUP_ADVANCED].title = STR_TITLE_ADVANCED;
 
316
   ps->option[SOAP_OPTION_GROUP_ADVANCED].type = SANE_TYPE_GROUP;
 
317
   ps->option[SOAP_OPTION_GROUP_ADVANCED].cap = SANE_CAP_ADVANCED;
 
318
 
 
319
   ps->option[SOAP_OPTION_CONTRAST].name = SANE_NAME_CONTRAST;
 
320
   ps->option[SOAP_OPTION_CONTRAST].title = SANE_TITLE_CONTRAST;
 
321
   ps->option[SOAP_OPTION_CONTRAST].desc = SANE_DESC_CONTRAST;
 
322
   ps->option[SOAP_OPTION_CONTRAST].type = SANE_TYPE_INT;
 
323
   ps->option[SOAP_OPTION_CONTRAST].unit = SANE_UNIT_NONE;
 
324
   ps->option[SOAP_OPTION_CONTRAST].size = sizeof(SANE_Int);
 
325
   ps->option[SOAP_OPTION_CONTRAST].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
 
326
   ps->option[SOAP_OPTION_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
 
327
   ps->option[SOAP_OPTION_CONTRAST].constraint.range = &ps->contrastRange;
 
328
   ps->contrastRange.min = SOAP_CONTRAST_MIN;
 
329
   ps->contrastRange.max = SOAP_CONTRAST_MAX;
 
330
   ps->contrastRange.quant = 0;
 
331
 
 
332
   ps->option[SOAP_OPTION_COMPRESSION].name = STR_NAME_COMPRESSION;
 
333
   ps->option[SOAP_OPTION_COMPRESSION].title = STR_TITLE_COMPRESSION;
 
334
   ps->option[SOAP_OPTION_COMPRESSION].desc = STR_DESC_COMPRESSION;
 
335
   ps->option[SOAP_OPTION_COMPRESSION].type = SANE_TYPE_STRING;
 
336
   ps->option[SOAP_OPTION_COMPRESSION].unit = SANE_UNIT_NONE;
 
337
   ps->option[SOAP_OPTION_COMPRESSION].size = MAX_STRING_SIZE;
 
338
   ps->option[SOAP_OPTION_COMPRESSION].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
 
339
   ps->option[SOAP_OPTION_COMPRESSION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 
340
   ps->option[SOAP_OPTION_COMPRESSION].constraint.string_list = ps->compressionList;
 
341
 
 
342
   ps->option[SOAP_OPTION_JPEG_QUALITY].name = STR_NAME_JPEG_QUALITY;
 
343
   ps->option[SOAP_OPTION_JPEG_QUALITY].title = STR_TITLE_JPEG_QUALITY;
 
344
   ps->option[SOAP_OPTION_JPEG_QUALITY].desc = STR_DESC_JPEG_QUALITY;
 
345
   ps->option[SOAP_OPTION_JPEG_QUALITY].type = SANE_TYPE_INT;
 
346
   ps->option[SOAP_OPTION_JPEG_QUALITY].unit = SANE_UNIT_NONE;
 
347
   ps->option[SOAP_OPTION_JPEG_QUALITY].size = sizeof(SANE_Int);
 
348
   ps->option[SOAP_OPTION_JPEG_QUALITY].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
 
349
   ps->option[SOAP_OPTION_JPEG_QUALITY].constraint_type = SANE_CONSTRAINT_RANGE;
 
350
   ps->option[SOAP_OPTION_JPEG_QUALITY].constraint.range = &ps->jpegQualityRange;
 
351
   ps->jpegQualityRange.min = MIN_JPEG_COMPRESSION_FACTOR;
 
352
   ps->jpegQualityRange.max = MAX_JPEG_COMPRESSION_FACTOR;
 
353
   ps->jpegQualityRange.quant = 0;
 
354
 
 
355
   ps->option[SOAP_OPTION_GROUP_GEOMETRY].name = "geometry-group";
 
356
   ps->option[SOAP_OPTION_GROUP_GEOMETRY].title = STR_TITLE_GEOMETRY;
 
357
   ps->option[SOAP_OPTION_GROUP_GEOMETRY].type = SANE_TYPE_GROUP;
 
358
   ps->option[SOAP_OPTION_GROUP_GEOMETRY].cap = SANE_CAP_ADVANCED;
 
359
 
 
360
   ps->option[SOAP_OPTION_TL_X].name = SANE_NAME_SCAN_TL_X;
 
361
   ps->option[SOAP_OPTION_TL_X].title = SANE_TITLE_SCAN_TL_X;
 
362
   ps->option[SOAP_OPTION_TL_X].desc = SANE_DESC_SCAN_TL_X;
 
363
   ps->option[SOAP_OPTION_TL_X].type = SANE_TYPE_FIXED;
 
364
   ps->option[SOAP_OPTION_TL_X].unit = SANE_UNIT_MM;
 
365
   ps->option[SOAP_OPTION_TL_X].size = sizeof(SANE_Int);
 
366
   ps->option[SOAP_OPTION_TL_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
367
   ps->option[SOAP_OPTION_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
 
368
   ps->option[SOAP_OPTION_TL_X].constraint.range = &ps->tlxRange;
 
369
   ps->tlxRange.min = 0;
 
370
   ps->tlxRange.quant = 0;
 
371
 
 
372
   ps->option[SOAP_OPTION_TL_Y].name = SANE_NAME_SCAN_TL_Y;
 
373
   ps->option[SOAP_OPTION_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
 
374
   ps->option[SOAP_OPTION_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
 
375
   ps->option[SOAP_OPTION_TL_Y].type = SANE_TYPE_FIXED;
 
376
   ps->option[SOAP_OPTION_TL_Y].unit = SANE_UNIT_MM;
 
377
   ps->option[SOAP_OPTION_TL_Y].size = sizeof(SANE_Int);
 
378
   ps->option[SOAP_OPTION_TL_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
379
   ps->option[SOAP_OPTION_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 
380
   ps->option[SOAP_OPTION_TL_Y].constraint.range = &ps->tlyRange;
 
381
   ps->tlyRange.min = 0;
 
382
   ps->tlyRange.quant = 0;
 
383
 
 
384
   ps->option[SOAP_OPTION_BR_X].name = SANE_NAME_SCAN_BR_X;
 
385
   ps->option[SOAP_OPTION_BR_X].title = SANE_TITLE_SCAN_BR_X;
 
386
   ps->option[SOAP_OPTION_BR_X].desc = SANE_DESC_SCAN_BR_X;
 
387
   ps->option[SOAP_OPTION_BR_X].type = SANE_TYPE_FIXED;
 
388
   ps->option[SOAP_OPTION_BR_X].unit = SANE_UNIT_MM;
 
389
   ps->option[SOAP_OPTION_BR_X].size = sizeof(SANE_Int);
 
390
   ps->option[SOAP_OPTION_BR_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
391
   ps->option[SOAP_OPTION_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
 
392
   ps->option[SOAP_OPTION_BR_X].constraint.range = &ps->brxRange;
 
393
   ps->brxRange.min = 0;
 
394
   ps->brxRange.quant = 0;
 
395
 
 
396
   ps->option[SOAP_OPTION_BR_Y].name = SANE_NAME_SCAN_BR_Y;
 
397
   ps->option[SOAP_OPTION_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
 
398
   ps->option[SOAP_OPTION_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
 
399
   ps->option[SOAP_OPTION_BR_Y].type = SANE_TYPE_FIXED;
 
400
   ps->option[SOAP_OPTION_BR_Y].unit = SANE_UNIT_MM;
 
401
   ps->option[SOAP_OPTION_BR_Y].size = sizeof(SANE_Int);
 
402
   ps->option[SOAP_OPTION_BR_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
403
   ps->option[SOAP_OPTION_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 
404
   ps->option[SOAP_OPTION_BR_Y].constraint.range = &ps->bryRange;
 
405
   ps->bryRange.min = 0;
 
406
   ps->bryRange.quant = 0;
 
407
 
 
408
   return 0;
 
409
} /* init_options */
 
410
 
 
411
/* Verify current x/y extents and set effective extents. */ 
 
412
static int set_extents(struct soap_session *ps)
 
413
{
 
414
   int stat = 0;
 
415
 
 
416
   if ((ps->currentBrx > ps->currentTlx) && (ps->currentBrx - ps->currentTlx >= ps->min_width) && (ps->currentBrx - ps->currentTlx <= ps->tlxRange.max))
 
417
   {
 
418
     ps->effectiveTlx = ps->currentTlx;
 
419
     ps->effectiveBrx = ps->currentBrx;
 
420
   }
 
421
   else
 
422
   {
 
423
     ps->effectiveTlx = 0;  /* current setting is not valid, zero it */
 
424
     ps->effectiveBrx = 0;
 
425
     stat = 1;
 
426
   }
 
427
   if ((ps->currentBry > ps->currentTly) && (ps->currentBry - ps->currentTly > ps->min_height) && (ps->currentBry - ps->currentTly <= ps->tlyRange.max))
 
428
   {
 
429
     ps->effectiveTly = ps->currentTly;
 
430
     ps->effectiveBry = ps->currentBry;
 
431
   }
 
432
   else
 
433
   {
 
434
     ps->effectiveTly = 0;  /* current setting is not valid, zero it */
 
435
     ps->effectiveBry = 0;
 
436
     stat = 1;
 
437
   }
 
438
   return stat;
 
439
} /* set_extents */
 
440
 
 
441
static struct soap_session *create_session()
 
442
{
 
443
   struct soap_session *ps;
 
444
 
 
445
   if ((ps = malloc(sizeof(struct soap_session))) == NULL)
 
446
   {
 
447
      BUG("malloc failed: %m\n");
 
448
      return NULL;
 
449
   }
 
450
   memset(ps, 0, sizeof(struct soap_session));
 
451
   ps->tag = "SOAPHT";
 
452
   ps->dd = -1;
 
453
   ps->cd = -1;
 
454
 
 
455
   return ps;
 
456
} /* create_session */
 
457
 
 
458
/*
 
459
 * SANE APIs.
 
460
 */
 
461
 
 
462
SANE_Status soapht_open(SANE_String_Const device, SANE_Handle *handle)
 
463
{
 
464
   struct hpmud_model_attributes ma;
 
465
   int i, stat = SANE_STATUS_IO_ERROR;
 
466
 
 
467
   DBG8("sane_hpaio_open(%s)\n", device);
 
468
 
 
469
   if (session)
 
470
   {
 
471
      BUG("session in use\n");
 
472
      return SANE_STATUS_DEVICE_BUSY;
 
473
   }
 
474
 
 
475
   if ((session = create_session()) == NULL)
 
476
      return SANE_STATUS_NO_MEM;
 
477
    
 
478
   /* Set session to specified device. */
 
479
   snprintf(session->uri, sizeof(session->uri)-1, "hp:%s", device);   /* prepend "hp:" */
 
480
 
 
481
   /* Get actual model attributes from models.dat. */
 
482
   hpmud_query_model(session->uri, &ma);
 
483
   session->scan_type = ma.scantype;
 
484
 
 
485
   if (hpmud_open_device(session->uri, ma.mfp_mode, &session->dd) != HPMUD_R_OK)
 
486
   {
 
487
      BUG("unable to open device %s\n", session->uri);
 
488
      goto bugout;
 
489
 
 
490
      free(session);
 
491
      session = NULL;
 
492
      return SANE_STATUS_IO_ERROR;
 
493
   }
 
494
 
 
495
   if (bb_load(session, "bb_soapht.so"))
 
496
   {
 
497
      stat = SANE_STATUS_IO_ERROR;
 
498
      goto bugout;
 
499
   }
 
500
 
 
501
   /* Init sane option descriptors. */
 
502
   init_options(session);  
 
503
 
 
504
   if (session->bb_open(session))
 
505
   {
 
506
      stat = SANE_STATUS_IO_ERROR;
 
507
      goto bugout;
 
508
   }
 
509
 
 
510
   /* Set supported Scan Modes as determined by bb_open. */
 
511
   soapht_control_option(session, SOAP_OPTION_SCAN_MODE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
512
 
 
513
   /* Set scan input sources as determined by bb_open. */
 
514
   soapht_control_option(session, SOAP_OPTION_INPUT_SOURCE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */  
 
515
 
 
516
   /* Set supported resolutions. */
 
517
     soapht_control_option(session, SOAP_OPTION_SCAN_RESOLUTION, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
518
 
 
519
   /* Set supported contrast. */
 
520
   soapht_control_option(session, SOAP_OPTION_CONTRAST, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
521
 
 
522
   /* Set supported compression. (Note, cm1017 may say it supports MMR, but it doesn't) */
 
523
   soapht_control_option(session, SOAP_OPTION_COMPRESSION, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
524
   
 
525
   /* Determine supported jpeg quality factor as determined by bb_open. */
 
526
   soapht_control_option(session, SOAP_OPTION_JPEG_QUALITY, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
527
 
 
528
   /* Set x,y extents. See bb_open */
 
529
   soapht_control_option(session, SOAP_OPTION_TL_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
530
   soapht_control_option(session, SOAP_OPTION_TL_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
531
   soapht_control_option(session, SOAP_OPTION_BR_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
532
   soapht_control_option(session, SOAP_OPTION_BR_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
533
 
 
534
   *handle = (SANE_Handle *)session;
 
535
 
 
536
   stat = SANE_STATUS_GOOD;
 
537
 
 
538
bugout:
 
539
 
 
540
   if (stat != SANE_STATUS_GOOD)
 
541
   {
 
542
      if (session)
 
543
      {
 
544
         bb_unload(session);
 
545
         if (session->dd > 0)
 
546
            hpmud_close_device(session->dd);
 
547
         free(session);
 
548
         session = NULL;
 
549
      }
 
550
   }
 
551
 
 
552
   return stat;
 
553
} /* saneht_open */
 
554
 
 
555
void soapht_close(SANE_Handle handle)
 
556
{
 
557
   struct soap_session *ps = (struct soap_session *)handle;
 
558
 
 
559
   DBG8("sane_hpaio_close()\n"); 
 
560
 
 
561
   if (ps == NULL || ps != session)
 
562
   {
 
563
      BUG("invalid sane_close\n");
 
564
      return;
 
565
   }
 
566
 
 
567
   ps->bb_close(ps);
 
568
   bb_unload(ps);
 
569
 
 
570
   if (ps->dd > 0)
 
571
      hpmud_close_device(ps->dd);
 
572
    
 
573
   free(ps);
 
574
   session = NULL;
 
575
} /* saneht_close */
 
576
 
 
577
const SANE_Option_Descriptor *soapht_get_option_descriptor(SANE_Handle handle, SANE_Int option)
 
578
{
 
579
   struct soap_session *ps = (struct soap_session *)handle;
 
580
 
 
581
   DBG8("sane_hpaio_get_option_descriptor(option=%s)\n", ps->option[option].name);
 
582
 
 
583
   if (option < 0 || option >= SOAP_OPTION_MAX)
 
584
      return NULL;
 
585
 
 
586
   return &ps->option[option];
 
587
} /* soapht_get_option_descriptor */
 
588
 
 
589
SANE_Status soapht_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int *set_result)
 
590
{
 
591
   struct soap_session *ps = (struct soap_session *)handle;
 
592
   SANE_Int *int_value = value, mset_result=0;
 
593
   int i, stat=SANE_STATUS_INVAL;
 
594
   char sz[64];
 
595
 
 
596
   switch(option)
 
597
   {
 
598
      case SOAP_OPTION_COUNT:
 
599
         if (action == SANE_ACTION_GET_VALUE)
 
600
         {
 
601
            *int_value = SOAP_OPTION_MAX;
 
602
            stat = SANE_STATUS_GOOD;
 
603
         }
 
604
         break;
 
605
      case SOAP_OPTION_SCAN_MODE:
 
606
         if (action == SANE_ACTION_GET_VALUE)
 
607
         {
 
608
            for (i=0; ps->scanModeList[i]; i++)
 
609
            {
 
610
               if (ps->currentScanMode == ps->scanModeMap[i])
 
611
               {
 
612
                  strcpy(value, ps->scanModeList[i]);
 
613
                  stat = SANE_STATUS_GOOD;
 
614
                  break;
 
615
               }
 
616
            }
 
617
         }
 
618
         else if (action == SANE_ACTION_SET_VALUE)
 
619
         {
 
620
            for (i=0; ps->scanModeList[i]; i++)
 
621
            {
 
622
               if (strcasecmp(ps->scanModeList[i], value) == 0)
 
623
               {
 
624
                  ps->currentScanMode = ps->scanModeMap[i];
 
625
                  set_scan_mode_side_effects(ps, ps->currentScanMode);
 
626
                  mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
 
627
                  stat = SANE_STATUS_GOOD;
 
628
                  break;
 
629
               }
 
630
            }
 
631
         }
 
632
         else
 
633
         {  /* Set default. */
 
634
            ps->currentScanMode = CE_RGB24;
 
635
            set_scan_mode_side_effects(ps, ps->currentScanMode);
 
636
            stat = SANE_STATUS_GOOD;
 
637
         }
 
638
         break;
 
639
      case SOAP_OPTION_INPUT_SOURCE:
 
640
         if (action == SANE_ACTION_GET_VALUE)
 
641
         {
 
642
            for (i=0; ps->inputSourceList[i]; i++)
 
643
            {
 
644
               if (ps->currentInputSource == ps->inputSourceMap[i])
 
645
               {
 
646
                  strcpy(value, ps->inputSourceList[i]);
 
647
                  stat = SANE_STATUS_GOOD;
 
648
                  break;
 
649
               }
 
650
            }
 
651
         }
 
652
         else if (action == SANE_ACTION_SET_VALUE)
 
653
         {
 
654
          for (i=0; ps->inputSourceList[i]; i++)
 
655
           {
 
656
             if (strcasecmp(ps->inputSourceList[i], value) == 0)
 
657
             {
 
658
               ps->currentInputSource = ps->inputSourceMap[i];
 
659
               set_input_source_side_effects(ps, ps->currentInputSource);
 
660
               if(ps->currentInputSource == IS_ADF || ps->currentInputSource == IS_ADF_DUPLEX)
 
661
               {
 
662
                 i = ps->adf_resolutionList[0] + 1;
 
663
                 while(i--) ps->resolutionList[i] = ps->adf_resolutionList[i];
 
664
               }
 
665
               else //if(ps->currentInputSource == IS_PLATEN) 
 
666
               {
 
667
                 i = ps->platen_resolutionList[0] + 1;
 
668
                 while(i--) ps->resolutionList[i] = ps->platen_resolutionList[i];
 
669
               }
 
670
               mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
 
671
               stat = SANE_STATUS_GOOD;
 
672
               break;
 
673
             }
 
674
           }
 
675
         }
 
676
         else
 
677
         {  /* Set default. */
 
678
            ps->currentInputSource = IS_PLATEN;
 
679
            set_input_source_side_effects(ps, ps->currentInputSource);
 
680
            mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
 
681
            stat = SANE_STATUS_GOOD;
 
682
         }
 
683
         break;
 
684
      case SOAP_OPTION_SCAN_RESOLUTION:
 
685
         if (action == SANE_ACTION_GET_VALUE)
 
686
         {
 
687
            *int_value = ps->currentResolution;
 
688
            stat = SANE_STATUS_GOOD;
 
689
         }
 
690
         else if (action == SANE_ACTION_SET_VALUE)
 
691
         {
 
692
            for (i=1; i <= ps->resolutionList[0]; i++)
 
693
            {
 
694
               if (ps->resolutionList[i] == *int_value)
 
695
               {
 
696
                  ps->currentResolution = *int_value;
 
697
                  mset_result |= SANE_INFO_RELOAD_PARAMS;
 
698
                  stat = SANE_STATUS_GOOD;
 
699
                  break;
 
700
               }
 
701
            }
 
702
         }
 
703
         else
 
704
         {  /* Set default. */
 
705
            ps->currentResolution = 75;
 
706
            stat = SANE_STATUS_GOOD;
 
707
         }
 
708
         break;
 
709
      case SOAP_OPTION_CONTRAST:
 
710
         if (action == SANE_ACTION_GET_VALUE)
 
711
         {
 
712
            *int_value = ps->currentContrast;
 
713
            stat = SANE_STATUS_GOOD;
 
714
         }
 
715
         else if (action == SANE_ACTION_SET_VALUE)
 
716
         {
 
717
            if (*int_value >= SOAP_CONTRAST_MIN && *int_value <= SOAP_CONTRAST_MAX)
 
718
            {
 
719
               ps->currentContrast = *int_value;
 
720
               stat = SANE_STATUS_GOOD;
 
721
               break;
 
722
            }
 
723
         }
 
724
         else
 
725
         {  /* Set default. */
 
726
            ps->currentContrast = SOAP_CONTRAST_DEFAULT;
 
727
            stat = SANE_STATUS_GOOD;
 
728
         }
 
729
         break;
 
730
      case SOAP_OPTION_COMPRESSION:
 
731
         if (action == SANE_ACTION_GET_VALUE)
 
732
         {
 
733
            for (i=0; ps->compressionList[i]; i++)
 
734
            {
 
735
               if (ps->currentCompression == ps->compressionMap[i])
 
736
               {
 
737
                  strcpy(value, ps->compressionList[i]);
 
738
                  stat = SANE_STATUS_GOOD;
 
739
                  break;
 
740
               }
 
741
            }
 
742
         }
 
743
         else if (action == SANE_ACTION_SET_VALUE)
 
744
         {
 
745
            for (i=0; ps->compressionList[i]; i++)
 
746
            {
 
747
               if (strcasecmp(ps->compressionList[i], value) == 0)
 
748
               {
 
749
                  ps->currentCompression = ps->compressionMap[i];
 
750
                  stat = SANE_STATUS_GOOD;
 
751
                  break;
 
752
               }
 
753
            }
 
754
         }
 
755
         else
 
756
         {  /* Set default. */
 
757
            ps->currentCompression = SF_JFIF;
 
758
            stat = SANE_STATUS_GOOD;
 
759
         }
 
760
         break;
 
761
      case SOAP_OPTION_JPEG_QUALITY:
 
762
         if (action == SANE_ACTION_GET_VALUE)
 
763
         {
 
764
            *int_value = ps->currentJpegQuality;
 
765
            stat = SANE_STATUS_GOOD;
 
766
         }
 
767
         else if (action == SANE_ACTION_SET_VALUE)
 
768
         {
 
769
            if (*int_value >= MIN_JPEG_COMPRESSION_FACTOR && *int_value <= MAX_JPEG_COMPRESSION_FACTOR)
 
770
            {
 
771
               ps->currentJpegQuality = *int_value;
 
772
               stat = SANE_STATUS_GOOD;
 
773
               break;
 
774
            }
 
775
         }
 
776
         else
 
777
         {  /* Set default. */
 
778
            ps->currentJpegQuality = SAFER_JPEG_COMPRESSION_FACTOR;
 
779
            stat = SANE_STATUS_GOOD;
 
780
         }
 
781
         break;
 
782
      case SOAP_OPTION_TL_X:
 
783
         if (action == SANE_ACTION_GET_VALUE)
 
784
         {
 
785
            *int_value = ps->currentTlx;
 
786
            stat = SANE_STATUS_GOOD;
 
787
         }
 
788
         else if (action == SANE_ACTION_SET_VALUE)
 
789
         {
 
790
            if (*int_value >= ps->tlxRange.min && *int_value <= ps->tlxRange.max)
 
791
            {
 
792
               ps->currentTlx = *int_value;
 
793
               mset_result |= SANE_INFO_RELOAD_PARAMS;
 
794
               stat = SANE_STATUS_GOOD;
 
795
               break;
 
796
            }
 
797
         }
 
798
         else
 
799
         {  /* Set default. */
 
800
            ps->currentTlx = ps->tlxRange.min;
 
801
            stat = SANE_STATUS_GOOD;
 
802
         }
 
803
         break;
 
804
      case SOAP_OPTION_TL_Y:
 
805
         if (action == SANE_ACTION_GET_VALUE)
 
806
         {
 
807
            *int_value = ps->currentTly;
 
808
            stat = SANE_STATUS_GOOD;
 
809
         }
 
810
         else if (action == SANE_ACTION_SET_VALUE)
 
811
         {
 
812
            if (*int_value >= ps->tlyRange.min && *int_value <= ps->tlyRange.max)
 
813
            {
 
814
               
 
815
               ps->currentTly = *int_value;
 
816
               mset_result |= SANE_INFO_RELOAD_PARAMS;
 
817
               stat = SANE_STATUS_GOOD;
 
818
               break;
 
819
            }
 
820
         }
 
821
         else
 
822
         {  /* Set default. */
 
823
            ps->currentTly = ps->tlyRange.min;
 
824
            stat = SANE_STATUS_GOOD;
 
825
         }
 
826
         break;
 
827
      case SOAP_OPTION_BR_X:
 
828
         if (action == SANE_ACTION_GET_VALUE)
 
829
         {
 
830
            *int_value = ps->currentBrx;
 
831
            stat = SANE_STATUS_GOOD;
 
832
         }
 
833
         else if (action == SANE_ACTION_SET_VALUE)
 
834
         {
 
835
            if (*int_value >= ps->brxRange.min && *int_value <= ps->brxRange.max)
 
836
            {
 
837
               ps->currentBrx = *int_value;
 
838
               mset_result |= SANE_INFO_RELOAD_PARAMS;
 
839
               stat = SANE_STATUS_GOOD;
 
840
               break;
 
841
            }
 
842
         }
 
843
         else
 
844
         {  /* Set default. */
 
845
            ps->currentBrx = ps->brxRange.max;
 
846
            stat = SANE_STATUS_GOOD;
 
847
         }
 
848
         break;
 
849
      case SOAP_OPTION_BR_Y:
 
850
         if (action == SANE_ACTION_GET_VALUE)
 
851
         {
 
852
            *int_value = ps->currentBry;
 
853
            stat = SANE_STATUS_GOOD;
 
854
         }
 
855
         else if (action == SANE_ACTION_SET_VALUE)
 
856
         {
 
857
            if (*int_value >= ps->bryRange.min && *int_value <= ps->bryRange.max)
 
858
            {
 
859
               ps->currentBry = *int_value;
 
860
               mset_result |= SANE_INFO_RELOAD_PARAMS;
 
861
               stat = SANE_STATUS_GOOD;
 
862
               break;
 
863
            }
 
864
         }
 
865
         else
 
866
         {  /* Set default. */
 
867
            ps->currentBry = ps->bryRange.max;
 
868
            stat = SANE_STATUS_GOOD;
 
869
         }
 
870
         break;
 
871
      default:
 
872
         break;
 
873
   }
 
874
 
 
875
   if (set_result)
 
876
      *set_result = mset_result;
 
877
 
 
878
   if (stat != SANE_STATUS_GOOD)
 
879
   {
 
880
      BUG("control_option failed: option=%s action=%s\n", ps->option[option].name, 
 
881
                  action==SANE_ACTION_GET_VALUE ? "get" : action==SANE_ACTION_SET_VALUE ? "set" : "auto");
 
882
   }
 
883
 
 
884
   DBG8("sane_hpaio_control_option (option=%s action=%s value=%s)\n", ps->option[option].name, 
 
885
                        action==SANE_ACTION_GET_VALUE ? "get" : action==SANE_ACTION_SET_VALUE ? "set" : "auto",
 
886
     value ? ps->option[option].type == SANE_TYPE_STRING ? (char *)value : psnprintf(sz, sizeof(sz), "%d", *(int *)value) : "na");
 
887
 
 
888
   return stat;
 
889
} /* soapht_control_option */
 
890
 
 
891
SANE_Status soapht_get_parameters(SANE_Handle handle, SANE_Parameters *params)
 
892
{
 
893
   struct soap_session *ps = (struct soap_session *)handle;
 
894
 
 
895
   set_extents(ps);
 
896
 
 
897
   /* Get scan parameters for sane client. */
 
898
   ps->bb_get_parameters(ps, params, ps->ip_handle ? SPO_STARTED : SPO_BEST_GUESS);
 
899
 
 
900
   DBG8("sane_hpaio_get_parameters(): format=%d, last_frame=%d, lines=%d, depth=%d, pixels_per_line=%d, bytes_per_line=%d\n",
 
901
                    params->format, params->last_frame, params->lines, params->depth, params->pixels_per_line, params->bytes_per_line);
 
902
 
 
903
   return SANE_STATUS_GOOD;
 
904
} /* soapht_get_parameters */
 
905
 
 
906
SANE_Status soapht_start(SANE_Handle handle)
 
907
{
 
908
   struct soap_session *ps = (struct soap_session *)handle;
 
909
   SANE_Parameters pp;
 
910
   IP_IMAGE_TRAITS traits;
 
911
   IP_XFORM_SPEC xforms[IP_MAX_XFORMS], *pXform=xforms;
 
912
   int stat, ret;
 
913
 
 
914
   DBG8("sane_hpaio_start()\n");
 
915
   
 
916
    ps -> user_cancel = 0;
 
917
    ps -> cnt = 0;
 
918
    ps -> index = 0;
 
919
  
 
920
   if (set_extents(ps))
 
921
   {
 
922
      BUG("invalid extents: tlx=%d brx=%d tly=%d bry=%d minwidth=%d minheight%d maxwidth=%d maxheight=%d\n",
 
923
         ps->currentTlx, ps->currentTly, ps->currentBrx, ps->currentBry, ps->min_width, ps->min_height, ps->tlxRange.max, ps->tlyRange.max);
 
924
      stat = SANE_STATUS_INVAL;
 
925
      goto bugout;
 
926
   }   
 
927
 
 
928
   /* If input is ADF and ADF is empty, return SANE_STATUS_NO_DOCS. */
 
929
   if (ps->currentInputSource==IS_ADF || ps->currentInputSource==IS_ADF_DUPLEX)
 
930
   {
 
931
      ret = ps->bb_is_paper_in_adf(ps);   /* 0 = no paper in adf, 1 = paper in adf, -1 = error */
 
932
      if (ret == 0)
 
933
      {
 
934
         stat = SANE_STATUS_NO_DOCS;     /* done scanning */
 
935
         SendScanEvent (ps->uri, EVENT_SCAN_ADF_NO_DOCS);
 
936
         goto bugout;
 
937
      }
 
938
      else if (ret < 0)
 
939
      {
 
940
         stat = SANE_STATUS_IO_ERROR;
 
941
         goto bugout;
 
942
      }
 
943
   }
 
944
 
 
945
   /* Start scan and get actual image traits. */
 
946
   if (ps->bb_start_scan(ps))
 
947
   {
 
948
      stat = SANE_STATUS_IO_ERROR;
 
949
      goto bugout;
 
950
   }
 
951
   SendScanEvent(ps->uri, EVENT_START_SCAN_JOB);
 
952
   memset(xforms, 0, sizeof(xforms));    
 
953
 
 
954
   /* Setup image-processing pipeline for xform. */
 
955
   if (ps->currentScanMode == CE_RGB24 || ps->currentScanMode == CE_GRAY8)
 
956
   {
 
957
      switch(ps->currentCompression)
 
958
      {
 
959
         case SF_JFIF:
 
960
            pXform->aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword = 0;    /* 0=no */
 
961
            ADD_XFORM(X_JPG_DECODE);
 
962
            pXform->aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword = IP_CNV_YCC_TO_SRGB;
 
963
            pXform->aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword = 0x00010000;
 
964
            ADD_XFORM(X_CNV_COLOR_SPACE);
 
965
            break;
 
966
         case SF_HPRAW:
 
967
         default:
 
968
            break;
 
969
      }
 
970
   }
 
971
   else
 
972
   {  /* Must be BLACK_AND_WHITE1 (Lineart). */
 
973
      switch(ps->currentCompression)
 
974
      {
 
975
         case SF_JFIF:
 
976
            pXform->aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword = 0;    /* 0=no */
 
977
            ADD_XFORM(X_JPG_DECODE);
 
978
            pXform->aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword = 127;
 
979
            ADD_XFORM(X_GRAY_2_BI);
 
980
            break;
 
981
         case SF_HPRAW:
 
982
            pXform->aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword = 127;
 
983
            ADD_XFORM(X_GRAY_2_BI);
 
984
         default:
 
985
            break;
 
986
      }
 
987
   }
 
988
 
 
989
   /* Setup x/y cropping for xform. (Actually we let cm1017 do it's own cropping) */
 
990
   pXform->aXformInfo[IP_CROP_LEFT].dword = 0;
 
991
   pXform->aXformInfo[IP_CROP_RIGHT].dword = 0;
 
992
   pXform->aXformInfo[IP_CROP_TOP].dword = 0;
 
993
   pXform->aXformInfo[IP_CROP_MAXOUTROWS].dword = 0;
 
994
   ADD_XFORM(X_CROP);
 
995
 
 
996
   /* Setup x/y padding for xform. (Actually we let cm1017 do it's own padding) */
 
997
   pXform->aXformInfo[IP_PAD_LEFT].dword = 0; /* # of pixels to add to left side */
 
998
   pXform->aXformInfo[IP_PAD_RIGHT].dword = 0; /* # of pixels to add to right side */
 
999
   pXform->aXformInfo[IP_PAD_TOP].dword = 0; /* # of rows to add to top */
 
1000
   pXform->aXformInfo[IP_PAD_BOTTOM].dword = 0;  /* # of rows to add to bottom */
 
1001
   pXform->aXformInfo[IP_PAD_VALUE].dword = ps->currentScanMode == CE_BLACK_AND_WHITE1 ? 0 : -1;   /* lineart white = 0, rgb white = -1 */ 
 
1002
   pXform->aXformInfo[IP_PAD_MIN_HEIGHT].dword = 0;
 
1003
   ADD_XFORM(X_PAD);
 
1004
 
 
1005
   /* Open image processor. */
 
1006
   if ((ret = ipOpen(pXform-xforms, xforms, 0, &ps->ip_handle)) != IP_DONE)
 
1007
   {
 
1008
      BUG("unable open image processor: err=%d\n", ret);
 
1009
      stat = SANE_STATUS_INVAL;
 
1010
      goto bugout;
 
1011
   }
 
1012
 
 
1013
   /* Get scan parameters for image processor. */
 
1014
   if (ps->currentCompression == SF_HPRAW)
 
1015
      ps->bb_get_parameters(ps, &pp, SPO_STARTED_JR);     /* hpraw, use actual parameters */
 
1016
   else
 
1017
      ps->bb_get_parameters(ps, &pp, SPO_BEST_GUESS);     /* jpeg, use best guess */
 
1018
   traits.iPixelsPerRow = pp.pixels_per_line;
 
1019
   switch(ps->currentScanMode)
 
1020
   {
 
1021
      case CE_BLACK_AND_WHITE1:         /* lineart (let IP create Mono from Gray8) */
 
1022
      case CE_GRAY8:
 
1023
         traits.iBitsPerPixel = 8;     /* grayscale */
 
1024
         break;
 
1025
      case CE_RGB24:
 
1026
      default:
 
1027
         traits.iBitsPerPixel = 24;      /* color */
 
1028
         break;
 
1029
   }
 
1030
   traits.lHorizDPI = ps->currentResolution << 16;
 
1031
   traits.lVertDPI = ps->currentResolution << 16;
 
1032
   traits.lNumRows =  pp.lines;
 
1033
   traits.iNumPages = 1;
 
1034
   traits.iPageNum = 1;
 
1035
   traits.iComponentsPerPixel = ((traits.iBitsPerPixel % 3) ? 1 : 3);
 
1036
   ipSetDefaultInputTraits(ps->ip_handle, &traits);
 
1037
 
 
1038
   /* If jpeg get output image attributes from the image processor. */
 
1039
   if (ps->currentCompression == SF_JFIF)
 
1040
   {
 
1041
      /* Enable parsed header flag. */
 
1042
      ipResultMask(ps->ip_handle, IP_PARSED_HEADER);
 
1043
 
 
1044
      /* Wait for image processor to process header so we know the exact size of the image for sane_get_params. */
 
1045
      while (1)
 
1046
      {
 
1047
         ret = get_ip_data(ps, NULL, 0, NULL);
 
1048
 
 
1049
         if (ret & (IP_INPUT_ERROR | IP_FATAL_ERROR | IP_DONE))
 
1050
         {
 
1051
            BUG("ipConvert error=%x\n", ret);
 
1052
            stat = SANE_STATUS_IO_ERROR;
 
1053
            goto bugout;
 
1054
         }
 
1055
 
 
1056
         if (ret & IP_PARSED_HEADER)
 
1057
         {
 
1058
            ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits);  /* get valid image traits */
 
1059
            ipResultMask(ps->ip_handle, 0);                          /* disable parsed header flag */
 
1060
            break;
 
1061
         }
 
1062
      }
 
1063
   }
 
1064
   else
 
1065
      ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits);  /* get valid image traits */
 
1066
 
 
1067
   stat = SANE_STATUS_GOOD;
 
1068
 
 
1069
bugout:
 
1070
   if (stat != SANE_STATUS_GOOD)
 
1071
   {
 
1072
      if (ps->ip_handle)
 
1073
      {
 
1074
         ipClose(ps->ip_handle); 
 
1075
         ps->ip_handle = 0;
 
1076
      }   
 
1077
      ps->bb_end_scan(ps, stat == SANE_STATUS_IO_ERROR ? 1: 0);
 
1078
   }
 
1079
 
 
1080
   return stat;
 
1081
} /* soapht_start */
 
1082
 
 
1083
SANE_Status soapht_read(SANE_Handle handle, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length)
 
1084
{
 
1085
   struct soap_session *ps = (struct soap_session *)handle;
 
1086
   int ret, stat=SANE_STATUS_IO_ERROR;
 
1087
 
 
1088
   DBG8("sane_hpaio_read() handle=%p data=%p maxLength=%d\n", (void *)handle, data, maxLength);
 
1089
   if(ps->user_cancel)
 
1090
   {
 
1091
     DBG8("soapht_read() EVENT_SCAN_CANCEL****uri=%s\n", ps->uri);
 
1092
     SendScanEvent(ps->uri, EVENT_SCAN_CANCEL);
 
1093
     return SANE_STATUS_CANCELLED;
 
1094
   }
 
1095
  
 
1096
   ret = get_ip_data(ps, data, maxLength, length);
 
1097
 
 
1098
   if(ret & (IP_INPUT_ERROR | IP_FATAL_ERROR))
 
1099
   {
 
1100
      BUG("ipConvert error=%x\n", ret);
 
1101
      goto bugout;
 
1102
   }
 
1103
 
 
1104
   if (ret & IP_DONE)
 
1105
   {
 
1106
      stat = SANE_STATUS_EOF;
 
1107
      SendScanEvent(ps->uri, EVENT_END_SCAN_JOB);
 
1108
   }
 
1109
   else
 
1110
      stat = SANE_STATUS_GOOD;
 
1111
 
 
1112
bugout:
 
1113
   if (stat != SANE_STATUS_GOOD)
 
1114
   {
 
1115
      if (ps->ip_handle)
 
1116
      {
 
1117
         /* 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. */ 
 
1118
         ipClose(ps->ip_handle);  
 
1119
         ps->ip_handle = 0;
 
1120
      } 
 
1121
      ps->bb_end_page(ps, 0);
 
1122
   }
 
1123
 
 
1124
   DBG8("-sane_hpaio_read() output=%p bytes_read=%d maxLength=%d status=%d\n", data, *length, maxLength, stat);
 
1125
 
 
1126
   return stat;
 
1127
} /* soapht_read */
 
1128
 
 
1129
void soapht_cancel(SANE_Handle handle)
 
1130
{
 
1131
   struct soap_session *ps = (struct soap_session *)handle;
 
1132
 
 
1133
   DBG8("sane_hpaio_cancel()\n"); 
 
1134
 
 
1135
   /*
 
1136
    * Sane_cancel is always called at the end of the scan job. Note that on a multiple page scan job 
 
1137
    * sane_cancel is called only once.
 
1138
    */
 
1139
   ps -> user_cancel = 1;
 
1140
   if (ps->ip_handle)
 
1141
   {
 
1142
      ipClose(ps->ip_handle); 
 
1143
      ps->ip_handle = 0;
 
1144
   }
 
1145
   ps->bb_end_scan(ps, 0);
 
1146
} /* soapht_cancel */
 
1147
 
 
1148
 
 
1149
 
 
1150
 
 
1151