winepulse: Set pulse master volume to 0 when session is muted.
[wine.git] / dlls / sane.ds / sane_main.c
blob1df6cb9ba2dc43a5487995cceff980b596567927
1 /*
2 * SANE.DS functions
4 * Copyright 2000 Shi Quan He <shiquan@cyberdude.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdio.h>
27 #include "sane_i.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(twain);
32 struct tagActiveDS activeDS;
34 DSMENTRYPROC SANE_dsmentry;
36 #ifdef SONAME_LIBSANE
37 #define MAKE_FUNCPTR(f) typeof(f) * p##f;
38 MAKE_FUNCPTR(sane_init)
39 MAKE_FUNCPTR(sane_exit)
40 MAKE_FUNCPTR(sane_get_devices)
41 MAKE_FUNCPTR(sane_open)
42 MAKE_FUNCPTR(sane_close)
43 MAKE_FUNCPTR(sane_get_option_descriptor)
44 MAKE_FUNCPTR(sane_control_option)
45 MAKE_FUNCPTR(sane_get_parameters)
46 MAKE_FUNCPTR(sane_start)
47 MAKE_FUNCPTR(sane_read)
48 MAKE_FUNCPTR(sane_cancel)
49 MAKE_FUNCPTR(sane_set_io_mode)
50 MAKE_FUNCPTR(sane_get_select_fd)
51 MAKE_FUNCPTR(sane_strstatus)
52 #undef MAKE_FUNCPTR
54 HINSTANCE SANE_instance;
56 static void *libsane_handle;
58 static void close_libsane(void *h)
60 if (h)
61 dlclose(h);
64 static void *open_libsane(void)
66 void *h;
68 h = dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW);
69 if (!h)
71 WARN("failed to load %s; %s\n", SONAME_LIBSANE, dlerror());
72 return NULL;
75 #define LOAD_FUNCPTR(f) \
76 if((p##f = dlsym(h, #f)) == NULL) { \
77 close_libsane(h); \
78 ERR("Could not dlsym %s\n", #f); \
79 return NULL; \
82 LOAD_FUNCPTR(sane_init)
83 LOAD_FUNCPTR(sane_exit)
84 LOAD_FUNCPTR(sane_get_devices)
85 LOAD_FUNCPTR(sane_open)
86 LOAD_FUNCPTR(sane_close)
87 LOAD_FUNCPTR(sane_get_option_descriptor)
88 LOAD_FUNCPTR(sane_control_option)
89 LOAD_FUNCPTR(sane_get_parameters)
90 LOAD_FUNCPTR(sane_start)
91 LOAD_FUNCPTR(sane_read)
92 LOAD_FUNCPTR(sane_cancel)
93 LOAD_FUNCPTR(sane_set_io_mode)
94 LOAD_FUNCPTR(sane_get_select_fd)
95 LOAD_FUNCPTR(sane_strstatus)
96 #undef LOAD_FUNCPTR
98 return h;
101 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
103 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
105 switch (fdwReason)
107 case DLL_PROCESS_ATTACH: {
108 SANE_Int version_code;
110 libsane_handle = open_libsane();
111 if (! libsane_handle)
112 return FALSE;
114 psane_init (&version_code, NULL);
115 SANE_instance = hinstDLL;
116 DisableThreadLibraryCalls(hinstDLL);
117 break;
119 case DLL_PROCESS_DETACH:
120 if (lpvReserved) break;
121 TRACE("calling sane_exit()\n");
122 psane_exit ();
123 close_libsane(libsane_handle);
124 break;
127 return TRUE;
130 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
131 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
133 #endif /* SONAME_LIBSANE */
135 static TW_UINT16 SANE_SetEntryPoint (pTW_IDENTITY pOrigin, TW_MEMREF pData);
137 static TW_UINT16 SANE_SourceControlHandler (
138 pTW_IDENTITY pOrigin,
139 TW_UINT16 DAT,
140 TW_UINT16 MSG,
141 TW_MEMREF pData)
143 TW_UINT16 twRC = TWRC_SUCCESS;
145 switch (DAT)
147 case DAT_IDENTITY:
148 switch (MSG)
150 case MSG_CLOSEDS:
151 #ifdef SONAME_LIBSANE
152 psane_close (activeDS.deviceHandle);
153 #else
154 twRC = TWRC_FAILURE;
155 activeDS.twCC = TWCC_CAPUNSUPPORTED;
156 #endif
157 break;
158 case MSG_OPENDS:
159 #ifdef SONAME_LIBSANE
160 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
161 #else
162 twRC = TWRC_FAILURE;
163 activeDS.twCC = TWCC_CAPUNSUPPORTED;
164 #endif
165 break;
166 case MSG_GET:
167 #ifdef SONAME_LIBSANE
168 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
169 #else
170 twRC = TWRC_FAILURE;
171 activeDS.twCC = TWCC_CAPUNSUPPORTED;
172 #endif
173 break;
175 break;
176 case DAT_CAPABILITY:
177 switch (MSG)
179 case MSG_GET:
180 twRC = SANE_CapabilityGet (pOrigin, pData);
181 break;
182 case MSG_GETCURRENT:
183 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
184 break;
185 case MSG_GETDEFAULT:
186 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
187 break;
188 case MSG_QUERYSUPPORT:
189 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
190 break;
191 case MSG_RESET:
192 twRC = SANE_CapabilityReset (pOrigin, pData);
193 break;
194 case MSG_SET:
195 twRC = SANE_CapabilitySet (pOrigin, pData);
196 break;
197 default:
198 twRC = TWRC_FAILURE;
199 activeDS.twCC = TWCC_CAPBADOPERATION;
200 FIXME("unrecognized operation triplet\n");
201 break;
203 break;
205 case DAT_ENTRYPOINT:
206 if (MSG == MSG_SET)
207 twRC = SANE_SetEntryPoint (pOrigin, pData);
208 else
210 twRC = TWRC_FAILURE;
211 activeDS.twCC = TWCC_CAPBADOPERATION;
212 FIXME("unrecognized operation triplet\n");
214 break;
216 case DAT_EVENT:
217 if (MSG == MSG_PROCESSEVENT)
218 twRC = SANE_ProcessEvent (pOrigin, pData);
219 else
221 activeDS.twCC = TWCC_CAPBADOPERATION;
222 twRC = TWRC_FAILURE;
224 break;
226 case DAT_PENDINGXFERS:
227 switch (MSG)
229 case MSG_ENDXFER:
230 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
231 break;
232 case MSG_GET:
233 twRC = SANE_PendingXfersGet (pOrigin, pData);
234 break;
235 case MSG_RESET:
236 twRC = SANE_PendingXfersReset (pOrigin, pData);
237 break;
238 default:
239 activeDS.twCC = TWCC_CAPBADOPERATION;
240 twRC = TWRC_FAILURE;
242 break;
244 case DAT_SETUPMEMXFER:
245 if (MSG == MSG_GET)
246 twRC = SANE_SetupMemXferGet (pOrigin, pData);
247 else
249 activeDS.twCC = TWCC_CAPBADOPERATION;
250 twRC = TWRC_FAILURE;
252 break;
254 case DAT_STATUS:
255 if (MSG == MSG_GET)
256 twRC = SANE_GetDSStatus (pOrigin, pData);
257 else
259 activeDS.twCC = TWCC_CAPBADOPERATION;
260 twRC = TWRC_FAILURE;
262 break;
264 case DAT_USERINTERFACE:
265 switch (MSG)
267 case MSG_DISABLEDS:
268 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
269 break;
270 case MSG_ENABLEDS:
271 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
272 break;
273 case MSG_ENABLEDSUIONLY:
274 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
275 break;
276 default:
277 activeDS.twCC = TWCC_CAPBADOPERATION;
278 twRC = TWRC_FAILURE;
279 break;
281 break;
283 case DAT_XFERGROUP:
284 switch (MSG)
286 case MSG_GET:
287 twRC = SANE_XferGroupGet (pOrigin, pData);
288 break;
289 case MSG_SET:
290 twRC = SANE_XferGroupSet (pOrigin, pData);
291 break;
292 default:
293 activeDS.twCC = TWCC_CAPBADOPERATION;
294 twRC = TWRC_FAILURE;
295 break;
297 break;
299 default:
300 WARN("code unsupported: %d\n", DAT);
301 activeDS.twCC = TWCC_CAPUNSUPPORTED;
302 twRC = TWRC_FAILURE;
303 break;
306 return twRC;
310 static TW_UINT16 SANE_ImageGroupHandler (
311 pTW_IDENTITY pOrigin,
312 TW_UINT16 DAT,
313 TW_UINT16 MSG,
314 TW_MEMREF pData)
316 TW_UINT16 twRC = TWRC_SUCCESS;
318 switch (DAT)
320 case DAT_IMAGEINFO:
321 if (MSG == MSG_GET)
322 twRC = SANE_ImageInfoGet (pOrigin, pData);
323 else
325 activeDS.twCC = TWCC_CAPBADOPERATION;
326 twRC = TWRC_FAILURE;
328 break;
330 case DAT_IMAGELAYOUT:
331 switch (MSG)
333 case MSG_GET:
334 twRC = SANE_ImageLayoutGet (pOrigin, pData);
335 break;
336 case MSG_GETDEFAULT:
337 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
338 break;
339 case MSG_RESET:
340 twRC = SANE_ImageLayoutReset (pOrigin, pData);
341 break;
342 case MSG_SET:
343 twRC = SANE_ImageLayoutSet (pOrigin, pData);
344 break;
345 default:
346 twRC = TWRC_FAILURE;
347 activeDS.twCC = TWCC_CAPBADOPERATION;
348 ERR("unrecognized operation triplet\n");
349 break;
351 break;
353 case DAT_IMAGEMEMXFER:
354 if (MSG == MSG_GET)
355 twRC = SANE_ImageMemXferGet (pOrigin, pData);
356 else
358 activeDS.twCC = TWCC_CAPBADOPERATION;
359 twRC = TWRC_FAILURE;
361 break;
363 case DAT_IMAGENATIVEXFER:
364 if (MSG == MSG_GET)
365 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
366 else
368 activeDS.twCC = TWCC_CAPBADOPERATION;
369 twRC = TWRC_FAILURE;
371 break;
373 default:
374 twRC = TWRC_FAILURE;
375 activeDS.twCC = TWCC_CAPUNSUPPORTED;
376 WARN("unsupported DG type %d\n", DAT);
377 break;
379 return twRC;
382 /* Main entry point for the TWAIN library */
383 TW_UINT16 WINAPI
384 DS_Entry ( pTW_IDENTITY pOrigin,
385 TW_UINT32 DG,
386 TW_UINT16 DAT,
387 TW_UINT16 MSG,
388 TW_MEMREF pData)
390 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
392 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
394 switch (DG)
396 case DG_CONTROL:
397 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
398 break;
399 case DG_IMAGE:
400 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
401 break;
402 case DG_AUDIO:
403 WARN("Audio group of controls not implemented yet.\n");
404 twRC = TWRC_FAILURE;
405 activeDS.twCC = TWCC_CAPUNSUPPORTED;
406 break;
407 default:
408 activeDS.twCC = TWCC_BADPROTOCOL;
409 twRC = TWRC_FAILURE;
412 return twRC;
415 void SANE_Notify (TW_UINT16 message)
417 SANE_dsmentry (&activeDS.identity, &activeDS.appIdentity, DG_CONTROL, DAT_NULL, message, NULL);
420 /* DG_CONTROL/DAT_ENTRYPOINT/MSG_SET */
421 TW_UINT16 SANE_SetEntryPoint (pTW_IDENTITY pOrigin, TW_MEMREF pData)
423 TW_ENTRYPOINT *entry = (TW_ENTRYPOINT*)pData;
425 SANE_dsmentry = entry->DSM_Entry;
427 return TWRC_SUCCESS;
430 #ifdef SONAME_LIBSANE
431 /* Sane returns device names that are longer than the 32 bytes allowed
432 by TWAIN. However, it colon separates them, and the last bit is
433 the most interesting. So we use the last bit, and add a signature
434 to ensure uniqueness */
435 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
437 const char *p;
438 int signature = 0;
440 if (strlen(in) <= outsize - 1)
442 strcpy(out, in);
443 return;
446 for (p = in; *p; p++)
447 signature += *p;
449 p = strrchr(in, ':');
450 if (!p)
451 p = in;
452 else
453 p++;
455 if (strlen(p) > outsize - 7 - 1)
456 p += strlen(p) - (outsize - 7 - 1);
458 strcpy(out, p);
459 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
463 static const SANE_Device **sane_devlist;
465 static void
466 detect_sane_devices(void) {
467 if (sane_devlist && sane_devlist[0]) return;
468 TRACE("detecting sane...\n");
469 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
470 return;
473 static TW_UINT16
474 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
475 static int cursanedev = 0;
477 detect_sane_devices();
478 if (!sane_devlist[cursanedev])
479 return TWRC_FAILURE;
480 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
481 self->ProtocolMinor = TWON_PROTOCOLMINOR;
482 self->SupportedGroups = DG_CONTROL | DG_IMAGE | DF_DS2;
483 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
484 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
485 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
486 cursanedev++;
488 if (!sane_devlist[cursanedev] ||
489 !sane_devlist[cursanedev]->model ||
490 !sane_devlist[cursanedev]->vendor ||
491 !sane_devlist[cursanedev]->name
493 cursanedev = 0; /* wrap to begin */
494 return TWRC_SUCCESS;
497 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
498 SANE_Status status;
499 int i;
501 if (SANE_dsmentry == NULL)
503 static const WCHAR twain32W[] = {'t','w','a','i','n','_','3','2',0};
504 HMODULE moddsm = GetModuleHandleW(twain32W);
506 if (moddsm)
507 SANE_dsmentry = (void*)GetProcAddress(moddsm, "DSM_Entry");
509 if (!SANE_dsmentry)
511 ERR("can't find DSM entry point\n");
512 return TWRC_FAILURE;
516 detect_sane_devices();
517 if (!sane_devlist[0]) {
518 ERR("No scanners? We should not get to OpenDS?\n");
519 return TWRC_FAILURE;
522 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
523 TW_STR32 name;
525 /* To make string as short as above */
526 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
527 if (*self->Manufacturer && strcmp(name, self->Manufacturer))
528 continue;
529 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
530 if (*self->ProductFamily && strcmp(name, self->ProductFamily))
531 continue;
532 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
533 if (*self->ProductName && strcmp(name, self->ProductName))
534 continue;
535 break;
537 if (!sane_devlist[i]) {
538 WARN("Scanner not found.\n");
539 return TWRC_FAILURE;
541 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
542 if (status == SANE_STATUS_GOOD) {
543 activeDS.twCC = SANE_SaneSetDefaults();
544 if (activeDS.twCC == TWCC_SUCCESS) {
545 activeDS.currentState = 4;
546 activeDS.identity.Id = self->Id;
547 activeDS.appIdentity = *pOrigin;
548 return TWRC_SUCCESS;
550 else
551 psane_close(activeDS.deviceHandle);
553 else
554 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
555 return TWRC_FAILURE;
557 #endif