1 /*.............................................................................
2 * Project : SANE library for Plustek flatbed scanners.
3 *.............................................................................
4 */
5
6 /** @file plustek-usb.c
7 * @brief The interface functions to the USB driver stuff.
8 *
9 * Based on sources acquired from Plustek Inc.<br>
10 * Copyright (C) 2001-2007 Gerhard Jaeger <gerhard@gjaeger.de>
11 *
12 * History:
13 * - 0.40 - starting version of the USB support
14 * - 0.41 - removed CHECK
15 * - added Canon to the manufacturer list
16 * - 0.42 - added warmup stuff
17 * - added setmap function
18 * - changed detection stuff, so we first check whether
19 * - the vendor and product Ids match with the ones in our list
20 * - 0.43 - cleanup
21 * - 0.44 - changes to integration CIS based devices
22 * - 0.45 - added skipFine assignment
23 * - added auto device name detection if only product and vendor id<br>
24 * has been specified
25 * - made 16-bit gray mode work
26 * - added special handling for Genius devices
27 * - added TPA autodetection for EPSON Photo
28 * - fixed bug that causes warmup each time autodetected<br>
29 * TPA on EPSON is used
30 * - removed Genius from PCB-Id check
31 * - added Compaq to the list
32 * - removed the scaler stuff for CIS devices
33 * - removed homeing stuff from readline function
34 * - fixed flag setting in usbDev_startScan()
35 * - 0.46 - added additional branch to support alternate calibration
36 * - 0.47 - added special handling with 0x400 vendor ID and model override
37 * - removed PATH_MAX
38 * - change usbDev_stopScan and usbDev_open prototype
39 * - cleanup
40 * - 0.48 - added function usb_CheckAndCopyAdjs()
41 * - 0.49 - changed autodetection
42 * - added support for LiDE25 (pid 0x2220)
43 * - 0.50 - minor fix for startup reset
44 * removed unnecessary calls to usbio_ResetLM983x()
45 * 1200DPI CIS devices don't use GrayFromColor any longer
46 * - 0.51 - added Syscan to the vendor list
47 * - added SCANFLAG_Calibration handling
48 * - 0.52 - added _WAF_LOFF_ON_START and _WAF_INC_DARKTGT
49 * handling in usbDev_startScan()
50 * added Visioneer
51 * .
52 * <hr>
53 * This file is part of the SANE package.
54 *
55 * This program is free software; you can redistribute it and/or
56 * modify it under the terms of the GNU General Public License as
57 * published by the Free Software Foundation; either version 2 of the
58 * License, or (at your option) any later version.
59 *
60 * This program is distributed in the hope that it will be useful, but
61 * WITHOUT ANY WARRANTY; without even the implied warranty of
62 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
63 * General Public License for more details.
64 *
65 * You should have received a copy of the GNU General Public License
66 * along with this program. If not, see <https://www.gnu.org/licenses/>.
67 *
68 * As a special exception, the authors of SANE give permission for
69 * additional uses of the libraries contained in this release of SANE.
70 *
71 * The exception is that, if you link a SANE library with other files
72 * to produce an executable, this does not by itself cause the
73 * resulting executable to be covered by the GNU General Public
74 * License. Your use of that executable is in no way restricted on
75 * account of linking the SANE library code into it.
76 *
77 * This exception does not, however, invalidate any other reasons why
78 * the executable file might be covered by the GNU General Public
79 * License.
80 *
81 * If you submit changes to SANE to the maintainers to be included in
82 * a subsequent release, you agree by submitting the changes that
83 * those changes may be distributed with this exception intact.
84 *
85 * If you write modifications of your own for SANE, it is your choice
86 * whether to permit this exception to apply to your modifications.
87 * If you do not wish that, delete this exception notice.
88 * <hr>
89 */
90
91 /** useful for description tables
92 */
93 typedef struct {
94 int id;
95 char *desc;
96 char *desc_alt;
97 } TabDef, *pTabDef;
98
99 /** to allow different vendors...
100 */
101 static TabDef usbVendors[] = {
102
103 { 0x07B3, "Plustek", NULL },
104 { 0x0400, "NSC", "Mustek" },
105 { 0x0458, "KYE/Genius", NULL },
106 { 0x03F0, "Hewlett-Packard", NULL },
107 { 0x04B8, "Epson", NULL },
108 { 0x04A7, "Visioneer", NULL },
109 { 0x04A9, "Canon", NULL },
110 { 0x1606, "UMAX", NULL },
111 { 0x049F, "Compaq", NULL },
112 { 0x0A82, "Syscan", NULL },
113 { 0x0A53, "PandP Co., Ltd.", NULL },
114 { 0xFFFF, NULL, NULL }
115 };
116
117 /** we use at least 8 megs for scanning... */
118 #define _SCANBUF_SIZE (8 * 1024 * 1024)
119
120 /********************** the USB scanner interface ****************************/
121
122 /** remove the slash out of the model-name to obtain a valid filename
123 */
usb_normFileName( char *fname, char* buffer, u_long max_len )124 static SANE_Bool usb_normFileName( char *fname, char* buffer, u_long max_len )
125 {
126 char *src, *dst;
127
128 if( NULL == fname )
129 return SANE_FALSE;
130
131 if( strlen( fname ) >= max_len )
132 return SANE_FALSE;
133
134 src = fname;
135 dst = buffer;
136 while( *src != '\0' ) {
137
138 if((*src == '/') || isspace(*src) || ispunct(*src))
139 *dst = '_';
140 else
141 *dst = *src;
142
143 dst++;
144 src++;
145 }
146 *dst = '\0';
147
148 return SANE_TRUE;
149 }
150
151 /** do some range checking and copy the adjustment values from the
152 * frontend to our internal structures, so that the backend can take
153 * care of them.
154 */
usb_CheckAndCopyAdjs( Plustek_Device *dev )155 static void usb_CheckAndCopyAdjs( Plustek_Device *dev )
156 {
157 if( dev->adj.lampOff >= 0 )
158 dev->usbDev.dwLampOnPeriod = dev->adj.lampOff;
159
160 if( dev->adj.lampOffOnEnd >= 0 )
161 dev->usbDev.bLampOffOnEnd = dev->adj.lampOffOnEnd;
162
163 if( dev->adj.skipCalibration > 0 )
164 dev->usbDev.Caps.workaroundFlag |= _WAF_BYPASS_CALIBRATION;
165
166 if( dev->adj.skipFine > 0 )
167 dev->usbDev.Caps.workaroundFlag |= _WAF_SKIP_FINE;
168
169 if( dev->adj.skipFineWhite > 0 )
170 dev->usbDev.Caps.workaroundFlag |= _WAF_SKIP_WHITEFINE;
171
172 if( dev->adj.incDarkTgt > 0 )
173 dev->usbDev.Caps.workaroundFlag |= _WAF_INC_DARKTGT;
174
175 if( dev->adj.skipDarkStrip > 0 )
176 dev->usbDev.Caps.Normal.DarkShadOrgY = -1;
177
178 if( dev->adj.invertNegatives > 0 )
179 dev->usbDev.Caps.workaroundFlag |= _WAF_INV_NEGATIVE_MAP;
180 }
181
182 /**
183 * assign the values to the structures used by the currently found scanner
184 */
185 static void
usb_initDev( Plustek_Device *dev, int idx, int handle, int vendor )186 usb_initDev( Plustek_Device *dev, int idx, int handle, int vendor )
187 {
188 char *ptr;
189 char tmp_str1[PATH_MAX];
190 char tmp_str2[PATH_MAX];
191 int i;
192 ScanParam sParam;
193 u_short tmp = 0;
194 int ret = 0;
195
196 DBG( _DBG_INFO, "usb_initDev(%d,0x%04x,%i)\n",
197 idx, vendor, dev->initialized );
198 /* save capability flags... */
199 if( dev->initialized >= 0 ) {
200 tmp = DEVCAPSFLAG_TPA;
201 }
202
203 /* copy the original values... */
204 memcpy( &dev->usbDev.Caps, Settings[idx].pDevCaps, sizeof(DCapsDef));
205 memcpy( &dev->usbDev.HwSetting, Settings[idx].pHwDef, sizeof(HWDef));
206
207 /* restore capability flags... */
208 if( dev->initialized >= 0 ) {
209 dev->usbDev.Caps.wFlags |= tmp;
210 }
211
212 usb_CheckAndCopyAdjs( dev );
213 DBG( _DBG_INFO, "Device WAF : 0x%08lx\n", dev->usbDev.Caps.workaroundFlag );
214 DBG( _DBG_INFO, "Transferrate: %lu Bytes/s\n", dev->transferRate );
215
216 /* adjust data origin
217 */
218 dev->usbDev.Caps.Positive.DataOrigin.x -= dev->adj.tpa.x;
219 dev->usbDev.Caps.Positive.DataOrigin.y -= dev->adj.tpa.y;
220
221 dev->usbDev.Caps.Negative.DataOrigin.x -= dev->adj.neg.x;
222 dev->usbDev.Caps.Negative.DataOrigin.y -= dev->adj.neg.y;
223
224 dev->usbDev.Caps.Normal.DataOrigin.x -= dev->adj.pos.x;
225 dev->usbDev.Caps.Normal.DataOrigin.y -= dev->adj.pos.y;
226
227 /** adjust shading position
228 */
229 if( dev->adj.posShadingY >= 0 )
230 dev->usbDev.Caps.Normal.ShadingOriginY = dev->adj.posShadingY;
231
232 if( dev->adj.tpaShadingY >= 0 )
233 dev->usbDev.Caps.Positive.ShadingOriginY = dev->adj.tpaShadingY;
234
235 if( dev->adj.negShadingY >= 0 )
236 dev->usbDev.Caps.Negative.ShadingOriginY = dev->adj.negShadingY;
237
238 /* adjust the gamma settings... */
239 if( dev->adj.rgamma == 1.0 )
240 dev->adj.rgamma = dev->usbDev.HwSetting.gamma;
241 if( dev->adj.ggamma == 1.0 )
242 dev->adj.ggamma = dev->usbDev.HwSetting.gamma;
243 if( dev->adj.bgamma == 1.0 )
244 dev->adj.bgamma = dev->usbDev.HwSetting.gamma;
245 if( dev->adj.graygamma == 1.0 )
246 dev->adj.graygamma = dev->usbDev.HwSetting.gamma;
247
248 /* the following you normally get from the registry...
249 */
250 bMaxITA = 0; /* Maximum integration time adjust */
251
252 dev->usbDev.ModelStr = Settings[idx].pModelString;
253
254 dev->fd = handle;
255
256 if( dev->initialized < 0 ) {
257 if( usb_HasTPA( dev ))
258 dev->usbDev.Caps.wFlags |= DEVCAPSFLAG_TPA;
259 }
260 DBG( _DBG_INFO, "Device Flags: 0x%08x\n", dev->usbDev.Caps.wFlags );
261
262 /* well now we patch the vendor string...
263 * if not found, the default vendor will be Plustek
264 */
265 for( i = 0; usbVendors[i].desc != NULL; i++ ) {
266
267 if( usbVendors[i].id == vendor ) {
268 dev->sane.vendor = usbVendors[i].desc;
269 if (dev->usbDev.Caps.workaroundFlag & _WAF_USE_ALT_DESC )
270 if (usbVendors[i].desc_alt )
271 dev->sane.vendor = usbVendors[i].desc_alt;
272 DBG( _DBG_INFO, "Vendor adjusted to: >%s<\n", dev->sane.vendor );
273 break;
274 }
275 }
276
277 dev->usbDev.dwTicksLampOn = 0;
278 dev->usbDev.currentLamp = usb_GetLampStatus( dev );
279 usb_ResetRegisters( dev );
280
281 if( dev->initialized >= 0 )
282 return;
283
284 usb_IsScannerReady( dev );
285
286 sParam.bBitDepth = 8;
287 sParam.bCalibration = PARAM_Scan;
288 sParam.bChannels = 3;
289 sParam.bDataType = SCANDATATYPE_Color;
290 sParam.bSource = SOURCE_Reflection;
291 sParam.Origin.x = 0;
292 sParam.Origin.y = 0;
293 sParam.UserDpi.x = 150;
294 sParam.UserDpi.y = 150;
295 sParam.dMCLK = 4;
296 sParam.Size.dwPixels = 0;
297
298 /* create calibration-filename */
299 sprintf( tmp_str2, "%s-%s",
300 dev->sane.vendor, dev->usbDev.ModelStr );
301
302 if( !usb_normFileName( tmp_str2, tmp_str1, PATH_MAX )) {
303 strcpy( tmp_str1, "plustek-default" );
304 }
305
306 ptr = getenv ("HOME");
307 ret = ( NULL == ptr )?
308 snprintf( tmp_str2, sizeof(tmp_str2), "/tmp/%s", tmp_str1 ):
309 snprintf( tmp_str2, sizeof(tmp_str2), "%s/.sane/%s", ptr, tmp_str1 );
310
311 if ((ret < 0) || (ret > (int)sizeof(tmp_str2))) {
312 DBG( _DBG_WARNING,
313 "Failed to generate calibration file path. Default substituted.\n" );
314 snprintf(tmp_str2, sizeof(tmp_str2), "/tmp/plustek-default");
315 }
316
317 dev->calFile = strdup( tmp_str2 );
318 DBG( _DBG_INFO, "Calibration file-names set to:\n" );
319 DBG( _DBG_INFO, ">%s-coarse.cal<\n", dev->calFile );
320 DBG( _DBG_INFO, ">%s-fine.cal<\n", dev->calFile );
321
322 /* initialize the ASIC registers */
323 usb_SetScanParameters( dev, &sParam );
324
325 /* check and move sensor to its home position */
326 usb_ModuleToHome( dev, SANE_FALSE );
327
328 /* set the global flag, that we are initialized so far */
329 dev->initialized = idx;
330 }
331
332 /**
333 * will be used for retrieving a Plustek device
334 */
usb_CheckForPlustekDevice( int handle, Plustek_Device *dev )335 static int usb_CheckForPlustekDevice( int handle, Plustek_Device *dev )
336 {
337 char tmp[50];
338 char pcbStr[10];
339 u_char reg59[3], reg59s[3], pcbID;
340 int i, result;
341
342 /*
343 * Plustek uses the misc IO 12 to get the PCB ID
344 * (PCB = printed circuit board), so it's possible to have one
345 * product ID and up to 7 different devices...
346 */
347 DBG( _DBG_INFO, "Trying to get the pcbID of a Plustek device...\n" );
348
349 /* get the PCB-ID */
350 result = sanei_lm983x_read( handle, 0x59, reg59s, 3, SANE_TRUE );
351 if( SANE_STATUS_GOOD != result ) {
352 sanei_usb_close( handle );
353 return -1;
354 }
355
356 reg59[0] = 0x22; /* PIO1: Input, PIO2: Input */
357 reg59[1] = 0x02; /* PIO3: Input, PIO4: Output as low */
358 reg59[2] = 0x03;
359
360 result = sanei_lm983x_write( handle, 0x59, reg59, 3, SANE_TRUE );
361 if( SANE_STATUS_GOOD != result ) {
362 sanei_usb_close( handle );
363 return -1;
364 }
365
366 result = sanei_lm983x_read ( handle, 0x02, &pcbID, 1, SANE_TRUE );
367 if( SANE_STATUS_GOOD != result ) {
368 sanei_usb_close( handle );
369 return -1;
370 }
371
372 pcbID = (u_char)((pcbID >> 2) & 0x07);
373
374 result = sanei_lm983x_read( handle, 0x59, reg59s, 3, SANE_TRUE );
375 if( SANE_STATUS_GOOD != result ) {
376 sanei_usb_close( handle );
377 return -1;
378 }
379
380 DBG( _DBG_INFO, "pcbID=0x%02x\n", pcbID );
381
382 /* now roam through the setting list... */
383 strncpy( tmp, dev->usbId, 13 );
384 tmp[13] = '\0';
385
386 sprintf( pcbStr, "-%u", pcbID );
387 strcat ( tmp, pcbStr );
388
389 DBG( _DBG_INFO, "Checking for device >%s<\n", tmp );
390
391 for( i = 0; NULL != Settings[i].pIDString; i++ ) {
392
393 if( 0 == strcmp( Settings[i].pIDString, tmp )) {
394 DBG(_DBG_INFO, "Device description for >%s< found.\n", tmp );
395 usb_initDev( dev, i, handle, dev->usbDev.vendor );
396 return handle;
397 }
398 }
399
400 return -1;
401 }
402
403 /**
404 * will be called upon sane_exit
405 */
usbDev_shutdown( Plustek_Device *dev )406 static void usbDev_shutdown( Plustek_Device *dev )
407 {
408 SANE_Int handle;
409
410 DBG( _DBG_INFO, "Shutdown called (dev->fd=%d, %s)\n",
411 dev->fd, dev->sane.name );
412 if( NULL == dev->usbDev.ModelStr ) {
413 DBG( _DBG_INFO, "Function ignored!\n" );
414 return;
415 }
416
417 if( SANE_STATUS_GOOD == sanei_usb_open( dev->sane.name, &handle )) {
418
419 dev->fd = handle;
420
421 DBG( _DBG_INFO, "Waiting for scanner-ready...\n" );
422 usb_IsScannerReady( dev );
423
424 if( 0 != dev->usbDev.bLampOffOnEnd ) {
425
426 DBG( _DBG_INFO, "Switching lamp off...\n" );
427 usb_LampOn( dev, SANE_FALSE, SANE_FALSE );
428 }
429 dev->fd = -1;
430 sanei_usb_close( handle );
431 }
432 usb_StopLampTimer( dev );
433 }
434
435 /**
436 * This function checks whether a device, described by a given
437 * string(vendor and product ID), is support by this backend or not
438 *
439 * @param usbIdStr - string consisting out of product and vendor ID
440 * format: "0xVVVVx0xPPPP" VVVV = Vendor ID, PPP = Product ID
441 * @returns; SANE_TRUE if supported, SANE_FALSE if not
442 */
usb_IsDeviceInList( char *usbIdStr )443 static SANE_Bool usb_IsDeviceInList( char *usbIdStr )
444 {
445 int i;
446
447 for( i = 0; NULL != Settings[i].pIDString; i++ ) {
448
449 if( 0 == strncmp( Settings[i].pIDString, usbIdStr, 13 ))
450 return SANE_TRUE;
451 }
452 return SANE_FALSE;
453 }
454
455 /** get last valid entry of a list
456 */
457 static DevList*
getLast( DevList *l )458 getLast( DevList *l )
459 {
460 if( l == NULL )
461 return NULL;
462
463 while( l->next != NULL )
464 l = l->next;
465 return l;
466 }
467
468 /** add a new entry to our internal device list, when a device is detected
469 */
usb_attach( SANE_String_Const dev_name )470 static SANE_Status usb_attach( SANE_String_Const dev_name )
471 {
472 int len;
473 DevList *tmp, *last;
474
475 /* get some memory for the entry... */
476 len = sizeof(DevList) + strlen(dev_name) + 1;
477 tmp = (DevList*)malloc(len);
478
479 /* initialize and set the values */
480 memset(tmp, 0, len );
481
482 /* the device name is part of our structure space */
483 tmp->dev_name = &((char*)tmp)[sizeof(DevList)];
484 strcpy( tmp->dev_name, dev_name );
485 tmp->attached = SANE_FALSE;
486
487 /* root set ? */
488 if( usbDevs == NULL ) {
489 usbDevs = tmp;
490 } else {
491 last = getLast(usbDevs); /* append... */
492 last->next = tmp;
493 }
494 return SANE_STATUS_GOOD;
495 }
496
497 /**
498 */
499 static void
usbGetList( DevList **devs )500 usbGetList( DevList **devs )
501 {
502 int i;
503 SANE_Bool il;
504 SANE_Word v, p;
505 DevList *tmp;
506
507 DBG( _DBG_INFO, "Retrieving all supported and conntected devices\n" );
508 for( i = 0; NULL != Settings[i].pIDString; i++ ) {
509
510 v = strtol( &(Settings[i].pIDString)[0], 0, 0 );
511 p = strtol( &(Settings[i].pIDString)[7], 0, 0 );
512
513 /* check if this vendor- and product-ID has already been added, needed
514 * for Plustek devices - here one product-ID is used for more than one
515 * device type...
516 */
517 il = SANE_FALSE;
518 for( tmp = *devs; tmp ; tmp = tmp->next ) {
519 if( tmp->device_id == p && tmp->vendor_id == v ) {
520 il = SANE_TRUE;
521 break;
522 }
523 }
524 if( il ) {
525 DBG( _DBG_INFO2, "Already in list: 0x%04x-0x%04x\n", v, p );
526 continue;
527 }
528
529 /* get the last entry... */
530 tmp = getLast(*devs);
531 DBG( _DBG_INFO2, "Checking for 0x%04x-0x%04x\n", v, p );
532 sanei_usb_find_devices( v, p, usb_attach );
533
534 if( getLast(*devs) != tmp ) {
535
536 if( tmp == NULL )
537 tmp = *devs;
538 else
539 tmp = tmp->next;
540
541 while( tmp != NULL ) {
542 tmp->vendor_id = v;
543 tmp->device_id = p;
544 tmp = tmp->next;
545 }
546 }
547 }
548
549 DBG( _DBG_INFO, "Available and supported devices:\n" );
550 if( *devs == NULL )
551 DBG( _DBG_INFO, "NONE.\n" );
552
553 for( tmp = *devs; tmp; tmp = tmp->next ) {
554 DBG( _DBG_INFO, "Device: >%s< - 0x%04xx0x%04x\n",
555 tmp->dev_name, tmp->vendor_id, tmp->device_id );
556 }
557 }
558
559 /**
560 */
usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock )561 static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock )
562 {
563 char dn[512];
564 char devStr[50];
565 int result;
566 int i;
567 int lc;
568 SANE_Int handle;
569 SANE_Byte version;
570 SANE_Word vendor, product;
571 SANE_Bool was_empty;
572 SANE_Status status;
573 DevList *tmp;
574
575 DBG( _DBG_INFO, "usbDev_open(%s,%s) - %p\n",
576 dev->name, dev->usbId, (void*)devs );
577
578 /* preset our internal usb device structure */
579 memset( &dev->usbDev, 0, sizeof(DeviceDef));
580
581 /* devs is NULL, when called from sane_start */
582 if( devs ) {
583
584 dn[0] = '\0';
585 if( !strcmp( dev->name, "auto" )) {
586
587 /* use the first "unattached"... */
588 for( tmp = devs; tmp; tmp = tmp->next ) {
589 if( !tmp->attached ) {
590 tmp->attached = SANE_TRUE;
591 strcpy( dn, tmp->dev_name );
592 break;
593 }
594 }
595 } else {
596
597 vendor = strtol( &dev->usbId[0], 0, 0 );
598 product = strtol( &dev->usbId[7], 0, 0 );
599
600 /* check the first match... */
601 for( tmp = devs; tmp; tmp = tmp->next ) {
602 if( tmp->vendor_id == vendor && tmp->device_id == product ) {
603 if( !tmp->attached ) {
604 tmp->attached = SANE_TRUE;
605 strcpy( dn, tmp->dev_name );
606 break;
607 }
608 }
609 }
610 }
611
612 if( !dn[0] ) {
613 DBG( _DBG_ERROR, "No supported device found!\n" );
614 return -1;
615 }
616
617 status = sanei_access_lock( dn, 5 );
618 if( SANE_STATUS_GOOD != status ) {
619 DBG( _DBG_ERROR, "sanei_access_lock failed: %d\n", status );
620 return -1;
621 }
622
623 status = sanei_usb_open( dn, &handle );
624 if( SANE_STATUS_GOOD != status ) {
625 DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n",
626 strerror(errno), errno);
627 sanei_access_unlock( dev->sane.name );
628 return -1;
629 }
630
631 /* replace the old devname, so we are able to have multiple
632 * auto-detected devices
633 */
634 free( dev->name );
635 dev->name = strdup(dn);
636 dev->sane.name = dev->name;
637
638 } else {
639
640 status = sanei_access_lock( dev->sane.name, 5 );
641 if( SANE_STATUS_GOOD != status ) {
642 DBG( _DBG_ERROR, "sanei_access_lock failed: %d\n", status );
643 return -1;
644 }
645
646 status = sanei_usb_open( dev->name, &handle );
647 if( SANE_STATUS_GOOD != status ) {
648 DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n",
649 strerror(errno), errno);
650 sanei_access_unlock( dev->sane.name );
651 return -1;
652 }
653 }
654
655 was_empty = SANE_FALSE;
656
657 result = sanei_usb_get_vendor_product( handle, &vendor, &product );
658
659 if( SANE_STATUS_GOOD == result ) {
660
661 sprintf( devStr, "0x%04X-0x%04X", vendor, product );
662
663 DBG(_DBG_INFO,"Vendor ID=0x%04X, Product ID=0x%04X\n",vendor,product);
664
665 if( dev->usbId[0] != '\0' ) {
666
667 if( 0 != strcmp( dev->usbId, devStr )) {
668 DBG( _DBG_ERROR, "Specified Vendor and Product ID "
669 "doesn't match with the ones\n"
670 "in the config file\n" );
671 sanei_access_unlock( dev->sane.name );
672 sanei_usb_close( handle );
673 return -1;
674 }
675 } else {
676 sprintf( dev->usbId, "0x%04X-0x%04X", vendor, product );
677 was_empty = SANE_TRUE;
678 }
679
680 } else {
681
682 DBG( _DBG_INFO, "Can't get vendor & product ID from driver...\n" );
683
684 /* if the ioctl stuff is not supported by the kernel and we have
685 * nothing specified, we have to give up...
686 */
687 if( dev->usbId[0] == '\0' ) {
688 DBG( _DBG_ERROR, "Cannot autodetect Vendor an Product ID, "
689 "please specify in config file.\n" );
690 sanei_access_unlock( dev->sane.name );
691 sanei_usb_close( handle );
692 return -1;
693 }
694
695 vendor = strtol( &dev->usbId[0], 0, 0 );
696 product = strtol( &dev->usbId[7], 0, 0 );
697 DBG( _DBG_INFO, "... using the specified: "
698 "0x%04X-0x%04X\n", vendor, product );
699 }
700
701 /* before accessing the scanner, check if supported!
702 */
703 if( !usb_IsDeviceInList( dev->usbId )) {
704 DBG( _DBG_ERROR, "Device >%s<, is not supported!\n", dev->usbId );
705 sanei_access_unlock( dev->sane.name );
706 sanei_usb_close( handle );
707 return -1;
708 }
709
710 status = usbio_DetectLM983x( handle, &version );
711 if( SANE_STATUS_GOOD != status ) {
712 sanei_usb_close( handle );
713 sanei_access_unlock( dev->sane.name );
714 return -1;
715 }
716
717 if ((version < 3) || (version > 4)) {
718 DBG( _DBG_ERROR, "This is not a LM9831 or LM9832 chip based scanner.\n" );
719 sanei_usb_close( handle );
720 sanei_access_unlock( dev->sane.name );
721 return -1;
722 }
723
724 /* need to set the handle and the detected chiptype... */
725 dev->fd = handle;
726 dev->usbDev.HwSetting.chip = (version==3 ? _LM9831:_LM9832);
727 usbio_ResetLM983x( dev );
728 dev->fd = -1;
729
730 dev->usbDev.vendor = vendor;
731 dev->usbDev.product = product;
732
733 DBG( _DBG_INFO, "Detected vendor & product ID: "
734 "0x%04X-0x%04X\n", vendor, product );
735
736 /*
737 * Plustek uses the misc IO 1/2 to get the PCB ID
738 * (PCB = printed circuit board), so it's possible to have one
739 * product ID and up to 7 different devices...
740 */
741 if( 0x07B3 == vendor ) {
742
743 handle = usb_CheckForPlustekDevice( handle, dev );
744
745 if( was_empty )
746 dev->usbId[0] = '\0';
747
748 if( handle >= 0 ) {
749 if( !keep_lock )
750 sanei_access_unlock( dev->sane.name );
751 return handle;
752 }
753
754 } else {
755
756 /* now roam through the setting list... */
757 lc = 13;
758 strncpy( devStr, dev->usbId, lc );
759 devStr[lc] = '\0';
760
761 if( 0x400 == vendor ) {
762 if((dev->adj.mov < 0) || (dev->adj.mov > 1)) {
763 DBG(_DBG_INFO, "BearPaw MOV out of range: %d\n", dev->adj.mov);
764 dev->adj.mov = 0;
765 }
766 sprintf( devStr, "%s-%d", dev->usbId, dev->adj.mov );
767 lc = strlen(devStr);
768 DBG( _DBG_INFO, "BearPaw device: %s (%d)\n", devStr, lc );
769 }
770
771 if( was_empty )
772 dev->usbId[0] = '\0';
773
774 /* if we don't use the PCD ID extension...
775 */
776 for( i = 0; NULL != Settings[i].pIDString; i++ ) {
777
778 if( 0 == strncmp( Settings[i].pIDString, devStr, lc )) {
779 DBG( _DBG_INFO, "Device description for >%s< found.\n", devStr );
780 usb_initDev( dev, i, handle, vendor );
781 if( !keep_lock )
782 sanei_access_unlock( dev->sane.name );
783 return handle;
784 }
785 }
786 }
787
788 sanei_access_unlock( dev->sane.name );
789 sanei_usb_close( handle );
790 DBG( _DBG_ERROR, "No matching device found >%s<\n", devStr );
791 return -1;
792 }
793
794 /**
795 */
usbDev_close( Plustek_Device *dev )796 static int usbDev_close( Plustek_Device *dev )
797 {
798 DBG( _DBG_INFO, "usbDev_close()\n" );
799 sanei_usb_close( dev->fd );
800 dev->fd = -1;
801 return 0;
802 }
803
804 /** convert the stuff
805 */
usbDev_getCaps( Plustek_Device *dev )806 static int usbDev_getCaps( Plustek_Device *dev )
807 {
808 DCapsDef *scaps = &dev->usbDev.Caps;
809
810 DBG( _DBG_INFO, "usbDev_getCaps()\n" );
811
812 dev->caps.dwFlag = 0;
813
814 if(((DEVCAPSFLAG_Positive & scaps->wFlags) &&
815 (DEVCAPSFLAG_Negative & scaps->wFlags)) ||
816 (DEVCAPSFLAG_TPA & scaps->wFlags)) {
817 dev->caps.dwFlag |= SFLAG_TPA;
818 }
819
820 dev->caps.wMaxExtentX = scaps->Normal.Size.x;
821 dev->caps.wMaxExtentY = scaps->Normal.Size.y;
822 return 0;
823 }
824
825 /** usbDev_getCropInfo
826 * function to set the image relevant stuff
827 */
usbDev_getCropInfo( Plustek_Device *dev, CropInfo *ci )828 static int usbDev_getCropInfo( Plustek_Device *dev, CropInfo *ci )
829 {
830 WinInfo size;
831
832 DBG( _DBG_INFO, "usbDev_getCropInfo()\n" );
833
834 usb_GetImageInfo( dev, &ci->ImgDef, &size );
835
836 ci->dwPixelsPerLine = size.dwPixels;
837 ci->dwLinesPerArea = size.dwLines;
838 ci->dwBytesPerLine = size.dwBytes;
839
840 if( ci->ImgDef.dwFlag & SCANFLAG_DWORDBoundary )
841 ci->dwBytesPerLine = (ci->dwBytesPerLine + 3UL) & 0xfffffffcUL;
842
843 DBG( _DBG_INFO, "PPL = %lu\n", ci->dwPixelsPerLine );
844 DBG( _DBG_INFO, "LPA = %lu\n", ci->dwLinesPerArea );
845 DBG( _DBG_INFO, "BPL = %lu\n", ci->dwBytesPerLine );
846
847 return 0;
848 }
849
850 /**
851 */
usbDev_setMap( Plustek_Device *dev, SANE_Word *map, SANE_Word length, SANE_Word channel )852 static int usbDev_setMap( Plustek_Device *dev, SANE_Word *map,
853 SANE_Word length, SANE_Word channel )
854 {
855 SANE_Word i, idx;
856
857 DBG(_DBG_INFO,"Setting map[%u] at 0x%08lx\n",channel,(unsigned long)map);
858
859 _VAR_NOT_USED( dev );
860
861 if( channel == _MAP_MASTER ) {
862
863 for( i = 0; i < length; i++ ) {
864 a_bMap[i] = (SANE_Byte)map[i];
865 a_bMap[length +i] = (SANE_Byte)map[i];
866 a_bMap[(length*2)+i] = (SANE_Byte)map[i];
867 }
868
869 } else {
870
871 idx = 0;
872 if( channel == _MAP_GREEN )
873 idx = 1;
874 if( channel == _MAP_BLUE )
875 idx = 2;
876
877 for( i = 0; i < length; i++ ) {
878 a_bMap[(length * idx)+i] = (SANE_Byte)map[i];
879 }
880 }
881
882 return 0;
883 }
884
885 /**
886 */
887 static int
usbDev_setScanEnv( Plustek_Device *dev, ScanInfo *si )888 usbDev_setScanEnv( Plustek_Device *dev, ScanInfo *si )
889 {
890 ScanDef *scan = &dev->scanning;
891 DCapsDef *caps = &dev->usbDev.Caps;
892
893 DBG( _DBG_INFO, "usbDev_setScanEnv()\n" );
894
895 /* clear all the stuff */
896 memset( scan, 0, sizeof(ScanDef));
897
898 if((si->ImgDef.dwFlag & SCANDEF_Adf) &&
899 (si->ImgDef.dwFlag & SCANDEF_ContinuousScan)) {
900 scan->sParam.dMCLK = dMCLK_ADF;
901 }
902
903 /* Save necessary information */
904 scan->fGrayFromColor = 0;
905
906 /* for some devices and settings, we tweak the physical settings
907 * how to get the image - but not in calibration mode
908 */
909 if((si->ImgDef.dwFlag & SCANFLAG_Calibration) == 0) {
910
911 if( si->ImgDef.wDataType == COLOR_256GRAY ) {
912
913 if( !(si->ImgDef.dwFlag & SCANDEF_Adf) && !usb_IsCISDevice(dev) &&
914 (caps->OpticDpi.x == 1200 && si->ImgDef.xyDpi.x <= 300)) {
915 scan->fGrayFromColor = 2;
916 si->ImgDef.wDataType = COLOR_TRUE24;
917 DBG( _DBG_INFO, "* Gray from color set!\n" );
918 }
919
920 if( caps->workaroundFlag & _WAF_GRAY_FROM_COLOR ) {
921 DBG( _DBG_INFO, "* Gray(8-bit) from color set!\n" );
922 scan->fGrayFromColor = 2;
923 si->ImgDef.wDataType = COLOR_TRUE24;
924 }
925
926 } else if ( si->ImgDef.wDataType == COLOR_GRAY16 ) {
927 if( caps->workaroundFlag & _WAF_GRAY_FROM_COLOR ) {
928 DBG( _DBG_INFO, "* Gray(16-bit) from color set!\n" );
929 scan->fGrayFromColor = 2;
930 si->ImgDef.wDataType = COLOR_TRUE48;
931 }
932
933 } else if ( si->ImgDef.wDataType == COLOR_BW ) {
934 if( caps->workaroundFlag & _WAF_BIN_FROM_COLOR ) {
935 DBG( _DBG_INFO, "* Binary from color set!\n" );
936 scan->fGrayFromColor = 10;
937 si->ImgDef.wDataType = COLOR_TRUE24;
938 }
939 }
940 }
941
942 usb_SaveImageInfo( dev, &si->ImgDef );
943 usb_GetImageInfo ( dev, &si->ImgDef, &scan->sParam.Size );
944
945 /* mask the flags */
946 scan->dwFlag = si->ImgDef.dwFlag &
947 (SCANFLAG_bgr | SCANFLAG_BottomUp | SCANFLAG_Calibration |
948 SCANFLAG_DWORDBoundary | SCANFLAG_RightAlign |
949 SCANFLAG_StillModule | SCANDEF_Adf | SCANDEF_ContinuousScan);
950
951 if( !(SCANDEF_QualityScan & si->ImgDef.dwFlag)) {
952 DBG( _DBG_INFO, "* Preview Mode set!\n" );
953 } else {
954 DBG( _DBG_INFO, "* Preview Mode NOT set!\n" );
955 scan->dwFlag |= SCANDEF_QualityScan;
956 }
957
958 scan->sParam.brightness = si->siBrightness;
959 scan->sParam.contrast = si->siContrast;
960
961 if( scan->sParam.bBitDepth <= 8 )
962 scan->dwFlag &= ~SCANFLAG_RightAlign;
963
964 if( scan->dwFlag & SCANFLAG_DWORDBoundary ) {
965 if( scan->fGrayFromColor && scan->fGrayFromColor < 10)
966 scan->dwBytesLine = (scan->sParam.Size.dwBytes / 3 + 3) & 0xfffffffcUL;
967 else
968 scan->dwBytesLine = (scan->sParam.Size.dwBytes + 3UL) & 0xfffffffcUL;
969
970 } else {
971
972 if( scan->fGrayFromColor && scan->fGrayFromColor < 10)
973 scan->dwBytesLine = scan->sParam.Size.dwBytes / 3;
974 else
975 scan->dwBytesLine = scan->sParam.Size.dwBytes;
976 }
977
978 /* on CIS based devices we have to reconfigure the illumination
979 * settings for the gray modes
980 */
981 usb_AdjustCISLampSettings( dev, SANE_TRUE );
982
983 if( scan->dwFlag & SCANFLAG_BottomUp)
984 scan->lBufAdjust = -(long)scan->dwBytesLine;
985 else
986 scan->lBufAdjust = scan->dwBytesLine;
987
988 /* LM9831 has a BUG in 16-bit mode,
989 * so we generate pseudo 16-bit data from 8-bit
990 */
991 if( scan->sParam.bBitDepth > 8 ) {
992
993 if( _LM9831 == dev->usbDev.HwSetting.chip ) {
994
995 scan->sParam.bBitDepth = 8;
996 scan->dwFlag |= SCANFLAG_Pseudo48;
997 scan->sParam.Size.dwBytes >>= 1;
998 }
999 }
1000
1001 /* Source selection */
1002 if( scan->sParam.bSource == SOURCE_Reflection ) {
1003
1004 dev->usbDev.pSource = &caps->Normal;
1005 scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1006 (u_long)dev->usbDev.Normal.lLeft;
1007 scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1008 (u_long)dev->usbDev.Normal.lUp;
1009
1010 } else if( scan->sParam.bSource == SOURCE_Transparency ) {
1011
1012 dev->usbDev.pSource = &caps->Positive;
1013 scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1014 (u_long)dev->usbDev.Positive.lLeft;
1015 scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1016 (u_long)dev->usbDev.Positive.lUp;
1017
1018 } else if( scan->sParam.bSource == SOURCE_Negative ) {
1019
1020 dev->usbDev.pSource = &caps->Negative;
1021 scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1022 (u_long)dev->usbDev.Negative.lLeft;
1023 scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1024 (u_long)dev->usbDev.Negative.lUp;
1025
1026 } else {
1027
1028 dev->usbDev.pSource = &dev->usbDev.Caps.Adf;
1029 scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1030 (u_long)dev->usbDev.Normal.lLeft;
1031 scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1032 (u_long)dev->usbDev.Normal.lUp;
1033 }
1034
1035 if( scan->sParam.bSource == SOURCE_ADF ) {
1036
1037 if( scan->dwFlag & SCANDEF_ContinuousScan )
1038 dev->usbDev.fLastScanIsAdf = SANE_TRUE;
1039 else
1040 dev->usbDev.fLastScanIsAdf = SANE_FALSE;
1041 }
1042
1043 return 0;
1044 }
1045
1046 /**
1047 */
1048 static int
usbDev_stopScan( Plustek_Device *dev )1049 usbDev_stopScan( Plustek_Device *dev )
1050 {
1051 DBG( _DBG_INFO, "usbDev_stopScan()\n" );
1052
1053 /* in cancel-mode we first stop the motor */
1054 usb_ScanEnd( dev );
1055
1056 dev->scanning.dwFlag = 0;
1057
1058 if( NULL != dev->scanning.pScanBuffer ) {
1059
1060 free( dev->scanning.pScanBuffer );
1061 dev->scanning.pScanBuffer = NULL;
1062 usb_StartLampTimer( dev );
1063 }
1064 return 0;
1065 }
1066
1067 /**
1068 */
1069 static int
usbDev_startScan( Plustek_Device *dev )1070 usbDev_startScan( Plustek_Device *dev )
1071 {
1072 ScanDef *scan = &dev->scanning;
1073 DBG( _DBG_INFO, "usbDev_startScan()\n" );
1074
1075 /* HEINER: Preview currently not working correctly */
1076 #if 0
1077 if( scan->dwFlag & SCANDEF_QualityScan )
1078 dev->usbDev.a_bRegs[0x0a] = 0;
1079 else
1080 dev->usbDev.a_bRegs[0x0a] = 1;
1081 #endif
1082 dev->usbDev.a_bRegs[0x0a] = 0;
1083
1084 if((scan->dwFlag & SCANDEF_Adf) && (scan->dwFlag & SCANDEF_ContinuousScan)) {
1085 scan->fCalibrated = SANE_TRUE;
1086 } else {
1087 scan->fCalibrated = SANE_FALSE;
1088 }
1089
1090 scan->sParam.PhyDpi.x = usb_SetAsicDpiX(dev,scan->sParam.UserDpi.x);
1091 scan->sParam.PhyDpi.y = usb_SetAsicDpiY(dev,scan->sParam.UserDpi.y);
1092
1093 /* Allocate shading/scan buffer */
1094 scan->pScanBuffer = (u_long*)malloc( _SCANBUF_SIZE );
1095
1096 if( scan->pScanBuffer == NULL )
1097 return _E_ALLOC;
1098
1099 scan->dwFlag |= SCANFLAG_StartScan;
1100
1101 /* some devices (esp. BearPaw) do need a lamp switch off before
1102 * switching it on again. Otherwise it might happen that the lamp
1103 * remains off
1104 */
1105 if(dev->usbDev.Caps.workaroundFlag & _WAF_LOFF_ON_START) {
1106 if (usb_GetLampStatus(dev))
1107 usb_LampOn( dev, SANE_FALSE, SANE_TRUE );
1108 }
1109
1110 usb_LampOn( dev, SANE_TRUE, SANE_TRUE );
1111
1112 m_fStart = m_fFirst = SANE_TRUE;
1113 m_fAutoPark = (scan->dwFlag&SCANFLAG_StillModule)?SANE_FALSE:SANE_TRUE;
1114
1115 if( usb_IsSheetFedDevice(dev))
1116 if(usb_InCalibrationMode(dev))
1117 m_fAutoPark = SANE_FALSE;
1118
1119 usb_StopLampTimer( dev );
1120 return 0;
1121 }
1122
1123 /**
1124 * do the reading stuff here...
1125 * first we perform the calibration step, and then we read the image
1126 * line for line
1127 */
1128 static int
usbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf )1129 usbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf )
1130 {
1131 int result;
1132 SANE_Bool use_alt_cal = SANE_FALSE;
1133 ScanDef *scan = &dev->scanning;
1134 DCapsDef *scaps = &dev->usbDev.Caps;
1135 HWDef *hw = &dev->usbDev.HwSetting;
1136
1137 DBG( _DBG_INFO, "usbDev_PrepareScan()\n" );
1138
1139 /* check the current position of the sensor and move it back
1140 * to it's home position if necessary...
1141 */
1142 if( !usb_IsSheetFedDevice(dev))
1143 usb_SensorStatus( dev );
1144
1145 /* CIS devices need special handling... */
1146 if( usb_IsCISDevice(dev)) {
1147 use_alt_cal = SANE_TRUE;
1148
1149 } else {
1150
1151 if( dev->adj.altCalibrate )
1152 use_alt_cal = SANE_TRUE;
1153 }
1154
1155 /* for the skip functionality use the "old" calibration functions */
1156 if( dev->usbDev.Caps.workaroundFlag & _WAF_BYPASS_CALIBRATION ) {
1157 use_alt_cal = SANE_FALSE;
1158 }
1159
1160 if( use_alt_cal ) {
1161 result = cano_DoCalibration( dev );
1162 } else {
1163 result = usb_DoCalibration( dev );
1164 }
1165
1166 if( SANE_TRUE != result ) {
1167 DBG( _DBG_ERROR, "calibration failed!!!\n" );
1168 return _E_ABORT;
1169 }
1170
1171 if( dev->adj.cacheCalData )
1172 usb_SaveCalData( dev );
1173
1174 DBG( _DBG_INFO, "calibration done.\n" );
1175 if( usb_InCalibrationMode(dev))
1176 return 0;
1177
1178 if( !(scan->dwFlag & SCANFLAG_Scanning)) {
1179
1180 usleep( 10 * 1000 );
1181
1182 /* need to preset that here, as we need it during parameter setting
1183 */
1184 scan->bLinesToSkip = (u_char)(scan->sParam.PhyDpi.y / 50);
1185
1186 scan->dwLinesDiscard = 0;
1187 if( scan->sParam.bChannels == 3 ) {
1188 scan->dwLinesDiscard = (u_long)scaps->bSensorDistance *
1189 scan->sParam.PhyDpi.y / scaps->OpticDpi.y;
1190 scan->dwLinesDiscard <<= 1;
1191 }
1192
1193 if( !usb_SetScanParameters( dev, &scan->sParam )) {
1194 DBG( _DBG_ERROR, "Setting Scan Parameters failed!\n" );
1195 return 0;
1196 }
1197
1198 /* if we bypass the calibration step, we wait on lamp warmup here...
1199 */
1200 if( scaps->workaroundFlag & _WAF_BYPASS_CALIBRATION ) {
1201 if( !usb_Wait4Warmup( dev )) {
1202 DBG( _DBG_INFO, "usbDev_Prepare() - Cancel detected...\n" );
1203 return 0;
1204 }
1205 }
1206
1207 scan->pbScanBufBegin = (u_char*)scan->pScanBuffer;
1208
1209 if((dev->caps.dwFlag & SFLAG_ADF) && (scaps->OpticDpi.x == 600))
1210 scan->dwLinesScanBuf = 8;
1211 else
1212 scan->dwLinesScanBuf = 32;
1213
1214 scan->dwBytesScanBuf = scan->dwLinesScanBuf *
1215 scan->sParam.Size.dwPhyBytes;
1216
1217 scan->dwNumberOfScanBufs = _SCANBUF_SIZE / scan->dwBytesScanBuf;
1218 scan->dwLinesPerScanBufs = scan->dwNumberOfScanBufs *
1219 scan->dwLinesScanBuf;
1220 scan->pbScanBufEnd = scan->pbScanBufBegin +
1221 scan->dwLinesPerScanBufs *
1222 scan->sParam.Size.dwPhyBytes;
1223 scan->dwRedShift = 0;
1224 scan->dwBlueShift = 0;
1225 scan->dwGreenShift = 0;
1226
1227 /* CCD scanner */
1228 if( scan->sParam.bChannels == 3 ) {
1229
1230 scan->dwLinesDiscard = (u_long)scaps->bSensorDistance *
1231 scan->sParam.PhyDpi.y / scaps->OpticDpi.y;
1232
1233 switch( scaps->bSensorOrder ) {
1234
1235 case SENSORORDER_rgb:
1236 scan->Red.pb = scan->pbScanBufBegin;
1237 scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1238 scan->sParam.Size.dwPhyBytes;
1239 scan->Blue.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1240 scan->sParam.Size.dwPhyBytes * 2UL;
1241 break;
1242
1243 case SENSORORDER_rbg:
1244 scan->Red.pb = scan->pbScanBufBegin;
1245 scan->Blue.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1246 scan->sParam.Size.dwPhyBytes;
1247 scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1248 scan->sParam.Size.dwPhyBytes * 2UL;
1249 break;
1250
1251 case SENSORORDER_gbr:
1252 scan->Green.pb = scan->pbScanBufBegin;
1253 scan->Blue.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1254 scan->sParam.Size.dwPhyBytes;
1255 scan->Red.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1256 scan->sParam.Size.dwPhyBytes * 2UL;
1257 break;
1258
1259 case SENSORORDER_grb:
1260 scan->Green.pb = scan->pbScanBufBegin;
1261 scan->Red.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1262 scan->sParam.Size.dwPhyBytes;
1263 scan->Blue.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1264 scan->sParam.Size.dwPhyBytes * 2UL;
1265 break;
1266
1267 case SENSORORDER_brg:
1268 scan->Blue.pb = scan->pbScanBufBegin;
1269 scan->Red.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1270 scan->sParam.Size.dwPhyBytes;
1271 scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1272 scan->sParam.Size.dwPhyBytes * 2UL;
1273 break;
1274
1275 case SENSORORDER_bgr:
1276 scan->Blue.pb = scan->pbScanBufBegin;
1277 scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1278 scan->sParam.Size.dwPhyBytes;
1279 scan->Red.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1280 scan->sParam.Size.dwPhyBytes * 2UL;
1281 }
1282
1283 /* double it for last channel */
1284 scan->dwLinesDiscard <<= 1;
1285 scan->dwGreenShift = (7UL+scan->sParam.bBitDepth) >> 3;
1286 scan->Green.pb += scan->dwGreenShift;
1287 scan->Blue.pb += (scan->dwGreenShift * 2);
1288
1289 if( scan->dwFlag & SCANFLAG_bgr) {
1290
1291 u_char *pb = scan->Blue.pb;
1292
1293 scan->Blue.pb = scan->Red.pb;
1294 scan->Red.pb = pb;
1295 scan->dwBlueShift = 0;
1296 scan->dwRedShift = scan->dwGreenShift << 1;
1297 } else {
1298 scan->dwRedShift = 0;
1299 scan->dwBlueShift = scan->dwGreenShift << 1;
1300 }
1301
1302 } else {
1303
1304 /* CIS section */
1305
1306 /* this might be a simple gray operation or AFE 1 channel op */
1307 scan->dwLinesDiscard = 0;
1308 scan->Green.pb = scan->pbScanBufBegin;
1309
1310 if(( scan->sParam.bDataType == SCANDATATYPE_Color ) &&
1311 ( hw->bReg_0x26 & _ONE_CH_COLOR )) {
1312
1313 u_char so;
1314 u_long len = scan->sParam.Size.dwPhyBytes / 3;
1315
1316 so = scaps->bSensorOrder;
1317 if (_WAF_RESET_SO_TO_RGB & scaps->workaroundFlag) {
1318 if (scaps->bPCB != 0) {
1319 if (scan->sParam.PhyDpi.x > scaps->bPCB) {
1320 so = SENSORORDER_rgb;
1321 DBG(_DBG_INFO, "* Resetting sensororder to RGB\n");
1322 }
1323 }
1324 }
1325
1326 switch( so ) {
1327
1328 case SENSORORDER_rgb:
1329 scan->Red.pb = scan->pbScanBufBegin;
1330 scan->Green.pb = scan->pbScanBufBegin + len;
1331 scan->Blue.pb = scan->pbScanBufBegin + len * 2UL;
1332 break;
1333
1334 case SENSORORDER_gbr:
1335 scan->Green.pb = scan->pbScanBufBegin;
1336 scan->Blue.pb = scan->pbScanBufBegin + len;
1337 scan->Red.pb = scan->pbScanBufBegin + len * 2UL;
1338 break;
1339 default:
1340 DBG( _DBG_ERROR, "CIS: This bSensorOrder "
1341 "is not defined\n" );
1342 return _E_INTERNAL;
1343 }
1344 }
1345 }
1346
1347 /* set a function to process the RAW data... */
1348 usb_GetImageProc( dev );
1349
1350 if( scan->sParam.bSource == SOURCE_ADF )
1351 scan->dwFlag |= SCANFLAG_StillModule;
1352
1353 DBG( _DBG_INFO, "* scan->dwFlag=0x%08lx\n", scan->dwFlag );
1354
1355 if( !usb_ScanBegin( dev,
1356 (scan->dwFlag&SCANFLAG_StillModule) ? SANE_FALSE:SANE_TRUE)) {
1357
1358 return _E_INTERNAL;
1359 }
1360
1361 scan->dwFlag |= SCANFLAG_Scanning;
1362
1363 if( scan->sParam.UserDpi.y != scan->sParam.PhyDpi.y ) {
1364
1365 if( scan->sParam.UserDpi.y < scan->sParam.PhyDpi.y ) {
1366
1367 scan->wSumY = scan->sParam.PhyDpi.y - scan->sParam.UserDpi.y;
1368 scan->dwFlag |= SCANFLAG_SampleY;
1369 DBG( _DBG_INFO, "SampleY Flag set (%u != %u, wSumY=%u)\n",
1370 scan->sParam.UserDpi.y, scan->sParam.PhyDpi.y, scan->wSumY );
1371 }
1372 }
1373 }
1374
1375 dumpPicInit( &scan->sParam, "plustek-pic.raw" );
1376
1377 /* here the NT driver uses an extra reading thread...
1378 * as the SANE stuff already forked the driver to read data, I think
1379 * we should only read data by using a function...
1380 */
1381 scan->dwLinesUser = scan->sParam.Size.dwLines;
1382 if( !scan->dwLinesUser )
1383 return _E_BUFFER_TOO_SMALL;
1384
1385 if( scan->sParam.Size.dwLines < scan->dwLinesUser )
1386 scan->dwLinesUser = scan->sParam.Size.dwLines;
1387
1388 scan->sParam.Size.dwLines -= scan->dwLinesUser;
1389 if( scan->dwFlag & SCANFLAG_BottomUp )
1390 scan->UserBuf.pb = buf + (scan->dwLinesUser - 1) * scan->dwBytesLine;
1391 else
1392 scan->UserBuf.pb = buf;
1393
1394 DBG(_DBG_INFO,"Reading the data now!\n" );
1395 DBG(_DBG_INFO,"PhyDpi.x = %u\n", scan->sParam.PhyDpi.x );
1396 DBG(_DBG_INFO,"PhyDpi.y = %u\n", scan->sParam.PhyDpi.y );
1397 DBG(_DBG_INFO,"UserDpi.x = %u\n", scan->sParam.UserDpi.x );
1398 DBG(_DBG_INFO,"UserDpi.y = %u\n", scan->sParam.UserDpi.y );
1399 DBG(_DBG_INFO,"NumberOfScanBufs = %lu\n",scan->dwNumberOfScanBufs);
1400 DBG(_DBG_INFO,"LinesPerScanBufs = %lu\n",scan->dwLinesPerScanBufs);
1401 DBG(_DBG_INFO,"dwPhyBytes = %lu\n",scan->sParam.Size.dwPhyBytes);
1402 DBG(_DBG_INFO,"dwPhyPixels = %lu\n",scan->sParam.Size.dwPhyPixels);
1403 DBG(_DBG_INFO,"dwTotalBytes = %lu\n",scan->sParam.Size.dwTotalBytes);
1404 DBG(_DBG_INFO,"dwPixels = %lu\n",scan->sParam.Size.dwPixels);
1405 DBG(_DBG_INFO,"dwBytes = %lu\n",scan->sParam.Size.dwBytes);
1406 DBG(_DBG_INFO,"dwValidPixels = %lu\n",scan->sParam.Size.dwValidPixels);
1407 DBG(_DBG_INFO,"dwBytesScanBuf = %lu\n",scan->dwBytesScanBuf );
1408 DBG(_DBG_INFO,"dwLinesDiscard = %lu\n",scan->dwLinesDiscard );
1409 DBG(_DBG_INFO,"dwLinesToSkip = %u\n", scan->bLinesToSkip );
1410 DBG(_DBG_INFO,"dwLinesUser = %lu\n",scan->dwLinesUser );
1411 DBG(_DBG_INFO,"dwBytesLine = %lu\n",scan->dwBytesLine );
1412
1413 scan->pbGetDataBuf = scan->pbScanBufBegin;
1414
1415 scan->dwLinesToProcess = usb_ReadData( dev );
1416 if( 0 == scan->dwLinesToProcess )
1417 return _E_DATAREAD;
1418
1419 return 0;
1420 }
1421
1422 /** as the name says, read one line...
1423 */
1424 static int
usbDev_ReadLine( Plustek_Device *dev )1425 usbDev_ReadLine( Plustek_Device *dev )
1426 {
1427 int wrap;
1428 u_long cur;
1429 ScanDef *scan = &dev->scanning;
1430 HWDef *hw = &dev->usbDev.HwSetting;
1431
1432 cur = scan->dwLinesUser;
1433
1434 /* we stay within this sample loop until one line has been processed for
1435 * the user...
1436 */
1437 while( cur == scan->dwLinesUser ) {
1438
1439 if( usb_IsEscPressed()) {
1440 DBG( _DBG_INFO, "readLine() - Cancel detected...\n" );
1441 return _E_ABORT;
1442 }
1443
1444 if( !(scan->dwFlag & SCANFLAG_SampleY)) {
1445
1446 scan->pfnProcess( dev );
1447
1448 /* Adjust user buffer pointer */
1449 scan->UserBuf.pb += scan->lBufAdjust;
1450 scan->dwLinesUser--;
1451
1452 } else {
1453
1454 scan->wSumY += scan->sParam.UserDpi.y;
1455
1456 if( scan->wSumY >= scan->sParam.PhyDpi.y ) {
1457 scan->wSumY -= scan->sParam.PhyDpi.y;
1458
1459 scan->pfnProcess( dev );
1460
1461 /* Adjust user buffer pointer */
1462 scan->UserBuf.pb += scan->lBufAdjust;
1463 scan->dwLinesUser--;
1464 }
1465 }
1466
1467 /* Adjust get buffer pointers */
1468 wrap = 0;
1469
1470 if( scan->sParam.bDataType == SCANDATATYPE_Color ) {
1471
1472 scan->Red.pb += scan->sParam.Size.dwPhyBytes;
1473 if( scan->Red.pb >= scan->pbScanBufEnd ) {
1474 scan->Red.pb = scan->pbScanBufBegin + scan->dwRedShift;
1475 wrap = 1;
1476 }
1477
1478 scan->Green.pb += scan->sParam.Size.dwPhyBytes;
1479 if( scan->Green.pb >= scan->pbScanBufEnd ) {
1480 scan->Green.pb = scan->pbScanBufBegin + scan->dwGreenShift;
1481 wrap = 1;
1482 }
1483
1484 scan->Blue.pb += scan->sParam.Size.dwPhyBytes;
1485 if( scan->Blue.pb >= scan->pbScanBufEnd ) {
1486 scan->Blue.pb = scan->pbScanBufBegin + scan->dwBlueShift;
1487 wrap = 1;
1488 }
1489 } else {
1490 scan->Green.pb += scan->sParam.Size.dwPhyBytes;
1491 if( scan->Green.pb >= scan->pbScanBufEnd )
1492 scan->Green.pb = scan->pbScanBufBegin + scan->dwGreenShift;
1493 }
1494
1495 /* on any wrap-around of the get pointers in one channel mode
1496 * we have to reset them
1497 */
1498 if( wrap ) {
1499
1500 u_long len = scan->sParam.Size.dwPhyBytes;
1501
1502 if( hw->bReg_0x26 & _ONE_CH_COLOR ) {
1503
1504 if(scan->sParam.bDataType == SCANDATATYPE_Color) {
1505 len /= 3;
1506 }
1507 scan->Red.pb = scan->pbScanBufBegin;
1508 scan->Green.pb = scan->pbScanBufBegin + len;
1509 scan->Blue.pb = scan->pbScanBufBegin + len * 2UL;
1510 }
1511 }
1512
1513 /* line processed, check if we have to get more...
1514 */
1515 scan->dwLinesToProcess--;
1516
1517 if( 0 == scan->dwLinesToProcess ) {
1518
1519 scan->dwLinesToProcess = usb_ReadData( dev );
1520 if( 0 == scan->dwLinesToProcess ) {
1521
1522 if( usb_IsEscPressed())
1523 return _E_ABORT;
1524 }
1525 }
1526 }
1527 return 0;
1528 }
1529
1530 /* END PLUSTEK-USB.C ........................................................*/
1531