blob: 72574e06772bae2e9c2e66655ffe05901105ed16 [file] [log] [blame]
Shi Quan He6b0720f2002-03-21 02:58:39 +00001/*
2 * Copyright 2000 Corel Corporation
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Shi Quan He6b0720f2002-03-21 02:58:39 +000017 */
18
Steven Edwards14e3b192003-08-22 05:05:56 +000019#define NONAMELESSUNION
20#define NONAMELESSSTRUCT
21
Francois Gouget10adf6b2004-09-13 18:06:46 +000022#include "config.h"
23
Steven Edwards14e3b192003-08-22 05:05:56 +000024#include <stdarg.h>
Jeremy Whiteeae4ac92009-03-05 13:15:06 -060025#include <stdio.h>
26#include <math.h>
Steven Edwards14e3b192003-08-22 05:05:56 +000027
28#include "windef.h"
Shi Quan He6b0720f2002-03-21 02:58:39 +000029#include "winbase.h"
30#include "twain.h"
Marcus Meissner125efed2006-05-08 20:05:42 +020031#include "sane_i.h"
Jeremy White81b28882009-03-06 11:52:33 -060032#include "winnls.h"
Shi Quan He6b0720f2002-03-21 02:58:39 +000033#include "wine/debug.h"
34
35WINE_DEFAULT_DEBUG_CHANNEL(twain);
36
Francois Gouget4dc89872009-03-03 00:16:10 +010037#ifndef SANE_VALUE_SCAN_MODE_COLOR
38#define SANE_VALUE_SCAN_MODE_COLOR SANE_I18N("Color")
39#endif
40#ifndef SANE_VALUE_SCAN_MODE_GRAY
41#define SANE_VALUE_SCAN_MODE_GRAY SANE_I18N("Gray")
42#endif
43#ifndef SANE_VALUE_SCAN_MODE_LINEART
44#define SANE_VALUE_SCAN_MODE_LINEART SANE_I18N("Lineart")
45#endif
46
Jeremy White06399042009-02-05 16:23:29 -060047static TW_UINT16 get_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 *type, TW_UINT32 *value)
48{
49 if (pCapability->hContainer)
50 {
51 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
52 if (pVal)
53 {
54 *value = pVal->Item;
55 if (type)
56 *type = pVal->ItemType;
57 GlobalUnlock (pCapability->hContainer);
58 return TWCC_SUCCESS;
59 }
60 }
61 return TWCC_BUMMER;
62}
63
64
65static TW_UINT16 set_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 type, TW_UINT32 value)
66{
67 pCapability->hContainer = GlobalAlloc (0, sizeof(TW_ONEVALUE));
68
69 if (pCapability->hContainer)
70 {
71 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
72 if (pVal)
73 {
74 pCapability->ConType = TWON_ONEVALUE;
75 pVal->ItemType = type;
76 pVal->Item = value;
77 GlobalUnlock (pCapability->hContainer);
78 return TWCC_SUCCESS;
79 }
80 }
81 return TWCC_LOWMEMORY;
82}
83
84static TW_UINT16 msg_set(pTW_CAPABILITY pCapability, TW_UINT32 *val)
85{
86 if (pCapability->ConType == TWON_ONEVALUE)
87 return get_onevalue(pCapability, NULL, val);
88
89 FIXME("Partial Stub: MSG_SET only supports TW_ONEVALUE\n");
90 return TWCC_BADCAP;
91}
92
93
94static TW_UINT16 msg_get_enum(pTW_CAPABILITY pCapability, const TW_UINT32 *values, int value_count,
95 TW_UINT16 type, TW_UINT32 current, TW_UINT32 default_value)
96{
97 TW_ENUMERATION *enumv = NULL;
98 TW_UINT32 *p32;
99 TW_UINT16 *p16;
100 int i;
101
102 pCapability->ConType = TWON_ENUMERATION;
103 pCapability->hContainer = 0;
104
105 if (type == TWTY_INT16 || type == TWTY_UINT16)
106 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT16)]));
107
108 if (type == TWTY_INT32 || type == TWTY_UINT32)
109 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT32)]));
110
111 if (pCapability->hContainer)
112 enumv = GlobalLock(pCapability->hContainer);
113
114 if (! enumv)
115 return TWCC_LOWMEMORY;
116
117 enumv->ItemType = type;
118 enumv->NumItems = value_count;
119
120 p16 = (TW_UINT16 *) enumv->ItemList;
121 p32 = (TW_UINT32 *) enumv->ItemList;
122 for (i = 0; i < value_count; i++)
123 {
124 if (values[i] == current)
125 enumv->CurrentIndex = i;
126 if (values[i] == default_value)
127 enumv->DefaultIndex = i;
128 if (type == TWTY_INT16 || type == TWTY_UINT16)
129 p16[i] = values[i];
130 if (type == TWTY_INT32 || type == TWTY_UINT32)
131 p32[i] = values[i];
132 }
133
134 GlobalUnlock(pCapability->hContainer);
135 return TWCC_SUCCESS;
136}
137
Jeremy White6ace7992009-02-23 16:25:26 -0600138#ifdef SONAME_LIBSANE
139static TW_UINT16 msg_get_range(pTW_CAPABILITY pCapability, TW_UINT16 type,
140 TW_UINT32 minval, TW_UINT32 maxval, TW_UINT32 step, TW_UINT32 def, TW_UINT32 current)
141{
142 TW_RANGE *range = NULL;
143
144 pCapability->ConType = TWON_RANGE;
145 pCapability->hContainer = 0;
146
147 pCapability->hContainer = GlobalAlloc (0, sizeof(*range));
148 if (pCapability->hContainer)
149 range = GlobalLock(pCapability->hContainer);
150
151 if (! range)
152 return TWCC_LOWMEMORY;
153
154 range->ItemType = type;
155 range->MinValue = minval;
156 range->MaxValue = maxval;
157 range->StepSize = step;
158 range->DefaultValue = def;
159 range->CurrentValue = current;
160
161 GlobalUnlock(pCapability->hContainer);
162 return TWCC_SUCCESS;
163}
164#endif
165
Jeremy Whitee93c14f2009-01-28 08:52:56 -0600166static TW_UINT16 TWAIN_GetSupportedCaps(pTW_CAPABILITY pCapability)
167{
168 TW_ARRAY *a;
Jeremy White63202662009-02-09 13:01:39 -0600169 static const UINT16 supported_caps[] = { CAP_SUPPORTEDCAPS, CAP_XFERCOUNT, CAP_UICONTROLLABLE,
Jeremy White28b708c2009-03-05 13:15:20 -0600170 CAP_AUTOFEED, CAP_FEEDERENABLED,
Jeremy Whitef75b5eb2009-02-25 20:58:34 -0600171 ICAP_XFERMECH, ICAP_PIXELTYPE, ICAP_UNITS, ICAP_BITDEPTH, ICAP_COMPRESSION, ICAP_PIXELFLAVOR,
Jeremy White81b28882009-03-06 11:52:33 -0600172 ICAP_XRESOLUTION, ICAP_YRESOLUTION, ICAP_PHYSICALHEIGHT, ICAP_PHYSICALWIDTH, ICAP_SUPPORTEDSIZES };
Jeremy Whitee93c14f2009-01-28 08:52:56 -0600173
174 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY, ItemList[sizeof(supported_caps)] ));
175 pCapability->ConType = TWON_ARRAY;
176
177 if (pCapability->hContainer)
178 {
179 UINT16 *u;
180 int i;
181 a = GlobalLock (pCapability->hContainer);
182 a->ItemType = TWTY_UINT16;
183 a->NumItems = sizeof(supported_caps) / sizeof(supported_caps[0]);
184 u = (UINT16 *) a->ItemList;
185 for (i = 0; i < a->NumItems; i++)
186 u[i] = supported_caps[i];
187 GlobalUnlock (pCapability->hContainer);
188 return TWCC_SUCCESS;
189 }
190 else
191 return TWCC_LOWMEMORY;
192}
193
194
Shi Quan He6b0720f2002-03-21 02:58:39 +0000195/* ICAP_XFERMECH */
Alexandre Julliard5a2a9142008-12-02 15:25:29 +0100196static TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action)
Vincent Béron9a624912002-05-31 23:06:46 +0000197{
Jeremy White06399042009-02-05 16:23:29 -0600198 static const TW_UINT32 possible_values[] = { TWSX_NATIVE, TWSX_MEMORY };
199 TW_UINT32 val;
200 TW_UINT16 twCC = TWCC_BADCAP;
201
Shi Quan He6b0720f2002-03-21 02:58:39 +0000202 TRACE("ICAP_XFERMECH\n");
203
204 switch (action)
205 {
Jeremy White06399042009-02-05 16:23:29 -0600206 case MSG_QUERYSUPPORT:
207 twCC = set_onevalue(pCapability, TWTY_INT32,
208 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
Shi Quan He6b0720f2002-03-21 02:58:39 +0000209 break;
Shi Quan He6b0720f2002-03-21 02:58:39 +0000210
Jeremy White06399042009-02-05 16:23:29 -0600211 case MSG_GET:
212 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
213 TWTY_UINT16, activeDS.capXferMech, TWSX_NATIVE);
214 break;
215
216 case MSG_SET:
217 twCC = msg_set(pCapability, &val);
218 if (twCC == TWCC_SUCCESS)
219 {
220 activeDS.capXferMech = (TW_UINT16) val;
221 FIXME("Partial Stub: XFERMECH set to %d, but ignored\n", val);
Shi Quan He6b0720f2002-03-21 02:58:39 +0000222 }
223 break;
Jeremy White06399042009-02-05 16:23:29 -0600224
Shi Quan He6b0720f2002-03-21 02:58:39 +0000225 case MSG_GETDEFAULT:
Jeremy White06399042009-02-05 16:23:29 -0600226 twCC = set_onevalue(pCapability, TWTY_UINT16, TWSX_NATIVE);
Shi Quan He6b0720f2002-03-21 02:58:39 +0000227 break;
Jeremy White06399042009-02-05 16:23:29 -0600228
Shi Quan He6b0720f2002-03-21 02:58:39 +0000229 case MSG_RESET:
Marcus Meissner125efed2006-05-08 20:05:42 +0200230 activeDS.capXferMech = TWSX_NATIVE;
Jeremy White06399042009-02-05 16:23:29 -0600231 /* .. fall through intentional .. */
232
233 case MSG_GETCURRENT:
234 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capXferMech);
235 FIXME("Partial Stub: XFERMECH of %d not actually used\n", activeDS.capXferMech);
Shi Quan He6b0720f2002-03-21 02:58:39 +0000236 break;
237 }
Jeremy White06399042009-02-05 16:23:29 -0600238 return twCC;
Shi Quan He6b0720f2002-03-21 02:58:39 +0000239}
Jeremy White25d59532009-02-09 13:00:47 -0600240
241
Jeremy White333ef6a2009-02-09 13:00:57 -0600242/* CAP_XFERCOUNT */
243static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action)
244{
245 TW_UINT32 val;
246 TW_UINT16 twCC = TWCC_BADCAP;
247
248 TRACE("CAP_XFERCOUNT\n");
249
250 switch (action)
251 {
252 case MSG_QUERYSUPPORT:
253 twCC = set_onevalue(pCapability, TWTY_INT32,
254 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
255 break;
256
257 case MSG_GET:
258 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
259 FIXME("Partial Stub: Reporting only support for transfer all\n");
260 break;
261
262 case MSG_SET:
263 twCC = msg_set(pCapability, &val);
264 if (twCC == TWCC_SUCCESS)
265 FIXME("Partial Stub: XFERCOUNT set to %d, but ignored\n", val);
266 break;
267
268 case MSG_GETDEFAULT:
269 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
270 break;
271
272 case MSG_RESET:
273 /* .. fall through intentional .. */
274
275 case MSG_GETCURRENT:
276 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
277 break;
278 }
279 return twCC;
280}
281
Jeremy White00f9ef02009-02-25 20:58:42 -0600282#ifdef SONAME_LIBSANE
283static BOOL pixeltype_to_sane_mode(TW_UINT16 pixeltype, SANE_String mode, int len)
284{
285 SANE_String_Const m = NULL;
286 switch (pixeltype)
287 {
288 case TWPT_GRAY:
289 m = SANE_VALUE_SCAN_MODE_GRAY;
290 break;
291 case TWPT_RGB:
292 m = SANE_VALUE_SCAN_MODE_COLOR;
293 break;
294 case TWPT_BW:
295 m = SANE_VALUE_SCAN_MODE_LINEART;
296 break;
297 }
298 if (! m)
299 return FALSE;
300 if (strlen(m) >= len)
301 return FALSE;
302 strcpy(mode, m);
303 return TRUE;
304}
305static BOOL sane_mode_to_pixeltype(SANE_String_Const mode, TW_UINT16 *pixeltype)
306{
307 if (strcmp(mode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
308 *pixeltype = TWPT_BW;
309 else if (memcmp(mode, SANE_VALUE_SCAN_MODE_GRAY, strlen(SANE_VALUE_SCAN_MODE_GRAY)) == 0)
310 *pixeltype = TWPT_GRAY;
311 else if (strcmp(mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
312 *pixeltype = TWPT_RGB;
313 else
314 return FALSE;
315
316 return TRUE;
317}
318
319static TW_UINT16 sane_status_to_twcc(SANE_Status rc)
320{
321 switch (rc)
322 {
323 case SANE_STATUS_GOOD:
324 return TWCC_SUCCESS;
325 case SANE_STATUS_UNSUPPORTED:
326 return TWCC_CAPUNSUPPORTED;
327 case SANE_STATUS_JAMMED:
328 return TWCC_PAPERJAM;
329 case SANE_STATUS_NO_MEM:
330 return TWCC_LOWMEMORY;
331 case SANE_STATUS_ACCESS_DENIED:
332 return TWCC_DENIED;
333
334 case SANE_STATUS_IO_ERROR:
335 case SANE_STATUS_NO_DOCS:
336 case SANE_STATUS_COVER_OPEN:
337 case SANE_STATUS_EOF:
338 case SANE_STATUS_INVAL:
339 case SANE_STATUS_CANCELLED:
340 case SANE_STATUS_DEVICE_BUSY:
341 default:
342 return TWCC_BUMMER;
343 }
344}
345#endif
346
Jeremy White272c1882009-02-09 13:01:27 -0600347/* ICAP_PIXELTYPE */
348static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 action)
349{
Jeremy White272c1882009-02-09 13:01:27 -0600350 TW_UINT16 twCC = TWCC_BADCAP;
Jeremy White00f9ef02009-02-25 20:58:42 -0600351#ifdef SONAME_LIBSANE
352 TW_UINT32 possible_values[3];
353 int possible_value_count;
354 TW_UINT32 val;
355 SANE_Status rc;
356 SANE_Int status;
357 SANE_String_Const *choices;
358 char current_mode[64];
359 TW_UINT16 current_pixeltype = TWPT_BW;
360 SANE_Char mode[64];
Jeremy White272c1882009-02-09 13:01:27 -0600361
362 TRACE("ICAP_PIXELTYPE\n");
363
Jeremy White00f9ef02009-02-25 20:58:42 -0600364 rc = sane_option_probe_mode(activeDS.deviceHandle, &choices, current_mode, sizeof(current_mode));
365 if (rc != SANE_STATUS_GOOD)
366 {
367 ERR("Unable to retrieve mode from sane, ICAP_PIXELTYPE unsupported\n");
368 return twCC;
369 }
370
371 sane_mode_to_pixeltype(current_mode, &current_pixeltype);
372
373 /* Sane does not support a concept of a default mode, so we simply cache
374 * the first mode we find */
375 if (! activeDS.PixelTypeSet)
376 {
377 activeDS.PixelTypeSet = TRUE;
378 activeDS.defaultPixelType = current_pixeltype;
379 }
380
Jeremy White272c1882009-02-09 13:01:27 -0600381 switch (action)
382 {
383 case MSG_QUERYSUPPORT:
384 twCC = set_onevalue(pCapability, TWTY_INT32,
385 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
386 break;
387
388 case MSG_GET:
Jeremy White00f9ef02009-02-25 20:58:42 -0600389 for (possible_value_count = 0; choices && *choices && possible_value_count < 3; choices++)
390 {
391 TW_UINT16 pix;
392 if (sane_mode_to_pixeltype(*choices, &pix))
393 possible_values[possible_value_count++] = pix;
394 }
395 twCC = msg_get_enum(pCapability, possible_values, possible_value_count,
396 TWTY_UINT16, current_pixeltype, activeDS.defaultPixelType);
Jeremy White272c1882009-02-09 13:01:27 -0600397 break;
398
399 case MSG_SET:
400 twCC = msg_set(pCapability, &val);
401 if (twCC == TWCC_SUCCESS)
402 {
Jeremy White1d58b7e2009-03-02 16:48:10 -0600403 TRACE("Setting pixeltype to %d\n", val);
Jeremy White00f9ef02009-02-25 20:58:42 -0600404 if (! pixeltype_to_sane_mode(val, mode, sizeof(mode)))
405 return TWCC_BADVALUE;
406
407 status = 0;
408 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
409 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
410 if (rc == SANE_STATUS_INVAL && strcmp(mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
411 {
412 strcpy(mode, "Grayscale");
413 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
414 }
415 if (rc != SANE_STATUS_GOOD)
416 return sane_status_to_twcc(rc);
417 if (status & SANE_INFO_RELOAD_PARAMS)
418 psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
Jeremy White272c1882009-02-09 13:01:27 -0600419 }
420 break;
421
422 case MSG_GETDEFAULT:
Jeremy White00f9ef02009-02-25 20:58:42 -0600423 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.defaultPixelType);
Jeremy White272c1882009-02-09 13:01:27 -0600424 break;
425
426 case MSG_RESET:
Jeremy White00f9ef02009-02-25 20:58:42 -0600427 current_pixeltype = activeDS.defaultPixelType;
428 if (! pixeltype_to_sane_mode(current_pixeltype, mode, sizeof(mode)))
429 return TWCC_BADVALUE;
430
431 status = 0;
432 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
433 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
434 if (rc == SANE_STATUS_INVAL && strcmp(mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
435 {
436 strcpy(mode, "Grayscale");
437 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
438 }
439 if (rc != SANE_STATUS_GOOD)
440 return sane_status_to_twcc(rc);
441 if (status & SANE_INFO_RELOAD_PARAMS)
442 psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
443
Jeremy White272c1882009-02-09 13:01:27 -0600444 /* .. fall through intentional .. */
445
446 case MSG_GETCURRENT:
Jeremy White00f9ef02009-02-25 20:58:42 -0600447 twCC = set_onevalue(pCapability, TWTY_UINT16, current_pixeltype);
Jeremy White1d58b7e2009-03-02 16:48:10 -0600448 TRACE("Returning current pixeltype of %d\n", current_pixeltype);
Jeremy White272c1882009-02-09 13:01:27 -0600449 break;
450 }
451
Jeremy White00f9ef02009-02-25 20:58:42 -0600452#endif
Jeremy White272c1882009-02-09 13:01:27 -0600453 return twCC;
454}
455
Jeremy Whitef75b5eb2009-02-25 20:58:34 -0600456/* ICAP_UNITS */
457static TW_UINT16 SANE_ICAPUnits (pTW_CAPABILITY pCapability, TW_UINT16 action)
458{
459 TW_UINT32 val;
460 TW_UINT16 twCC = TWCC_BADCAP;
461
462 TRACE("ICAP_UNITS\n");
463
464 switch (action)
465 {
466 case MSG_QUERYSUPPORT:
467 twCC = set_onevalue(pCapability, TWTY_INT32,
468 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
469 break;
470
471 case MSG_GET:
472 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
473 break;
474
475 case MSG_SET:
476 twCC = msg_set(pCapability, &val);
477 if (twCC == TWCC_SUCCESS)
478 {
479 if (val != TWUN_INCHES)
480 {
481 ERR("Sane supports only SANE_UNIT_DPI\n");
482 twCC = TWCC_BADVALUE;
483 }
484 }
485 break;
486
487 case MSG_GETDEFAULT:
488 case MSG_RESET:
489 /* .. fall through intentional .. */
490
491 case MSG_GETCURRENT:
492 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
493 break;
494 }
495
496 return twCC;
497}
498
Jeremy White982482e2009-02-25 20:58:25 -0600499/* ICAP_BITDEPTH */
500static TW_UINT16 SANE_ICAPBitDepth(pTW_CAPABILITY pCapability, TW_UINT16 action)
501{
502 TW_UINT16 twCC = TWCC_BADCAP;
503#ifdef SONAME_LIBSANE
504 TW_UINT32 possible_values[1];
505
506 TRACE("ICAP_BITDEPTH\n");
507
508 possible_values[0] = activeDS.sane_param.depth;
509
510 switch (action)
511 {
512 case MSG_QUERYSUPPORT:
513 twCC = set_onevalue(pCapability, TWTY_INT32,
514 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
515 break;
516
517 case MSG_GET:
518 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
519 TWTY_UINT16, activeDS.sane_param.depth, activeDS.sane_param.depth);
520 break;
521
522 case MSG_GETDEFAULT:
523 /* .. Fall through intentional .. */
524
525 case MSG_GETCURRENT:
Jeremy White1d58b7e2009-03-02 16:48:10 -0600526 TRACE("Returning current bitdepth of %d\n", activeDS.sane_param.depth);
Jeremy White982482e2009-02-25 20:58:25 -0600527 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.sane_param.depth);
528 break;
529 }
530#endif
531 return twCC;
532}
533
Jeremy White63202662009-02-09 13:01:39 -0600534/* CAP_UICONTROLLABLE */
535static TW_UINT16 SANE_CAPUiControllable(pTW_CAPABILITY pCapability, TW_UINT16 action)
536{
537 TW_UINT16 twCC = TWCC_BADCAP;
538
539 TRACE("CAP_UICONTROLLABLE\n");
540
541 switch (action)
542 {
543 case MSG_QUERYSUPPORT:
544 twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET);
545 break;
546
547 case MSG_GET:
548 twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
549 break;
550
551 }
552 return twCC;
553}
554
Jeremy Whiteb0ec8882009-02-09 13:02:05 -0600555/* ICAP_COMPRESSION */
556static TW_UINT16 SANE_ICAPCompression (pTW_CAPABILITY pCapability, TW_UINT16 action)
557{
558 static const TW_UINT32 possible_values[] = { TWCP_NONE };
559 TW_UINT32 val;
560 TW_UINT16 twCC = TWCC_BADCAP;
561
562 TRACE("ICAP_COMPRESSION\n");
563
564 switch (action)
565 {
566 case MSG_QUERYSUPPORT:
567 twCC = set_onevalue(pCapability, TWTY_INT32,
568 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
569 break;
570
571 case MSG_GET:
572 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
573 TWTY_UINT16, TWCP_NONE, TWCP_NONE);
574 FIXME("Partial stub: We don't attempt to support compression\n");
575 break;
576
577 case MSG_SET:
578 twCC = msg_set(pCapability, &val);
579 if (twCC == TWCC_SUCCESS)
580 FIXME("Partial Stub: COMPRESSION set to %d, but ignored\n", val);
581 break;
582
583 case MSG_GETDEFAULT:
584 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
585 break;
586
587 case MSG_RESET:
588 /* .. fall through intentional .. */
589
590 case MSG_GETCURRENT:
591 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
592 break;
593 }
594 return twCC;
595}
596
Jeremy White6ace7992009-02-23 16:25:26 -0600597/* ICAP_XRESOLUTION, ICAP_YRESOLUTION */
598static TW_UINT16 SANE_ICAPResolution (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
599{
600 TW_UINT16 twCC = TWCC_BADCAP;
601#ifdef SONAME_LIBSANE
602 TW_UINT32 val;
603 SANE_Int current_resolution;
604 TW_FIX32 *default_res;
605 const char *best_option_name;
606 SANE_Int minval, maxval, quantval;
607 SANE_Status sane_rc;
608 SANE_Int set_status;
609
610 TRACE("ICAP_%cRESOLUTION\n", cap == ICAP_XRESOLUTION ? 'X' : 'Y');
611
612 /* Some scanners support 'x-resolution', most seem to just support 'resolution' */
613 if (cap == ICAP_XRESOLUTION)
614 {
615 best_option_name = "x-resolution";
616 default_res = &activeDS.defaultXResolution;
617 }
618 else
619 {
620 best_option_name = "y-resolution";
621 default_res = &activeDS.defaultYResolution;
622 }
623 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, &current_resolution) != SANE_STATUS_GOOD)
624 {
625 best_option_name = "resolution";
626 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, &current_resolution) != SANE_STATUS_GOOD)
627 return TWCC_BADCAP;
628 }
629
630 /* Sane does not support a concept of 'default' resolution, so we have to
631 * cache the resolution the very first time we load the scanner, and use that
632 * as the default */
633 if (cap == ICAP_XRESOLUTION && ! activeDS.XResolutionSet)
634 {
635 default_res->Whole = current_resolution;
636 default_res->Frac = 0;
637 activeDS.XResolutionSet = TRUE;
638 }
639
640 if (cap == ICAP_YRESOLUTION && ! activeDS.YResolutionSet)
641 {
642 default_res->Whole = current_resolution;
643 default_res->Frac = 0;
644 activeDS.YResolutionSet = TRUE;
645 }
646
647 switch (action)
648 {
649 case MSG_QUERYSUPPORT:
650 twCC = set_onevalue(pCapability, TWTY_INT32,
651 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
652 break;
653
654 case MSG_GET:
655 sane_rc = sane_option_probe_resolution(activeDS.deviceHandle, best_option_name, &minval, &maxval, &quantval);
656 if (sane_rc != SANE_STATUS_GOOD)
657 twCC = TWCC_BADCAP;
658 else
659 twCC = msg_get_range(pCapability, TWTY_FIX32,
660 minval, maxval, quantval == 0 ? 1 : quantval, default_res->Whole, current_resolution);
661 break;
662
663 case MSG_SET:
664 twCC = msg_set(pCapability, &val);
665 if (twCC == TWCC_SUCCESS)
666 {
667 TW_FIX32 f32;
668 memcpy(&f32, &val, sizeof(f32));
669 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, f32.Whole, &set_status);
670 if (sane_rc != SANE_STATUS_GOOD)
671 {
672 FIXME("Status of %d not expected or handled\n", sane_rc);
673 twCC = TWCC_BADCAP;
674 }
675 else if (set_status == SANE_INFO_INEXACT)
676 twCC = TWCC_CHECKSTATUS;
677 }
678 break;
679
680 case MSG_GETDEFAULT:
681 twCC = set_onevalue(pCapability, TWTY_FIX32, default_res->Whole);
682 break;
683
684 case MSG_RESET:
685 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, default_res->Whole, NULL);
686 if (sane_rc != SANE_STATUS_GOOD)
687 return TWCC_BADCAP;
688
689 /* .. fall through intentional .. */
690
691 case MSG_GETCURRENT:
692 twCC = set_onevalue(pCapability, TWTY_FIX32, current_resolution);
693 break;
694 }
695#endif
696 return twCC;
697}
698
Jeremy Whitee472c492009-03-05 13:25:58 -0600699#ifdef SONAME_LIBSANE
Jeremy Whiteeae4ac92009-03-05 13:15:06 -0600700static void convert_double_fix32(double d, TW_FIX32 *fix32)
701{
702 TW_INT32 value = (TW_INT32) (d * 65536.0 + 0.5);
703 fix32->Whole = value >> 16;
704 fix32->Frac = value & 0x0000ffffL;
705}
706
Jeremy Whiteeae4ac92009-03-05 13:15:06 -0600707static BOOL convert_sane_res_to_twain(double sane_res, SANE_Unit unit, TW_FIX32 *twain_res, TW_UINT16 twtype)
708{
709 double d;
710
711 if (unit != SANE_UNIT_MM)
712 return FALSE;
713
714 if (twtype != TWUN_INCHES)
715 return FALSE;
716
717 d = (sane_res / 10.0) / 2.54;
718 convert_double_fix32((sane_res / 10.0) / 2.54, twain_res);
719
720 return TRUE;
721}
722#endif
723
724/* ICAP_PHYSICALHEIGHT, ICAP_PHYSICALWIDTH */
725static TW_UINT16 SANE_ICAPPhysical (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
726{
727 TW_UINT16 twCC = TWCC_BADCAP;
728#ifdef SONAME_LIBSANE
729 TW_FIX32 res;
730 char option_name[64];
731 SANE_Fixed lower, upper;
732 SANE_Unit lowerunit, upperunit;
733 SANE_Status status;
734
735 TRACE("ICAP_PHYSICAL%s\n", cap == ICAP_PHYSICALHEIGHT? "HEIGHT" : "WIDTH");
736
737 sprintf(option_name, "tl-%c", cap == ICAP_PHYSICALHEIGHT ? 'y' : 'x');
738 status = sane_option_probe_scan_area(activeDS.deviceHandle, option_name, NULL, &lowerunit, &lower, NULL, NULL);
739 if (status != SANE_STATUS_GOOD)
740 return sane_status_to_twcc(status);
741
742 sprintf(option_name, "br-%c", cap == ICAP_PHYSICALHEIGHT ? 'y' : 'x');
743 status = sane_option_probe_scan_area(activeDS.deviceHandle, option_name, NULL, &upperunit, NULL, &upper, NULL);
744 if (status != SANE_STATUS_GOOD)
745 return sane_status_to_twcc(status);
746
747 if (upperunit != lowerunit)
748 return TWCC_BADCAP;
749
750 if (! convert_sane_res_to_twain(SANE_UNFIX(upper) - SANE_UNFIX(lower), upperunit, &res, TWUN_INCHES))
751 return TWCC_BADCAP;
752
753 switch (action)
754 {
755 case MSG_QUERYSUPPORT:
756 twCC = set_onevalue(pCapability, TWTY_INT32,
757 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
758 break;
759
760 case MSG_GET:
761 case MSG_GETDEFAULT:
762
763 /* .. fall through intentional .. */
764
765 case MSG_GETCURRENT:
766 twCC = set_onevalue(pCapability, TWTY_FIX32, res.Whole | (res.Frac << 16));
767 break;
768 }
769#endif
770 return twCC;
771}
772
Jeremy White9bb24b82009-02-13 13:14:45 -0600773/* ICAP_PIXELFLAVOR */
774static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action)
775{
Jeremy White2c0fea92009-03-02 17:08:11 -0600776 TW_UINT16 twCC = TWCC_BADCAP;
777#ifdef SONAME_LIBSANE
Jeremy White9bb24b82009-02-13 13:14:45 -0600778 static const TW_UINT32 possible_values[] = { TWPF_CHOCOLATE, TWPF_VANILLA };
779 TW_UINT32 val;
Jeremy White2c0fea92009-03-02 17:08:11 -0600780 TW_UINT32 flavor = activeDS.sane_param.depth == 1 ? TWPF_VANILLA : TWPF_CHOCOLATE;
Jeremy White9bb24b82009-02-13 13:14:45 -0600781
782 TRACE("ICAP_PIXELFLAVOR\n");
783
784 switch (action)
785 {
786 case MSG_QUERYSUPPORT:
787 twCC = set_onevalue(pCapability, TWTY_INT32,
788 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
789 break;
790
791 case MSG_GET:
792 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
Jeremy White2c0fea92009-03-02 17:08:11 -0600793 TWTY_UINT16, flavor, flavor);
Jeremy White9bb24b82009-02-13 13:14:45 -0600794 break;
795
796 case MSG_SET:
797 twCC = msg_set(pCapability, &val);
798 if (twCC == TWCC_SUCCESS)
799 {
800 FIXME("Stub: PIXELFLAVOR set to %d, but ignored\n", val);
801 }
802 break;
803
804 case MSG_GETDEFAULT:
Jeremy White2c0fea92009-03-02 17:08:11 -0600805 twCC = set_onevalue(pCapability, TWTY_UINT16, flavor);
Jeremy White9bb24b82009-02-13 13:14:45 -0600806 break;
807
808 case MSG_RESET:
809 /* .. fall through intentional .. */
810
811 case MSG_GETCURRENT:
Jeremy White2c0fea92009-03-02 17:08:11 -0600812 twCC = set_onevalue(pCapability, TWTY_UINT16, flavor);
Jeremy White9bb24b82009-02-13 13:14:45 -0600813 break;
814 }
Jeremy White2c0fea92009-03-02 17:08:11 -0600815#endif
Jeremy White9bb24b82009-02-13 13:14:45 -0600816 return twCC;
817}
818
Jeremy White81b28882009-03-06 11:52:33 -0600819#ifdef SONAME_LIBSANE
820static TW_UINT16 get_width_height(double *width, double *height, BOOL max)
821{
822 SANE_Status status;
823
824 SANE_Fixed tlx_current, tlx_min, tlx_max;
825 SANE_Fixed tly_current, tly_min, tly_max;
826 SANE_Fixed brx_current, brx_min, brx_max;
827 SANE_Fixed bry_current, bry_min, bry_max;
828
829 status = sane_option_probe_scan_area(activeDS.deviceHandle, "tl-x", &tlx_current, NULL, &tlx_min, &tlx_max, NULL);
830 if (status != SANE_STATUS_GOOD)
831 return sane_status_to_twcc(status);
832
833 status = sane_option_probe_scan_area(activeDS.deviceHandle, "tl-y", &tly_current, NULL, &tly_min, &tly_max, NULL);
834 if (status != SANE_STATUS_GOOD)
835 return sane_status_to_twcc(status);
836
837 status = sane_option_probe_scan_area(activeDS.deviceHandle, "br-x", &brx_current, NULL, &brx_min, &brx_max, NULL);
838 if (status != SANE_STATUS_GOOD)
839 return sane_status_to_twcc(status);
840
841 status = sane_option_probe_scan_area(activeDS.deviceHandle, "br-y", &bry_current, NULL, &bry_min, &bry_max, NULL);
842 if (status != SANE_STATUS_GOOD)
843 return sane_status_to_twcc(status);
844
845 if (max)
846 *width = SANE_UNFIX(brx_max) - SANE_UNFIX(tlx_min);
847 else
848 *width = SANE_UNFIX(brx_current) - SANE_UNFIX(tlx_current);
849
850 if (max)
851 *height = SANE_UNFIX(bry_max) - SANE_UNFIX(tly_min);
852 else
853 *height = SANE_UNFIX(bry_current) - SANE_UNFIX(tly_current);
854
855 return(TWCC_SUCCESS);
856}
857
858static TW_UINT16 set_one_coord(const char *name, double coord)
859{
860 SANE_Status status;
861 status = sane_option_set_fixed(activeDS.deviceHandle, name, SANE_FIX(coord), NULL);
862 if (status != SANE_STATUS_GOOD)
863 return sane_status_to_twcc(status);
864 return TWCC_SUCCESS;
865}
866
867static TW_UINT16 set_width_height(double width, double height)
868{
869 TW_UINT16 rc = TWCC_SUCCESS;
870 rc = set_one_coord("tl-x", 0);
871 if (rc != TWCC_SUCCESS)
872 return rc;
873 rc = set_one_coord("br-x", width);
874 if (rc != TWCC_SUCCESS)
875 return rc;
876 rc = set_one_coord("tl-y", 0);
877 if (rc != TWCC_SUCCESS)
878 return rc;
879 rc = set_one_coord("br-y", height);
880
881 return rc;
882}
883
884typedef struct
885{
886 TW_UINT32 size;
887 double x;
888 double y;
889} supported_size_t;
890
891static const supported_size_t supported_sizes[] =
892{
893 { TWSS_NONE, 0, 0 },
894 { TWSS_A4, 210, 297 },
895 { TWSS_JISB5, 182, 257 },
896 { TWSS_USLETTER, 215.9, 279.4 },
897 { TWSS_USLEGAL, 215.9, 355.6 },
898 { TWSS_A5, 148, 210 },
899 { TWSS_B4, 250, 353 },
900 { TWSS_B6, 125, 176 },
901 { TWSS_USLEDGER, 215.9, 431.8 },
902 { TWSS_USEXECUTIVE, 184.15, 266.7 },
903 { TWSS_A3, 297, 420 },
904};
905#define SUPPORTED_SIZE_COUNT (sizeof(supported_sizes) / sizeof(supported_sizes[0]))
906
907static TW_UINT16 get_default_paper_size(const supported_size_t *s, int n)
908{
909 DWORD paper;
910 int rc;
911 int defsize = -1;
912 double width, height;
913 int i;
914 rc = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE | LOCALE_RETURN_NUMBER, (void *) &paper, sizeof(paper));
915 if (rc > 0)
916 switch (paper)
917 {
918 case 1:
919 defsize = TWSS_USLETTER;
920 break;
921 case 5:
922 defsize = TWSS_USLEGAL;
923 break;
924 case 8:
925 defsize = TWSS_A3;
926 break;
927 case 9:
928 defsize = TWSS_A4;
929 break;
930 }
931
932 if (defsize == -1)
933 return TWSS_NONE;
934
935 if (get_width_height(&width, &height, TRUE) != TWCC_SUCCESS)
936 return TWSS_NONE;
937
938 for (i = 0; i < n; i++)
939 if (s[i].size == defsize)
940 {
941 /* Sane's use of integers to store floats is a hair lossy; deal with it */
942 if (s[i].x > (width + .01) || s[i].y > (height + 0.01))
943 return TWSS_NONE;
944 else
945 return s[i].size;
946 }
947
948 return TWSS_NONE;
949}
950
951static TW_UINT16 get_current_paper_size(const supported_size_t *s, int n)
952{
953 int i;
954 double width, height;
955 double xdelta, ydelta;
956
957 if (get_width_height(&width, &height, FALSE) != TWCC_SUCCESS)
958 return TWSS_NONE;
959
960 for (i = 0; i < n; i++)
961 {
962 /* Sane's use of integers to store floats results
963 * in a very small error; cope with that */
964 xdelta = s[i].x - width;
965 ydelta = s[i].y - height;
966 if (xdelta < 0.01 && xdelta > -0.01 &&
967 ydelta < 0.01 && ydelta > -0.01)
968 return s[i].size;
969 }
970
971 return TWSS_NONE;
972}
973#endif
974
975/* ICAP_SUPPORTEDSIZES */
976static TW_UINT16 SANE_ICAPSupportedSizes (pTW_CAPABILITY pCapability, TW_UINT16 action)
977{
978 TW_UINT16 twCC = TWCC_BADCAP;
979#ifdef SONAME_LIBSANE
980
981 static TW_UINT32 possible_values[SUPPORTED_SIZE_COUNT];
982 int i;
983 TW_UINT32 val;
984 TW_UINT16 default_size = get_default_paper_size(supported_sizes, SUPPORTED_SIZE_COUNT);
985 TW_UINT16 current_size = get_current_paper_size(supported_sizes, SUPPORTED_SIZE_COUNT);
986
987 TRACE("ICAP_SUPPORTEDSIZES\n");
988
989 switch (action)
990 {
991 case MSG_QUERYSUPPORT:
992 twCC = set_onevalue(pCapability, TWTY_INT32,
993 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
994 break;
995
996 case MSG_GET:
997 for (i = 0; i < sizeof(supported_sizes) / sizeof(supported_sizes[0]); i++)
998 possible_values[i] = supported_sizes[i].size;
999 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
1000 TWTY_UINT16, current_size, default_size);
1001 WARN("Partial Stub: our supported size selection is a bit thin.\n");
1002 break;
1003
1004 case MSG_SET:
1005 twCC = msg_set(pCapability, &val);
1006 if (twCC == TWCC_SUCCESS)
1007 for (i = 1; i < SUPPORTED_SIZE_COUNT; i++)
1008 if (supported_sizes[i].size == val)
1009 return set_width_height(supported_sizes[i].x, supported_sizes[i].y);
1010
1011 ERR("Unsupported size %d\n", val);
1012 twCC = TWCC_BADCAP;
1013 break;
1014
1015 case MSG_GETDEFAULT:
1016 twCC = set_onevalue(pCapability, TWTY_UINT16, default_size);
1017 break;
1018
1019 case MSG_RESET:
1020 twCC = TWCC_BADCAP;
1021 for (i = 1; i < SUPPORTED_SIZE_COUNT; i++)
1022 if (supported_sizes[i].size == default_size)
1023 {
1024 twCC = set_width_height(supported_sizes[i].x, supported_sizes[i].y);
1025 break;
1026 }
1027 if (twCC != TWCC_SUCCESS)
1028 return twCC;
1029
1030 /* .. fall through intentional .. */
1031
1032 case MSG_GETCURRENT:
1033 twCC = set_onevalue(pCapability, TWTY_UINT16, current_size);
1034 break;
1035 }
1036
1037#undef SUPPORTED_SIZE_COUNT
1038#endif
1039 return twCC;
1040}
1041
Jeremy White513b2b52009-03-05 13:15:13 -06001042/* CAP_AUTOFEED */
1043static TW_UINT16 SANE_CAPAutofeed (pTW_CAPABILITY pCapability, TW_UINT16 action)
1044{
1045 TW_UINT16 twCC = TWCC_BADCAP;
1046#ifdef SONAME_LIBSANE
1047 TW_UINT32 val;
1048 SANE_Bool autofeed;
1049 SANE_Status status;
1050
1051 TRACE("CAP_AUTOFEED\n");
1052
1053 if (sane_option_get_bool(activeDS.deviceHandle, "batch-scan", &autofeed, NULL) != SANE_STATUS_GOOD)
1054 return TWCC_BADCAP;
1055
1056 switch (action)
1057 {
1058 case MSG_QUERYSUPPORT:
1059 twCC = set_onevalue(pCapability, TWTY_INT32,
1060 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
1061 break;
1062
1063 case MSG_GET:
1064 twCC = set_onevalue(pCapability, TWTY_BOOL, autofeed);
1065 break;
1066
1067 case MSG_SET:
1068 twCC = msg_set(pCapability, &val);
1069 if (twCC == TWCC_SUCCESS)
1070 {
1071 if (val)
1072 autofeed = SANE_TRUE;
1073 else
1074 autofeed = SANE_FALSE;
1075
1076 status = sane_option_set_bool(activeDS.deviceHandle, "batch-scan", autofeed, NULL);
1077 if (status != SANE_STATUS_GOOD)
1078 {
1079 ERR("Error %s: Could not set batch-scan to %d\n", psane_strstatus(status), autofeed);
1080 return sane_status_to_twcc(status);
1081 }
1082 }
1083 break;
1084
1085 case MSG_GETDEFAULT:
1086 twCC = set_onevalue(pCapability, TWTY_BOOL, SANE_TRUE);
1087 break;
1088
1089 case MSG_RESET:
1090 autofeed = SANE_TRUE;
1091 status = sane_option_set_bool(activeDS.deviceHandle, "batch-scan", autofeed, NULL);
1092 if (status != SANE_STATUS_GOOD)
1093 {
1094 ERR("Error %s: Could not reset batch-scan to SANE_TRUE\n", psane_strstatus(status));
1095 return sane_status_to_twcc(status);
1096 }
1097 /* .. fall through intentional .. */
1098
1099 case MSG_GETCURRENT:
1100 twCC = set_onevalue(pCapability, TWTY_BOOL, autofeed);
1101 break;
1102 }
1103#endif
1104 return twCC;
1105}
1106
Jeremy White28b708c2009-03-05 13:15:20 -06001107/* CAP_FEEDERENABLED */
1108static TW_UINT16 SANE_CAPFeederEnabled (pTW_CAPABILITY pCapability, TW_UINT16 action)
1109{
1110 TW_UINT16 twCC = TWCC_BADCAP;
1111#ifdef SONAME_LIBSANE
1112 TW_UINT32 val;
1113 TW_BOOL enabled;
1114 SANE_Status status;
1115 SANE_Char source[64];
1116
1117 TRACE("CAP_FEEDERENABLED\n");
1118
1119 if (sane_option_get_str(activeDS.deviceHandle, SANE_NAME_SCAN_SOURCE, source, sizeof(source), NULL) != SANE_STATUS_GOOD)
1120 return TWCC_BADCAP;
1121
1122 if (strcmp(source, "Auto") == 0 || strcmp(source, "ADF") == 0)
1123 enabled = TRUE;
1124 else
1125 enabled = FALSE;
1126
1127 switch (action)
1128 {
1129 case MSG_QUERYSUPPORT:
1130 twCC = set_onevalue(pCapability, TWTY_INT32,
1131 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
1132 break;
1133
1134 case MSG_GET:
1135 twCC = set_onevalue(pCapability, TWTY_BOOL, enabled);
1136 break;
1137
1138 case MSG_SET:
1139 twCC = msg_set(pCapability, &val);
1140 if (twCC == TWCC_SUCCESS)
1141 {
1142 if (val)
1143 enabled = TRUE;
1144 else
1145 enabled = FALSE;
1146
1147 strcpy(source, "ADF");
1148 status = sane_option_set_str(activeDS.deviceHandle, SANE_NAME_SCAN_SOURCE, source, NULL);
1149 if (status != SANE_STATUS_GOOD)
1150 {
1151 strcpy(source, "Auto");
1152 status = sane_option_set_str(activeDS.deviceHandle, SANE_NAME_SCAN_SOURCE, source, NULL);
1153 }
1154 if (status != SANE_STATUS_GOOD)
1155 {
1156 ERR("Error %s: Could not set source to either ADF or Auto\n", psane_strstatus(status));
1157 return sane_status_to_twcc(status);
1158 }
1159 }
1160 break;
1161
1162 case MSG_GETDEFAULT:
1163 twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
1164 break;
1165
1166 case MSG_RESET:
1167 strcpy(source, "Auto");
1168 if (sane_option_set_str(activeDS.deviceHandle, SANE_NAME_SCAN_SOURCE, source, NULL) == SANE_STATUS_GOOD)
1169 enabled = TRUE;
1170 twCC = TWCC_SUCCESS;
1171 /* .. fall through intentional .. */
1172
1173 case MSG_GETCURRENT:
1174 twCC = set_onevalue(pCapability, TWTY_BOOL, enabled);
1175 break;
1176 }
1177#endif
1178 return twCC;
1179}
1180
Jeremy White513b2b52009-03-05 13:15:13 -06001181
Jeremy White9bb24b82009-02-13 13:14:45 -06001182
Jeremy White25d59532009-02-09 13:00:47 -06001183TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
1184{
1185 TW_UINT16 twCC = TWCC_CAPUNSUPPORTED;
1186
1187 TRACE("capability=%d action=%d\n", pCapability->Cap, action);
1188
1189 switch (pCapability->Cap)
1190 {
1191 case CAP_SUPPORTEDCAPS:
1192 if (action == MSG_GET)
1193 twCC = TWAIN_GetSupportedCaps(pCapability);
1194 else
1195 twCC = TWCC_BADVALUE;
1196 break;
1197
1198 case CAP_XFERCOUNT:
Jeremy White333ef6a2009-02-09 13:00:57 -06001199 twCC = SANE_CAPXferCount (pCapability, action);
Jeremy White25d59532009-02-09 13:00:47 -06001200 break;
1201
Jeremy White63202662009-02-09 13:01:39 -06001202 case CAP_UICONTROLLABLE:
1203 twCC = SANE_CAPUiControllable (pCapability, action);
1204 break;
1205
Jeremy White513b2b52009-03-05 13:15:13 -06001206 case CAP_AUTOFEED:
1207 twCC = SANE_CAPAutofeed (pCapability, action);
1208 break;
1209
Jeremy White28b708c2009-03-05 13:15:20 -06001210 case CAP_FEEDERENABLED:
1211 twCC = SANE_CAPFeederEnabled (pCapability, action);
1212 break;
1213
Jeremy White272c1882009-02-09 13:01:27 -06001214 case ICAP_PIXELTYPE:
1215 twCC = SANE_ICAPPixelType (pCapability, action);
1216 break;
1217
Jeremy Whitef75b5eb2009-02-25 20:58:34 -06001218 case ICAP_UNITS:
1219 twCC = SANE_ICAPUnits (pCapability, action);
1220 break;
1221
Jeremy White982482e2009-02-25 20:58:25 -06001222 case ICAP_BITDEPTH:
1223 twCC = SANE_ICAPBitDepth(pCapability, action);
1224 break;
1225
Jeremy White25d59532009-02-09 13:00:47 -06001226 case ICAP_XFERMECH:
1227 twCC = SANE_ICAPXferMech (pCapability, action);
1228 break;
Jeremy Whiteb0ec8882009-02-09 13:02:05 -06001229
Jeremy White9bb24b82009-02-13 13:14:45 -06001230 case ICAP_PIXELFLAVOR:
1231 twCC = SANE_ICAPPixelFlavor (pCapability, action);
1232 break;
1233
Jeremy Whiteb0ec8882009-02-09 13:02:05 -06001234 case ICAP_COMPRESSION:
1235 twCC = SANE_ICAPCompression(pCapability, action);
1236 break;
Jeremy White6ace7992009-02-23 16:25:26 -06001237
1238 case ICAP_XRESOLUTION:
1239 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
1240 break;
1241
1242 case ICAP_YRESOLUTION:
1243 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
1244 break;
Jeremy Whiteeae4ac92009-03-05 13:15:06 -06001245
1246 case ICAP_PHYSICALHEIGHT:
1247 twCC = SANE_ICAPPhysical(pCapability, action, pCapability->Cap);
1248 break;
1249
1250 case ICAP_PHYSICALWIDTH:
1251 twCC = SANE_ICAPPhysical(pCapability, action, pCapability->Cap);
1252 break;
1253
Jeremy White81b28882009-03-06 11:52:33 -06001254 case ICAP_SUPPORTEDSIZES:
1255 twCC = SANE_ICAPSupportedSizes (pCapability, action);
1256 break;
1257
Jeremy White25d59532009-02-09 13:00:47 -06001258 }
1259
Jeremy White22bab0a2009-02-09 13:01:09 -06001260 /* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
1261 * even if you don't formally support the capability */
1262 if (twCC == TWCC_CAPUNSUPPORTED && action == MSG_QUERYSUPPORT)
1263 twCC = set_onevalue(pCapability, 0, TWTY_INT32);
1264
Jeremy White20333122009-02-09 13:02:47 -06001265 if (twCC == TWCC_CAPUNSUPPORTED)
1266 TRACE("capability 0x%x/action=%d being reported as unsupported\n", pCapability->Cap, action);
1267
Jeremy White25d59532009-02-09 13:00:47 -06001268 return twCC;
1269}
Jeremy White513b2b52009-03-05 13:15:13 -06001270
1271TW_UINT16 SANE_SaneSetDefaults (void)
1272{
1273 TW_CAPABILITY cap;
1274
1275 memset(&cap, 0, sizeof(cap));
1276 cap.Cap = CAP_AUTOFEED;
1277 cap.ConType = TWON_DONTCARE16;
1278
1279 if (SANE_SaneCapability(&cap, MSG_RESET) == TWCC_SUCCESS)
1280 GlobalFree(cap.hContainer);
1281
Jeremy White28b708c2009-03-05 13:15:20 -06001282 memset(&cap, 0, sizeof(cap));
1283 cap.Cap = CAP_FEEDERENABLED;
1284 cap.ConType = TWON_DONTCARE16;
1285
1286 if (SANE_SaneCapability(&cap, MSG_RESET) == TWCC_SUCCESS)
1287 GlobalFree(cap.hContainer);
1288
Jeremy White81b28882009-03-06 11:52:33 -06001289 memset(&cap, 0, sizeof(cap));
1290 cap.Cap = ICAP_SUPPORTEDSIZES;
1291 cap.ConType = TWON_DONTCARE16;
1292
1293 if (SANE_SaneCapability(&cap, MSG_RESET) == TWCC_SUCCESS)
1294 GlobalFree(cap.hContainer);
1295
Jeremy White513b2b52009-03-05 13:15:13 -06001296 return TWCC_SUCCESS;
1297}