1 /*.............................................................................
2 * Project : SANE library for Plustek flatbed scanners.
3 *.............................................................................
4 */
5
6 /** @file plustek-usbscan.c
7 * @brief Scanning...
8 *
9 * Based on sources acquired from Plustek Inc.<br>
10 * Copyright (C) 2001-2013 Gerhard Jaeger <gerhard@gjaeger.de>
11 *
12 * History:
13 * - 0.40 - starting version of the USB support
14 * - 0.41 - minor fixes
15 * - 0.42 - added some stuff for CIS devices
16 * - 0.43 - no changes
17 * - 0.44 - added CIS specific settings and calculations
18 * - removed usb_IsEscPressed
19 * - 0.45 - fixed the special setting stuff for CanoScan
20 * - fixed pixel calculation for binary modes
21 * - fixed cancel hang problem
22 * - fixed CIS PhyBytes adjustment
23 * - removed CanoScan specific setting stuff
24 * - 0.46 - fixed problem in usb_SetScanParameters()
25 * - 0.47 - no changes
26 * - 0.48 - minor fixes
27 * - 0.49 - a_bRegs is now part of the device structure
28 * - using now PhyDpi.y as selector for the motor MCLK range
29 * - changed usb_MapDownload prototype
30 * - 0.50 - cleanup
31 * - 0.51 - added usb_get_res() and usb_GetPhyPixels()
32 * - 0.52 - removed stuff, that will most probably never be used
33 * .
34 * <hr>
35 * This file is part of the SANE package.
36 *
37 * This program is free software; you can redistribute it and/or
38 * modify it under the terms of the GNU General Public License as
39 * published by the Free Software Foundation; either version 2 of the
40 * License, or (at your option) any later version.
41 *
42 * This program is distributed in the hope that it will be useful, but
43 * WITHOUT ANY WARRANTY; without even the implied warranty of
44 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45 * General Public License for more details.
46 *
47 * You should have received a copy of the GNU General Public License
48 * along with this program. If not, see <https://www.gnu.org/licenses/>.
49 *
50 * As a special exception, the authors of SANE give permission for
51 * additional uses of the libraries contained in this release of SANE.
52 *
53 * The exception is that, if you link a SANE library with other files
54 * to produce an executable, this does not by itself cause the
55 * resulting executable to be covered by the GNU General Public
56 * License. Your use of that executable is in no way restricted on
57 * account of linking the SANE library code into it.
58 *
59 * This exception does not, however, invalidate any other reasons why
60 * the executable file might be covered by the GNU General Public
61 * License.
62 *
63 * If you submit changes to SANE to the maintainers to be included in
64 * a subsequent release, you agree by submitting the changes that
65 * those changes may be distributed with this exception intact.
66 *
67 * If you write modifications of your own for SANE, it is your choice
68 * whether to permit this exception to apply to your modifications.
69 * If you do not wish that, delete this exception notice.
70 * <hr>
71 */
72
73 #define DIVIDER 8
74
75 /** array used to get motor-settings and mclk-settings
76 */
77 static int dpi_ranges[] = { 75,100,150,200,300,400,600,800,1200,2400 };
78
79 static u_char bMaxITA;
80
81 static SANE_Bool m_fAutoPark;
82 static SANE_Bool m_fFirst;
83 static double m_dHDPIDivider;
84 static double m_dMCLKDivider;
85 static ScanParam *m_pParam;
86 static u_char m_bLineRateColor;
87 static u_char m_bCM;
88 static u_char m_bIntTimeAdjust;
89 static u_char m_bOldScanData;
90 static u_short m_wFastFeedStepSize;
91 static u_short m_wLineLength;
92 static u_short m_wStepSize;
93 static u_long m_dwPauseLimit;
94
95 static SANE_Bool m_fStart = SANE_FALSE;
96
97 /* Prototype... */
98 static SANE_Bool usb_DownloadShadingData( Plustek_Device*, u_char );
99
100 /** returns the min of the two values val1 and val2
101 * @param val1 - first parameter
102 * @param val2 - second parameter
103 * @return val1 if val1 < val2, else val1
104 */
105 static u_long
usb_min(u_long val1,u_long val2)106 usb_min( u_long val1, u_long val2 )
107 {
108 if( val1 > val2 )
109 return val2;
110 return val1;
111 }
112
113 /** returns the max of the two values val1 and val2
114 * @param val1 - first parameter
115 * @param val2 - second parameter
116 * @return val1 if val1 > val2, else val2
117 */
118 static u_long
usb_max(u_long val1,u_long val2)119 usb_max( u_long val1, u_long val2 )
120 {
121 if( val1 > val2 )
122 return val1;
123 return val2;
124 }
125
126 /** function to get the possible resolution for a specific base resolution,
127 * according to the dividers a LM983x offers.
128 * @param base - scanners optical resolution
129 * @param idx - which divider to use
130 */
131 static u_short
usb_get_res(u_short base,u_short idx)132 usb_get_res( u_short base, u_short idx )
133 {
134 double div_list[DIVIDER] = { 12.0, 8.0, 6.0, 4.0, 3.0, 2.0, 1.5, 1.0 };
135
136 if( idx == 0 || idx > DIVIDER )
137 return 0;
138
139 return (u_short)((double)base/div_list[idx-1]);
140 }
141
142 /** Set the horizontal DPI divider.
143 * Affected registers:<br>
144 * 0x09 - Horizontal DPI divider HDPI_DIV<br>
145 *
146 * @param dev - pointer to our device structure,
147 * it should contain all we need
148 * @param xdpi - user specified horizontal resolution
149 * @return - the function returns the "normalized" horizontal resolution.
150 */
151 static u_short
usb_SetAsicDpiX(Plustek_Device * dev,u_short xdpi)152 usb_SetAsicDpiX( Plustek_Device *dev, u_short xdpi )
153 {
154 u_short res;
155 ScanDef *scanning = &dev->scanning;
156 DCapsDef *scaps = &dev->usbDev.Caps;
157 u_char *regs = dev->usbDev.a_bRegs;
158
159 /* limit xdpi to lower value for certain devices...
160 */
161 if( scaps->OpticDpi.x == 1200 &&
162 scanning->sParam.bDataType != SCANDATATYPE_Color &&
163 xdpi < 150 &&
164 scanning->sParam.bDataType == SCANDATATYPE_BW ) {
165 xdpi = 150;
166 DBG( _DBG_INFO2, "* LIMIT XDPI to %udpi\n", xdpi );
167 }
168
169 m_dHDPIDivider = (double)scaps->OpticDpi.x / xdpi;
170
171 if (m_dHDPIDivider < 1.5)
172 {
173 m_dHDPIDivider = 1.0;
174 regs[0x09] = 0;
175 }
176 else if (m_dHDPIDivider < 2.0)
177 {
178 m_dHDPIDivider = 1.5;
179 regs[0x09] = 1;
180 }
181 else if (m_dHDPIDivider < 3.0)
182 {
183 m_dHDPIDivider = 2.0;
184 regs[0x09] = 2;
185 }
186 else if (m_dHDPIDivider < 4.0)
187 {
188 m_dHDPIDivider = 3.0;
189 regs[0x09] = 3;
190 }
191 else if (m_dHDPIDivider < 6.0)
192 {
193 m_dHDPIDivider = 4.0;
194 regs[0x09] = 4;
195 }
196 else if (m_dHDPIDivider < 8.0)
197 {
198 m_dHDPIDivider = 6.0;
199 regs[0x09] = 5;
200 }
201 else if (m_dHDPIDivider < 12.0)
202 {
203 m_dHDPIDivider = 8.0;
204 regs[0x09] = 6;
205 }
206 else
207 {
208 m_dHDPIDivider = 12.0;
209 regs[0x09] = 7;
210 }
211
212 /* adjust, if any turbo/preview mode is set, should be 0 here... */
213 if( regs[0x0a] )
214 regs[0x09] -= ((regs[0x0a] >> 2) + 2);
215
216 DBG( _DBG_INFO2, "* HDPI: %.3f\n", m_dHDPIDivider );
217 res = (u_short)((double)scaps->OpticDpi.x / m_dHDPIDivider);
218
219 DBG( _DBG_INFO2, "* XDPI=%u, HDPI=%.3f\n", res, m_dHDPIDivider );
220 return res;
221 }
222
223 /**
224 * @param dev - pointer to our device structure,
225 * it should contain all we need
226 * @param ydpi - user specified vertical resolution
227 * @return -
228 */
229 static u_short
usb_SetAsicDpiY(Plustek_Device * dev,u_short ydpi)230 usb_SetAsicDpiY( Plustek_Device *dev, u_short ydpi )
231 {
232 ScanDef *scanning = &dev->scanning;
233 DCapsDef *sCaps = &dev->usbDev.Caps;
234 HWDef *hw = &dev->usbDev.HwSetting;
235
236 u_short wMinDpi, wDpi;
237
238 if(0 != sCaps->bSensorDistance )
239 wMinDpi = sCaps->OpticDpi.y / sCaps->bSensorDistance;
240 else
241 wMinDpi = 75;
242
243 /* Here we might have to check against the MinDpi value ! */
244 wDpi = (ydpi + wMinDpi - 1) / wMinDpi * wMinDpi;
245
246 /*
247 * HEINER: added '*2'
248 */
249 if( wDpi > sCaps->OpticDpi.y * 2 )
250 wDpi = sCaps->OpticDpi.y * 2;
251
252 if( (hw->motorModel == MODEL_Tokyo600) ||
253 !_IS_PLUSTEKMOTOR(hw->motorModel)) {
254 /* return wDpi; */
255 } else if( sCaps->wFlags & DEVCAPSFLAG_Adf && sCaps->OpticDpi.x == 600 ) {
256 /* for ADF scanner color mode 300 dpi big noise */
257 if( scanning->sParam.bDataType == SCANDATATYPE_Color &&
258 scanning->sParam.bBitDepth > 8 && wDpi < 300 ) {
259 wDpi = 300;
260 }
261 } else if( sCaps->OpticDpi.x == 1200 ) {
262 if( scanning->sParam.bDataType != SCANDATATYPE_Color && wDpi < 200) {
263 wDpi = 200;
264 }
265 }
266
267 DBG( _DBG_INFO2, "* YDPI=%u, MinDPIY=%u\n", wDpi, wMinDpi );
268 return wDpi;
269 }
270
271 /** set color mode and sensor configuration stuff, according to the data mode
272 * Affected registers:<br>
273 * 0x26 - 0x27 - Color Mode settings<br>
274 * 0x0f - 0x18 - Sensor Configuration - directly from the HwDefs<br>
275 * 0x09 - add Data Mode and Pixel Packing<br>
276 *
277 * @param dev - pointer to our device structure,
278 * it should contain all we need
279 * @param pParam - pointer to the current scan parameters
280 * @return - Nothing
281 */
282 static void
usb_SetColorAndBits(Plustek_Device * dev,ScanParam * pParam)283 usb_SetColorAndBits( Plustek_Device *dev, ScanParam *pParam )
284 {
285 HWDef *hw = &dev->usbDev.HwSetting;
286 u_char *regs = dev->usbDev.a_bRegs;
287
288 /* Set pixel packing, data mode and AFE operation */
289 switch( pParam->bDataType ) {
290 case SCANDATATYPE_Color:
291 m_bCM = 3;
292 regs[0x26] = hw->bReg_0x26 & 0x7;
293
294 /* if set to one channel color, we select the blue channel
295 * as input source, this is the default, but I don't know
296 * what happens, if we deselect this
297 */
298 if( regs[0x26] & _ONE_CH_COLOR )
299 regs[0x26] |= (_BLUE_CH | 0x01);
300
301 memcpy( ®s[0x0f], hw->bReg_0x0f_Color, 10 );
302 break;
303
304 case SCANDATATYPE_Gray:
305 m_bCM = 1;
306 regs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04;
307 memcpy( ®s[0x0f], hw->bReg_0x0f_Mono, 10 );
308 break;
309
310 case SCANDATATYPE_BW:
311 m_bCM = 1;
312 regs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04;
313 memcpy( ®s[0x0f], hw->bReg_0x0f_Mono, 10 );
314 break;
315 }
316
317 regs[0x27] = hw->bReg_0x27;
318
319 if( pParam->bBitDepth > 8 ) {
320 regs[0x09] |= 0x20; /* 14/16bit image data */
321
322 } else if( pParam->bBitDepth == 8 ) {
323 regs[0x09] |= 0x18; /* 8bits/per pixel */
324 }
325 }
326
327 /**
328 * Data output from NS983X should be times of 2-byte and every line
329 * will append 2 status bytes
330 */
331 static void
usb_GetPhyPixels(Plustek_Device * dev,ScanParam * sp)332 usb_GetPhyPixels( Plustek_Device *dev, ScanParam *sp )
333 {
334 sp->Size.dwValidPixels = sp->Size.dwPixels * sp->PhyDpi.x / sp->UserDpi.x;
335
336 if (sp->bBitDepth == 1) {
337
338 /* Pixels should be times of 16 */
339 sp->Size.dwPhyPixels =
340 (sp->Size.dwValidPixels + 15UL) & 0xfffffff0UL;
341 sp->Size.dwPhyBytes = sp->Size.dwPhyPixels / 8UL + 2UL;
342
343 } else if (sp->bBitDepth == 8) {
344
345 /* Pixels should be times of 2 */
346 sp->Size.dwPhyPixels = (sp->Size.dwValidPixels + 1UL) & 0xfffffffeUL;
347 sp->Size.dwPhyBytes = sp->Size.dwPhyPixels * sp->bChannels + 2UL;
348
349 /* need to be adjusted for CIS devices in color mode */
350 if(usb_IsCISDevice( dev ) && (sp->bDataType == SCANDATATYPE_Color)) {
351 sp->Size.dwPhyBytes *= 3;
352 }
353 }
354 else /* sp->bBitDepth == 16 */
355 {
356 sp->Size.dwPhyPixels = sp->Size.dwValidPixels;
357 sp->Size.dwPhyBytes = sp->Size.dwPhyPixels * 2 * sp->bChannels + 2UL;
358
359 /* need to be adjusted for CIS devices in color mode */
360 if(usb_IsCISDevice( dev ) && (sp->bDataType == SCANDATATYPE_Color)) {
361 sp->Size.dwPhyBytes *= 3;
362 }
363 }
364 }
365
366 /** Calculate basic image settings like the number of physical bytes per line
367 * etc...
368 * Affected registers:<br>
369 * 0x22/0x23 - Data Pixels Start<br>
370 * 0x24/0x25 - Data Pixels End<br>
371 * 0x4a/0x4b - Full Steps to Skip at Start of Scan
372 *
373 * @param dev - pointer to our device structure,
374 * it should contain all we need
375 * @param pParam - pointer to the current scan parameters
376 * @return - Nothing
377 */
378 static void
usb_GetScanRect(Plustek_Device * dev,ScanParam * sp)379 usb_GetScanRect( Plustek_Device *dev, ScanParam *sp )
380 {
381 u_short wDataPixelStart, wLineEnd;
382
383 DCapsDef *sCaps = &dev->usbDev.Caps;
384 HWDef *hw = &dev->usbDev.HwSetting;
385 u_char *regs = dev->usbDev.a_bRegs;
386
387 /* Convert pixels to physical dpi based */
388 usb_GetPhyPixels( dev, sp );
389
390 /* Compute data start pixel */
391 #if 0
392 /* HEINER: check ADF stuff... */
393 if(sp->bCalibration != PARAM_Gain &&
394 sp->bCalibration != PARAM_Offset && ScanInf.m_fADF)
395 wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL -
396 (u_short)(m_dHDPIDivider * sp->Size.dwValidPixels + 0.5);
397 else
398 #endif
399 wDataPixelStart = (u_short)((u_long)sp->Origin.x *
400 sCaps->OpticDpi.x / 300UL);
401
402 /* during the calibration steps, we read the entire CCD data
403 */
404 if((sp->bCalibration != PARAM_Gain)&&(sp->bCalibration != PARAM_Offset)) {
405 /* HEINER: check ADF stuff... */
406 #if 0
407 if(ScanInf.m_fADF) {
408 wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL -
409 (u_short)(m_dHDPIDivider * sp->Size.dwValidPixels + 0.5);
410 }
411 #endif
412 wDataPixelStart += hw->wActivePixelsStart;
413 }
414
415 wLineEnd = wDataPixelStart + (u_short)(m_dHDPIDivider *
416 sp->Size.dwPhyPixels + 0.5);
417
418 DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u\n",
419 wDataPixelStart, wLineEnd );
420 if( wDataPixelStart & 1 ) {
421
422 wDataPixelStart++;
423 wLineEnd++;
424
425 DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u (ADJ)\n",
426 wDataPixelStart, wLineEnd );
427 }
428
429 regs[0x22] = _HIBYTE( wDataPixelStart );
430 regs[0x23] = _LOBYTE( wDataPixelStart );
431
432 /* should match: wLineEnd-wDataPixelStart%(m_dHDPIDivider*2) = 0!! */
433 regs[0x24] = _HIBYTE( wLineEnd );
434 regs[0x25] = _LOBYTE( wLineEnd );
435
436 DBG( _DBG_INFO2, ">> End-Start=%u, HDPI=%.2f\n",
437 wLineEnd-wDataPixelStart, m_dHDPIDivider);
438
439 /* Y origin */
440 if( sp->bCalibration == PARAM_Scan ) {
441
442 if( hw->motorModel == MODEL_Tokyo600 ) {
443
444 if(sp->PhyDpi.x <= 75)
445 sp->Origin.y += 20;
446 else if(sp->PhyDpi.x <= 100)
447 {
448 if (sp->bDataType == SCANDATATYPE_Color)
449 sp->Origin.y += 0;
450 else
451 sp->Origin.y -= 6;
452 }
453 else if(sp->PhyDpi.x <= 150)
454 {
455 if (sp->bDataType == SCANDATATYPE_Color)
456 sp->Origin.y -= 0;
457 }
458 else if(sp->PhyDpi.x <= 200)
459 {
460 if (sp->bDataType == SCANDATATYPE_Color)
461 sp->Origin.y -= 10;
462 else
463 sp->Origin.y -= 4;
464 }
465 else if(sp->PhyDpi.x <= 300)
466 {
467 if (sp->bDataType == SCANDATATYPE_Color)
468 sp->Origin.y += 16;
469 else
470 sp->Origin.y -= 18;
471 }
472 else if(sp->PhyDpi.x <= 400)
473 {
474 if (sp->bDataType == SCANDATATYPE_Color)
475 sp->Origin.y += 15;
476 else if(sp->bDataType == SCANDATATYPE_BW)
477 sp->Origin.y += 4;
478 }
479 else /* if(sp->PhyDpi.x <= 600) */
480 {
481 if (sp->bDataType == SCANDATATYPE_Gray)
482 sp->Origin.y += 4;
483 }
484 }
485
486 /* Add gray mode offset (Green offset, we assume the CCD are
487 * always be RGB or BGR order).
488 */
489 if (sp->bDataType != SCANDATATYPE_Color)
490 sp->Origin.y += (u_long)(300UL *
491 sCaps->bSensorDistance / sCaps->OpticDpi.y);
492 }
493
494 sp->Origin.y=(u_short)((u_long)sp->Origin.y * hw->wMotorDpi/300UL);
495
496 /* Something wrong, but I can not find it. */
497 if( hw->motorModel == MODEL_HuaLien && sCaps->OpticDpi.x == 600)
498 sp->Origin.y = sp->Origin.y * 297 / 298;
499
500 DBG(_DBG_INFO2,"* Full Steps to Skip at Start = 0x%04x\n",
501 sp->Origin.y);
502
503 regs[0x4a] = _HIBYTE( sp->Origin.y );
504 regs[0x4b] = _LOBYTE( sp->Origin.y );
505 }
506
507 /** preset scan stepsize and fastfeed stepsize
508 */
509 static void
usb_PresetStepSize(Plustek_Device * dev,ScanParam * pParam)510 usb_PresetStepSize( Plustek_Device *dev, ScanParam *pParam )
511 {
512 u_short ssize;
513 double mclkdiv = pParam->dMCLK;
514 HWDef *hw = &dev->usbDev.HwSetting;
515 u_char *regs = dev->usbDev.a_bRegs;
516
517 ssize = (u_short)((double)CRYSTAL_FREQ / ( mclkdiv * 8.0 *
518 (double)m_bCM * hw->dMaxMotorSpeed * 4.0 * (double)hw->wMotorDpi));
519
520 regs[0x46] = _HIBYTE( ssize );
521 regs[0x47] = _LOBYTE( ssize );
522 regs[0x48] = _HIBYTE( ssize );
523 regs[0x49] = _LOBYTE( ssize );
524
525 DBG( _DBG_INFO2, "* StepSize(Preset) = %u (0x%04x)\n", ssize, ssize );
526 }
527
528 /** calculate default phase difference DPD
529 */
530 static void
usb_GetDPD(Plustek_Device * dev)531 usb_GetDPD( Plustek_Device *dev )
532 {
533 int qtcnt; /* quarter speed count count reg 51 b2..3 */
534 int hfcnt; /* half speed count reg 51 b0..1 */
535 int strev; /* steps to reverse reg 50 */
536 int dpd; /* calculated dpd reg 52:53 */
537 int st; /* step size reg 46:47 */
538
539 HWDef *hw = &dev->usbDev.HwSetting;
540 u_char *regs = dev->usbDev.a_bRegs;
541
542 qtcnt = (regs[0x51] & 0x30) >> 4; /* quarter speed count */
543 hfcnt = (regs[0x51] & 0xc0) >> 6; /* half speed count */
544
545 if( _LM9831 == hw->chip )
546 strev = regs[0x50] & 0x3f; /* steps to reverse */
547 else /* LM9832/3 */
548 {
549 if (qtcnt == 3)
550 qtcnt = 8;
551 if (hfcnt == 3)
552 hfcnt = 8;
553 strev = regs[0x50]; /* steps to reverse */
554 }
555
556 st = regs[0x46] * 256 + regs[0x47]; /* scan step size */
557
558 if (m_wLineLength == 0)
559 dpd = 0;
560 else
561 {
562 dpd = (((qtcnt * 4) + (hfcnt * 2) + strev) * 4 * st) %
563 (m_wLineLength * m_bLineRateColor);
564 DBG( _DBG_INFO2, "* DPD =%u (0x%04x)\n", dpd, dpd );
565 dpd = m_wLineLength * m_bLineRateColor - dpd;
566 }
567
568 DBG( _DBG_INFO2, "* DPD =%u (0x%04x), step size=%u, steps2rev=%u\n",
569 dpd, dpd, st, strev);
570 DBG( _DBG_INFO2, "* llen=%u, lineRateColor=%u, qtcnt=%u, hfcnt=%u\n",
571 m_wLineLength, m_bLineRateColor, qtcnt, hfcnt );
572
573 regs[0x51] |= (u_char)((dpd >> 16) & 0x03);
574 regs[0x52] = (u_char)(dpd >> 8);
575 regs[0x53] = (u_char)(dpd & 0xFF);
576 }
577
578 #define MCLKDIV_SCALING 2
579 #define _MIN(a,b) ((a) < (b) ? (a) : (b))
580 #define _MAX(a,b) ((a) > (b) ? (a) : (b))
581
582 /**
583 */
584 static int
usb_GetMCLKDiv(Plustek_Device * dev)585 usb_GetMCLKDiv( Plustek_Device *dev )
586 {
587 int j, pixelbits, pixelsperline, r;
588 int minmclk, maxmclk, mclkdiv;
589 double hdpi, min_int_time;
590 u_char *regs = dev->usbDev.a_bRegs;
591 HWDef *hw = &dev->usbDev.HwSetting;
592
593 DBG( _DBG_INFO, "usb_GetMCLKDiv()\n" );
594
595 r = 8; /* line rate */
596 if ((regs[0x26] & 7) == 0)
597 r = 24; /* pixel rate */
598
599 /* use high or low res min integration time */
600 min_int_time = ((regs[0x9]&7) > 2 ? hw->dMinIntegrationTimeLowres:
601 hw->dMinIntegrationTimeHighres);
602
603 minmclk = (int)ceil((double) MCLKDIV_SCALING * CRYSTAL_FREQ *
604 min_int_time /((double)1000. * r * m_wLineLength));
605 minmclk = _MAX(minmclk,MCLKDIV_SCALING);
606
607 maxmclk = (int)(32.5*MCLKDIV_SCALING + .5);
608
609 DBG(_DBG_INFO2,"- lower mclkdiv limit=%f\n",(double)minmclk/MCLKDIV_SCALING);
610 DBG(_DBG_INFO2,"- upper mclkdiv limit=%f\n",(double)maxmclk/MCLKDIV_SCALING);
611
612 /* get the bits per pixel */
613 switch (regs[0x9] & 0x38) {
614 case 0: pixelbits=1; break;
615 case 0x8: pixelbits=2; break;
616 case 0x10: pixelbits=4; break;
617 case 0x18: pixelbits=8; break;
618 default: pixelbits=16;break;
619 }
620
621 /* compute the horizontal dpi (pixels per inch) */
622 j = regs[0x9] & 0x7;
623 hdpi = ((j&1)*.5+1)*(j&2?2:1)*(j&4?4:1);
624
625 pixelsperline = (int)((256*regs[0x24]+regs[0x25]-256*regs[0x22]-regs[0x23])
626 *pixelbits/(hdpi * 8));
627 mclkdiv = (int)ceil((double)MCLKDIV_SCALING * pixelsperline * CRYSTAL_FREQ
628 /((double) 8. * m_wLineLength * dev->transferRate));
629
630 DBG( _DBG_INFO2, "- hdpi = %.3f\n", hdpi );
631 DBG( _DBG_INFO2, "- pixelbits = %u\n", pixelbits );
632 DBG( _DBG_INFO2, "- pixelsperline = %u\n", pixelsperline );
633 DBG( _DBG_INFO2, "- linelen = %u\n", m_wLineLength );
634 DBG( _DBG_INFO2, "- transferrate = %lu\n", dev->transferRate );
635 DBG( _DBG_INFO2, "- MCLK Divider = %u\n", mclkdiv/MCLKDIV_SCALING );
636
637 mclkdiv = _MAX(mclkdiv,minmclk);
638 mclkdiv = _MIN(mclkdiv,maxmclk);
639 DBG( _DBG_INFO2, "- Current MCLK Divider = %u\n", mclkdiv/MCLKDIV_SCALING );
640
641 if( dev->transferRate == 2000000 ) {
642 while (mclkdiv * hdpi < 6.*MCLKDIV_SCALING) {
643 mclkdiv++;
644 }
645 DBG( _DBG_INFO2, "- HIGHSPEED MCLK Divider = %u\n",
646 mclkdiv/MCLKDIV_SCALING );
647 }
648
649 return mclkdiv;
650 }
651
652 /** Plusteks' poor-man MCLK calculation...
653 * at least we give the master clock divider and adjust the step size
654 * and integration time (for 14/16 bit modes)
655 */
656 static double
usb_GetMCLKDivider(Plustek_Device * dev,ScanParam * pParam)657 usb_GetMCLKDivider( Plustek_Device *dev, ScanParam *pParam )
658 {
659 double dMaxIntegrationTime;
660 double dMaxMCLKDivider;
661
662 DCapsDef *sCaps = &dev->usbDev.Caps;
663 HWDef *hw = &dev->usbDev.HwSetting;
664 u_char *regs = dev->usbDev.a_bRegs;
665
666 DBG( _DBG_INFO, "usb_GetMCLKDivider()\n" );
667
668 if( dev->transferRate == 2000000 ) {
669 int mclkdiv = usb_GetMCLKDiv(dev);
670 pParam->dMCLK = (double)mclkdiv/MCLKDIV_SCALING;
671 }
672
673 m_dMCLKDivider = pParam->dMCLK;
674
675 if (m_dHDPIDivider*m_dMCLKDivider >= 5.3/*6*/)
676 m_bIntTimeAdjust = 0;
677 else
678 m_bIntTimeAdjust = ceil( 5.3/*6.0*/ / (m_dHDPIDivider*m_dMCLKDivider));
679
680 if( pParam->bCalibration == PARAM_Scan ) {
681
682 usb_GetMCLKDiv(dev);
683
684 /* Compare Integration with USB speed to find the best ITA value */
685 if( pParam->bBitDepth > 8 ) {
686
687 while( pParam->Size.dwPhyBytes >
688 (m_dMCLKDivider * m_bCM * m_wLineLength / 6 * 9 / 10) *
689 (1 + m_bIntTimeAdjust)) {
690 m_bIntTimeAdjust++;
691 }
692
693 if( hw->motorModel == MODEL_HuaLien &&
694 sCaps->bCCD == kNEC3799 && m_bIntTimeAdjust > bMaxITA) {
695 m_bIntTimeAdjust = bMaxITA;
696 }
697
698 if(((hw->motorModel == MODEL_HP) && (sCaps->bCCD == kNECSLIM))/* ||
699 ( regs[0x26] & _ONE_CH_COLOR )*/) {
700
701 bMaxITA = (u_char)floor((m_dMCLKDivider + 1) / 2.0);
702
703 DBG( _DBG_INFO2, "* MaxITA (HP) = %u\n", bMaxITA );
704 if( m_bIntTimeAdjust > bMaxITA ) {
705 DBG( _DBG_INFO, "* ITA (%u) limited\n", m_bIntTimeAdjust );
706 m_bIntTimeAdjust = bMaxITA;
707 }
708 }
709 }
710 }
711 DBG( _DBG_INFO2, "* Integration Time Adjust = %u (HDPI=%.3f,MCLKD=%.3f)\n",
712 m_bIntTimeAdjust, m_dHDPIDivider, m_dMCLKDivider );
713
714 regs[0x08] = (u_char)((m_dMCLKDivider - 1) * 2);
715 regs[0x19] = m_bIntTimeAdjust;
716
717 if( m_bIntTimeAdjust != 0 ) {
718
719 m_wStepSize = (u_short)((u_long) m_wStepSize *
720 (m_bIntTimeAdjust + 1) / m_bIntTimeAdjust);
721 if( m_wStepSize < 2 )
722 m_wStepSize = 2;
723
724 regs[0x46] = _HIBYTE(m_wStepSize);
725 regs[0x47] = _LOBYTE(m_wStepSize);
726
727 DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n",
728 m_wStepSize, regs[0x46], regs[0x47] );
729 usb_GetDPD( dev );
730 }
731
732 /* Compute maximum MCLK divider base on maximum integration time for
733 * high lamp PWM, use equation 4
734 */
735 dMaxIntegrationTime = hw->dIntegrationTimeHighLamp;
736 dMaxMCLKDivider = (double)CRYSTAL_FREQ * dMaxIntegrationTime /
737 (1000 * 8 * m_bCM * m_wLineLength);
738
739 /* Determine lamp PWM setting */
740 if( m_dMCLKDivider > dMaxMCLKDivider ) {
741
742 DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleLow\n" );
743 regs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleLow );
744 regs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleLow );
745
746 } else {
747
748 DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleHigh\n" );
749 regs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleHigh );
750 regs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleHigh );
751 }
752
753 DBG( _DBG_INFO2, "* Current MCLK Divider = %f\n", m_dMCLKDivider );
754 return m_dMCLKDivider;
755 }
756
757 /** calculate the step size of each scan step
758 */
759 static void
usb_GetStepSize(Plustek_Device * dev,ScanParam * pParam)760 usb_GetStepSize( Plustek_Device *dev, ScanParam *pParam )
761 {
762 HWDef *hw = &dev->usbDev.HwSetting;
763 u_char *regs = dev->usbDev.a_bRegs;
764
765 /* Compute step size using equation 1 */
766 if (m_bIntTimeAdjust != 0) {
767 m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength *
768 m_bLineRateColor * (m_bIntTimeAdjust + 1)) /
769 (4 * hw->wMotorDpi * m_bIntTimeAdjust));
770 } else {
771 m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength *
772 m_bLineRateColor) / (4 * hw->wMotorDpi));
773 }
774
775 if (m_wStepSize < 2)
776 m_wStepSize = 2;
777
778 m_wStepSize = m_wStepSize * 298 / 297;
779
780 regs[0x46] = _HIBYTE( m_wStepSize );
781 regs[0x47] = _LOBYTE( m_wStepSize );
782
783 DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n",
784 m_wStepSize, regs[0x46], regs[0x47] );
785 }
786
787 /**
788 */
789 static void
usb_GetLineLength(Plustek_Device * dev,ScanParam * param)790 usb_GetLineLength( Plustek_Device *dev, ScanParam *param )
791 {
792 /* [note]
793 * The ITA in this moment is always 0, it will be changed later when we
794 * calculate MCLK. This is very strange why this routine will not call
795 * again to get all new value after ITA was changed? If this routine
796 * never call again, maybe we remove all factor with ITA here.
797 */
798 int tr;
799 int tpspd; /* turbo/preview mode speed reg 0a b2..3 */
800 int tpsel; /* turbo/preview mode select reg 0a b0..1 */
801 int gbnd; /* guardband duration reg 0e b4..7 */
802 int dur; /* pulse duration reg 0e b0..3 */
803 int ntr; /* number of tr pulses reg 0d b7 */
804 int afeop; /* scan mode, 0=pixel rate, 1=line rate, */
805 /* 4=1 channel mode a, 5=1 channel mode b, reg 26 b0..2 */
806 int ctmode; /* CIS tr timing mode reg 19 b0..1 */
807 int tp; /* tpspd or 1 if tpsel=0 */
808 int b; /* if ctmode=0, (ntr+1)*((2*gbnd)+dur+1), otherwise 1 */
809 int tradj; /* ITA */
810 int en_tradj;
811 u_short le;
812 HWDef *hw = &dev->usbDev.HwSetting;
813 ClkMotorDef *motor = usb_GetMotorSet( hw->motorModel );
814 u_char *regs = dev->usbDev.a_bRegs;
815
816 tpspd = (regs[0x0a] & 0x0c) >> 2; /* turbo/preview mode speed */
817 tpsel = regs[0x0a] & 3; /* turbo/preview mode select */
818
819 gbnd = (regs[0x0e] & 0xf0) >> 4; /* TR fi1 guardband duration */
820 dur = (regs[0x0e] & 0xf); /* TR pulse duration */
821
822 ntr = regs[0x0d] / 128; /* number of tr pulses */
823
824 afeop = regs[0x26] & 7; /* afe op - 3 channel or 1 channel */
825
826 tradj = regs[0x19] & 0x7f; /* integration time adjust */
827 en_tradj = (tradj) ? 1 : 0;
828
829 ctmode = (regs[0x0b] >> 3) & 3; /* cis tr timing mode */
830
831 m_bLineRateColor = 1;
832 if (afeop == 1 || afeop == 5) /* if 3 channel line or 1 channel mode b */
833 m_bLineRateColor = 3;
834
835 /* according to turbo/preview mode to set value */
836 if( tpsel == 0 ) {
837 tp = 1;
838 } else {
839 tp = tpspd + 2;
840 if( tp == 5 )
841 tp++;
842 }
843
844 b = 1;
845 if( ctmode == 0 ) { /* CCD mode scanner*/
846
847 b = (ntr + 1) * ((2 * gbnd) + dur + 1);
848 b += (1 - ntr) * en_tradj;
849 }
850 if( ctmode == 2 ) /* CIS mode scanner */
851 b = 3;
852
853 /* it might be necessary to tweak this value, to keep the
854 * MCLK constant - see some sheet-fed devices
855 */
856 le = hw->wLineEnd;
857 if (motor->dpi_thresh != 0) {
858 if( param->PhyDpi.y <= motor->dpi_thresh) {
859 le = motor->lineend;
860 DBG( _DBG_INFO2, "* Adjusting lineend: %u\n", le);
861 }
862 regs[0x20] = _HIBYTE( le );
863 regs[0x21] = _LOBYTE( le );
864 }
865
866 tr = m_bLineRateColor * (le + tp * (b + 3 - ntr));
867
868 if( tradj == 0 ) {
869 if( ctmode == 0 )
870 tr += m_bLineRateColor;
871 } else {
872
873 int le_phi, num_byteclk, num_mclkf, tr_fast_pix, extra_pix;
874
875 /* Line color or gray mode */
876 if( afeop != 0 ) {
877
878 le_phi = (tradj + 1) / 2 + 1 + 6;
879 num_byteclk = ((le_phi + 8 * le + 8 * b + 4) /
880 (8 * tradj)) + 1;
881 num_mclkf = 8 * tradj * num_byteclk;
882 tr_fast_pix = num_byteclk;
883 extra_pix = (num_mclkf - le_phi) % 8;
884 }
885 else /* 3 channel pixel rate color */
886 {
887 le_phi = (tradj + 1) / 2 + 1 + 10 + 12;
888 num_byteclk = ((le_phi + 3 * 8 * le + 3 * 8 * b + 3 * 4) /
889 (3 * 8 * tradj)) + 1;
890 num_mclkf = 3 * 8 * tradj * num_byteclk;
891 tr_fast_pix = num_byteclk;
892 extra_pix = (num_mclkf - le_phi) % (3 * 8);
893 }
894
895 tr = b + le + 4 + tr_fast_pix;
896 if (extra_pix == 0)
897 tr++;
898 tr *= m_bLineRateColor;
899 }
900 m_wLineLength = tr / m_bLineRateColor;
901
902 DBG( _DBG_INFO2, "* LineLength=%d, LineRateColor=%u\n",
903 m_wLineLength, m_bLineRateColor );
904 }
905
906 /** usb_GetMotorParam
907 * registers 0x56, 0x57
908 */
909 static void
usb_GetMotorParam(Plustek_Device * dev,ScanParam * pParam)910 usb_GetMotorParam( Plustek_Device *dev, ScanParam *pParam )
911 {
912 int idx, i;
913 ClkMotorDef *clk;
914 MDef *md;
915 DCapsDef *sCaps = &dev->usbDev.Caps;
916 HWDef *hw = &dev->usbDev.HwSetting;
917 u_char *regs = dev->usbDev.a_bRegs;
918
919 if (!_IS_PLUSTEKMOTOR(hw->motorModel)) {
920
921 clk = usb_GetMotorSet( hw->motorModel );
922 md = clk->motor_sets;
923 idx = 0;
924 for( i = 0; i < _MAX_CLK; i++ ) {
925 if( pParam->PhyDpi.y <= dpi_ranges[i] )
926 break;
927 idx++;
928 }
929 if( idx >= _MAX_CLK )
930 idx = _MAX_CLK - 1;
931
932 regs[0x56] = md[idx].pwm;
933 regs[0x57] = md[idx].pwm_duty;
934
935 regs[0x43] = 0;
936 regs[0x44] = 0;
937
938 if( md[idx].scan_lines_per_line > 1 ) {
939
940 if((pParam->bBitDepth > 8) &&
941 (pParam->bDataType == SCANDATATYPE_Color)) {
942
943 regs[0x43] = 0xff;
944 regs[0x44] = md[idx].scan_lines_per_line;
945
946 DBG( _DBG_INFO2, "* Line Skipping : 0x43=0x%02x, 0x44=0x%02x\n",
947 regs[0x43], regs[0x44] );
948 }
949 }
950 } else {
951
952 if( sCaps->OpticDpi.x == 1200 ) {
953
954 switch( hw->motorModel ) {
955
956 case MODEL_HuaLien:
957 case MODEL_KaoHsiung:
958 default:
959 if(pParam->PhyDpi.x <= 200)
960 {
961 regs[0x56] = 1;
962 regs[0x57] = 48; /* 63; */
963 }
964 else if(pParam->PhyDpi.x <= 300)
965 {
966 regs[0x56] = 2; /* 8; */
967 regs[0x57] = 48; /* 56; */
968 }
969 else if(pParam->PhyDpi.x <= 400)
970 {
971 regs[0x56] = 8;
972 regs[0x57] = 48;
973 }
974 else if(pParam->PhyDpi.x <= 600)
975 {
976 regs[0x56] = 2; /* 10; */
977 regs[0x57] = 48; /* 56; */
978 }
979 else /* pParam->PhyDpi.x == 1200) */
980 {
981 regs[0x56] = 1; /* 8; */
982 regs[0x57] = 48; /* 56; */
983 }
984 break;
985 }
986 } else {
987 switch ( hw->motorModel ) {
988
989 case MODEL_Tokyo600:
990 regs[0x56] = 16;
991 regs[0x57] = 4; /* 2; */
992 break;
993 case MODEL_HuaLien:
994 {
995 if(pParam->PhyDpi.x <= 200)
996 {
997 regs[0x56] = 64; /* 24; */
998 regs[0x57] = 4; /* 16; */
999 }
1000 else if(pParam->PhyDpi.x <= 300)
1001 {
1002 regs[0x56] = 64; /* 16; */
1003 regs[0x57] = 4; /* 16; */
1004 }
1005 else if(pParam->PhyDpi.x <= 400)
1006 {
1007 regs[0x56] = 64; /* 16; */
1008 regs[0x57] = 4; /* 16; */
1009 }
1010 else /* if(pParam->PhyDpi.x <= 600) */
1011 {
1012 /* HEINER: check ADF stuff... */
1013 #if 0
1014 if(ScanInf.m_fADF)
1015 {
1016 regs[0x56] = 8;
1017 regs[0x57] = 48;
1018 }
1019 else
1020 #endif
1021 {
1022 regs[0x56] = 64; /* 2; */
1023 regs[0x57] = 4; /* 48; */
1024 }
1025 }
1026 }
1027 break;
1028 case MODEL_KaoHsiung:
1029 default:
1030 if(pParam->PhyDpi.x <= 200)
1031 {
1032 regs[0x56] = 24;
1033 regs[0x57] = 16;
1034 }
1035 else if(pParam->PhyDpi.x <= 300)
1036 {
1037 regs[0x56] = 16;
1038 regs[0x57] = 16;
1039 }
1040 else if(pParam->PhyDpi.x <= 400)
1041 {
1042 regs[0x56] = 16;
1043 regs[0x57] = 16;
1044 }
1045 else /* if(pParam->PhyDpi.x <= 600) */
1046 {
1047 regs[0x56] = 2;
1048 regs[0x57] = 48;
1049 }
1050 break;
1051 }
1052 }
1053 }
1054
1055 DBG( _DBG_INFO2, "* MOTOR-Settings: PWM=0x%02x, PWM_DUTY=0x%02x\n",
1056 regs[0x56], regs[0x57] );
1057 }
1058
1059 /**
1060 */
1061 static void
usb_GetPauseLimit(Plustek_Device * dev,ScanParam * pParam)1062 usb_GetPauseLimit( Plustek_Device *dev, ScanParam *pParam )
1063 {
1064 int coeffsize, scaler;
1065 HWDef *hw = &dev->usbDev.HwSetting;
1066 u_char *regs = dev->usbDev.a_bRegs;
1067
1068 scaler = 1;
1069 if( hw->bReg_0x26 & _ONE_CH_COLOR ) {
1070 if( pParam->bDataType == SCANDATATYPE_Color ) {
1071 scaler = 3;
1072 }
1073 }
1074
1075 /* compute size of coefficient ram */
1076 coeffsize = 4 + 16 + 16; /* gamma and shading and offset */
1077
1078 /* if 16 bit, then not all is used */
1079 if( regs[0x09] & 0x20 ) {
1080 coeffsize = 16 + 16; /* no gamma */
1081 }
1082 coeffsize *= (2*3); /* 3 colors and 2 bytes/word */
1083
1084
1085 /* Get available buffer size in KB
1086 * for 512kb this will be 296
1087 * for 2Mb this will be 1832
1088 */
1089 m_dwPauseLimit = (u_long)(hw->wDRAMSize - (u_long)(coeffsize));
1090 m_dwPauseLimit -= ((pParam->Size.dwPhyBytes*scaler) / 1024 + 1);
1091
1092 /* If not reversing, take into account the steps to reverse */
1093 if( regs[0x50] == 0 )
1094 m_dwPauseLimit -= ((regs[0x54] & 7) *
1095 (pParam->Size.dwPhyBytes * scaler) + 1023) / 1024;
1096
1097 DBG( _DBG_INFO2, "* PL=%lu, coeffsize=%u, scaler=%u\n",
1098 m_dwPauseLimit, coeffsize, scaler );
1099
1100 m_dwPauseLimit = usb_max( usb_min(m_dwPauseLimit,
1101 (u_long)ceil(pParam->Size.dwTotalBytes / 1024.0)), 2);
1102
1103 regs[0x4e] = (u_char)floor((m_dwPauseLimit*512.0)/(2.0*hw->wDRAMSize));
1104
1105 if( regs[0x4e] > 1 ) {
1106 regs[0x4e]--;
1107 if(regs[0x4e] > 1)
1108 regs[0x4e]--;
1109 } else
1110 regs[0x4e] = 1;
1111
1112 /* resume, when buffer is 2/8 kbytes full (512k/2M memory)
1113 */
1114 regs[0x4f] = 1;
1115
1116 DBG( _DBG_INFO2, "* PauseLimit = %lu, [0x4e] = 0x%02x, [0x4f] = 0x%02x\n",
1117 m_dwPauseLimit, regs[0x4e], regs[0x4f] );
1118 }
1119
1120 /** usb_GetScanLinesAndSize
1121 */
1122 static void
usb_GetScanLinesAndSize(Plustek_Device * dev,ScanParam * pParam)1123 usb_GetScanLinesAndSize( Plustek_Device *dev, ScanParam *pParam )
1124 {
1125 DCapsDef *sCaps = &dev->usbDev.Caps;
1126
1127 pParam->Size.dwPhyLines = (u_long)ceil((double) pParam->Size.dwLines *
1128 pParam->PhyDpi.y / pParam->UserDpi.y);
1129
1130 /* Calculate color offset */
1131 if (pParam->bCalibration == PARAM_Scan && pParam->bChannels == 3) {
1132
1133 dev->scanning.bLineDistance = sCaps->bSensorDistance *
1134 pParam->PhyDpi.y / sCaps->OpticDpi.x;
1135 pParam->Size.dwPhyLines += (dev->scanning.bLineDistance << 1);
1136 }
1137 else
1138 dev->scanning.bLineDistance = 0;
1139
1140 pParam->Size.dwTotalBytes = pParam->Size.dwPhyBytes * pParam->Size.dwPhyLines;
1141
1142 DBG( _DBG_INFO, "* PhyBytes = %lu\n", pParam->Size.dwPhyBytes );
1143 DBG( _DBG_INFO, "* PhyLines = %lu\n", pParam->Size.dwPhyLines );
1144 DBG( _DBG_INFO, "* TotalBytes = %lu\n", pParam->Size.dwTotalBytes );
1145 }
1146
1147 /** function to preset/reset the merlin registers
1148 */
1149 static SANE_Bool
usb_SetScanParameters(Plustek_Device * dev,ScanParam * pParam)1150 usb_SetScanParameters( Plustek_Device *dev, ScanParam *pParam )
1151 {
1152 static u_char reg8, reg38[6], reg48[2];
1153
1154 ScanDef *scan = &dev->scanning;
1155 ScanParam *pdParam = &dev->scanning.sParam;
1156 HWDef *hw = &dev->usbDev.HwSetting;
1157 u_char *regs = dev->usbDev.a_bRegs;
1158
1159 m_pParam = pParam;
1160
1161 DBG( _DBG_INFO, "usb_SetScanParameters()\n" );
1162
1163 if( !usb_IsScannerReady(dev))
1164 return SANE_FALSE;
1165
1166 if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF) {
1167 /* HEINER: dSaveMoveSpeed is only used in func EjectPaper!!!
1168 dSaveMoveSpeed = hw->dMaxMoveSpeed;
1169 */
1170 hw->dMaxMoveSpeed = 1.0;
1171 usb_MotorSelect( dev, SANE_TRUE );
1172 usb_MotorOn( dev, SANE_TRUE );
1173 }
1174
1175 /*
1176 * calculate the basic settings...
1177 */
1178 pParam->PhyDpi.x = usb_SetAsicDpiX( dev, pParam->UserDpi.x );
1179 pParam->PhyDpi.y = usb_SetAsicDpiY( dev, pParam->UserDpi.y );
1180
1181 usb_SetColorAndBits( dev, pParam );
1182 usb_GetScanRect ( dev, pParam );
1183
1184 usb_PresetStepSize( dev, pParam );
1185
1186 if( dev->caps.dwFlag & SFLAG_ADF ) {
1187
1188 if( pParam->bCalibration == PARAM_Scan ) {
1189
1190 if( pdParam->bSource == SOURCE_ADF ) {
1191 regs[0x50] = 0;
1192 regs[0x51] = 0x40;
1193 if( pParam->PhyDpi.x <= 300)
1194 regs[0x54] = (regs[0x54] & ~7) | 4; /* 3; */
1195 else
1196 regs[0x54] = (regs[0x54] & ~7) | 5; /* 4; */
1197 } else {
1198 regs[0x50] = hw->bStepsToReverse;
1199 regs[0x51] = hw->bReg_0x51;
1200 regs[0x54] &= ~7;
1201 }
1202 } else
1203 regs[0x50] = 0;
1204 } else {
1205 if( pParam->bCalibration == PARAM_Scan )
1206 regs[0x50] = hw->bStepsToReverse;
1207 else
1208 regs[0x50] = 0;
1209 }
1210
1211 /* Assume we will not use ITA */
1212 regs[0x19] = m_bIntTimeAdjust = 0;
1213
1214 /* Get variables from calculation algorithms */
1215 if(!(pParam->bCalibration == PARAM_Scan &&
1216 pParam->bSource == SOURCE_ADF && dev->usbDev.fLastScanIsAdf )) {
1217
1218 DBG( _DBG_INFO2, "* Scan calculations...\n" );
1219 usb_GetLineLength ( dev, pParam );
1220 usb_GetStepSize ( dev, pParam );
1221 usb_GetDPD ( dev );
1222 usb_GetMCLKDivider( dev, pParam );
1223 usb_GetMotorParam ( dev, pParam );
1224 }
1225
1226 /* Compute fast feed step size, use equation 3 and equation 8 */
1227 if( m_dMCLKDivider < 1.0)
1228 m_dMCLKDivider = 1.0;
1229
1230 m_wFastFeedStepSize = (u_short)(CRYSTAL_FREQ /
1231 (m_dMCLKDivider * 8 * m_bCM * hw->dMaxMoveSpeed *
1232 4 * hw->wMotorDpi));
1233 /* CIS special ;-) */
1234 if((hw->bReg_0x26 & _ONE_CH_COLOR) && (m_bCM == 1)) {
1235 DBG( _DBG_INFO2, "* CIS FFStep-Speedup\n" );
1236 m_wFastFeedStepSize /= 3;
1237 }
1238
1239 if( m_bIntTimeAdjust != 0 )
1240 m_wFastFeedStepSize /= m_bIntTimeAdjust;
1241
1242 if(regs[0x0a])
1243 m_wFastFeedStepSize *= ((regs[0x0a] >> 2) + 2);
1244 regs[0x48] = _HIBYTE( m_wFastFeedStepSize );
1245 regs[0x49] = _LOBYTE( m_wFastFeedStepSize );
1246
1247 DBG( _DBG_INFO2, "* FFStepSize = %u, [0x48] = 0x%02x, [0x49] = 0x%02x\n",
1248 m_wFastFeedStepSize, regs[0x48], regs[0x49] );
1249
1250 /* Compute the number of lines to scan using actual Y resolution */
1251 usb_GetScanLinesAndSize( dev, pParam );
1252
1253 /* Pause limit should be bounded by total bytes to read
1254 * so that the chassis will not move too far.
1255 */
1256 usb_GetPauseLimit( dev, pParam );
1257
1258 /* For ADF .... */
1259 if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF) {
1260
1261 if( dev->usbDev.fLastScanIsAdf ) {
1262
1263 regs[0x08] = reg8;
1264 memcpy( ®s[0x38], reg38, sizeof(reg38));
1265 memcpy( ®s[0x48], reg48, sizeof(reg48));
1266
1267 } else {
1268
1269 reg8 = regs[0x08];
1270 memcpy( reg38, ®s[0x38], sizeof(reg38));
1271 memcpy( reg48, ®s[0x48], sizeof(reg48));
1272 }
1273 usb_MotorSelect( dev, SANE_TRUE );
1274 }
1275
1276 /* Reset LM983x's state machine before setting register values */
1277 if( !usbio_WriteReg( dev->fd, 0x18, 0x18 ))
1278 return SANE_FALSE;
1279
1280 usleep(200 * 1000); /* Need to delay at least xxx microseconds */
1281
1282 if( !usbio_WriteReg( dev->fd, 0x07, 0x20 ))
1283 return SANE_FALSE;
1284
1285 if( !usbio_WriteReg( dev->fd, 0x19, 6 ))
1286 return SANE_FALSE;
1287
1288 regs[0x07] = 0;
1289 regs[0x28] = 0;
1290
1291 /* set unused registers to 0 */
1292 memset( ®s[0x03], 0, 3 );
1293 memset( ®s[0x5f], 0, 0x7f-0x5f+1 );
1294
1295 if( !usb_IsSheetFedDevice(dev)) {
1296 /* we limit the possible scansteps to avoid, that the sensors bumps
1297 * against the scanbed - not necessary for sheet-fed devices
1298 */
1299 if(pParam->bCalibration==PARAM_Scan && pParam->bSource!=SOURCE_ADF) {
1300
1301 u_long lines = pParam->Size.dwPhyLines + scan->bLinesToSkip +
1302 scan->dwLinesDiscard + 5;
1303 u_short scansteps = (u_short)ceil((double)lines*
1304 hw->wMotorDpi / pParam->PhyDpi.y);
1305 DBG( _DBG_INFO, "* Scansteps=%u (%lu*%u/%u)\n", scansteps, lines,
1306 hw->wMotorDpi, pParam->PhyDpi.y );
1307 regs[0x4c] = _HIBYTE(scansteps);
1308 regs[0x4d] = _LOBYTE(scansteps);
1309 }
1310 }
1311
1312 /* set the merlin registers */
1313 _UIO(sanei_lm983x_write( dev->fd, 0x03, ®s[0x03], 3, SANE_TRUE));
1314 _UIO(sanei_lm983x_write( dev->fd, 0x08, ®s[0x08], 0x7f - 0x08+1, SANE_TRUE));
1315
1316 usleep(100);
1317
1318 if( !usbio_WriteReg( dev->fd, 0x07, 0 ))
1319 return SANE_FALSE;
1320
1321 DBG( _DBG_INFO, "usb_SetScanParameters() done.\n" );
1322 return SANE_TRUE;
1323 }
1324
1325 /**
1326 */
1327 static SANE_Bool
usb_ScanBegin(Plustek_Device * dev,SANE_Bool auto_park)1328 usb_ScanBegin( Plustek_Device *dev, SANE_Bool auto_park )
1329 {
1330 u_char value;
1331 u_short inches;
1332 HWDef *hw = &dev->usbDev.HwSetting;
1333 DCapsDef *sc = &dev->usbDev.Caps;
1334 u_char *regs = dev->usbDev.a_bRegs;
1335
1336 DBG( _DBG_INFO, "usb_ScanBegin()\n" );
1337
1338 if( !usb_Wait4ScanSample( dev ))
1339 return SANE_FALSE;
1340
1341 /* save the request for usb_ScanEnd () */
1342 m_fAutoPark = auto_park;
1343
1344 /* Disable home sensor during scan, or the chassis cannot move */
1345 value = ((m_pParam->bCalibration == PARAM_Scan &&
1346 m_pParam->bSource == SOURCE_ADF)? (regs[0x58] & ~7): 0);
1347
1348 if(!usbio_WriteReg( dev->fd, 0x58, value ))
1349 return SANE_FALSE;
1350
1351 /* Check if scanner is ready for receiving command */
1352 if( !usb_IsScannerReady(dev))
1353 return SANE_FALSE;
1354
1355 /* Flush cache - only LM9831 (Source: National Semiconductors) */
1356 if( _LM9831 == hw->chip ) {
1357
1358 for(;;) {
1359
1360 if( SANE_TRUE == cancelRead ) {
1361 DBG( _DBG_INFO, "ScanBegin() - Cancel detected...\n" );
1362 return SANE_FALSE;
1363 }
1364
1365 _UIO(usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData ));
1366 if( m_bOldScanData ) {
1367
1368 u_long dwBytesToRead = m_bOldScanData * hw->wDRAMSize * 4;
1369 u_char *pBuffer = malloc( sizeof(u_char) * dwBytesToRead );
1370
1371 DBG(_DBG_INFO,"Flushing cache - %lu bytes (bOldScanData=%u)\n",
1372 dwBytesToRead, m_bOldScanData );
1373
1374 _UIO(sanei_lm983x_read( dev->fd, 0x00, pBuffer,
1375 dwBytesToRead, SANE_FALSE ));
1376 free( pBuffer );
1377
1378 } else
1379 break;
1380 }
1381 }
1382
1383 /* Download map & Shading data */
1384 if(( m_pParam->bCalibration == PARAM_Scan && !usb_MapDownload( dev )) ||
1385 !usb_DownloadShadingData( dev, m_pParam->bCalibration )) {
1386 return SANE_FALSE;
1387 }
1388
1389 /* Move chassis and start to read image data */
1390 if (!usbio_WriteReg( dev->fd, 0x07, 3 ))
1391 return SANE_FALSE;
1392
1393 usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData );
1394 m_bOldScanData = 0; /* No data at all */
1395
1396 m_fStart = m_fFirst = SANE_TRUE; /* Prepare to read */
1397
1398 DBG( _DBG_DREGS, "Register Dump before reading data:\n" );
1399 dumpregs( dev->fd, NULL );
1400
1401 inches = (u_short)((m_pParam->Origin.y *300UL)/hw->wMotorDpi);
1402 DBG( _DBG_INFO2, ">>> INCH=%u, DOY=%u\n", inches, sc->Normal.DataOrigin.y );
1403 if( inches > sc->Normal.DataOrigin.y )
1404 usb_WaitPos( dev, 150, SANE_FALSE );
1405
1406 DBG( _DBG_INFO, "usb_ScanBegin() done.\n" );
1407 return SANE_TRUE;
1408 }
1409
1410 /** usb_ScanEnd
1411 * stop all the processing stuff and reposition sensor back home
1412 */
1413 static SANE_Bool
usb_ScanEnd(Plustek_Device * dev)1414 usb_ScanEnd( Plustek_Device *dev )
1415 {
1416 u_char value;
1417
1418 DBG( _DBG_INFO, "usbDev_ScanEnd(), start=%u, park=%u\n",
1419 m_fStart, m_fAutoPark );
1420 usbio_ReadReg( dev->fd, 0x07, &value );
1421 if( value == 3 || value != 2 )
1422 usbio_WriteReg( dev->fd, 0x07, 0 );
1423
1424 if( m_fStart ) {
1425 m_fStart = SANE_FALSE;
1426
1427 if( m_fAutoPark )
1428 usb_ModuleToHome( dev, SANE_FALSE );
1429 }
1430 else if( SANE_TRUE == cancelRead ) {
1431
1432 usb_ModuleToHome( dev, SANE_FALSE );
1433 }
1434 return SANE_TRUE;
1435 }
1436
1437 /**
1438 */
1439 static SANE_Bool
usb_IsDataAvailableInDRAM(Plustek_Device * dev)1440 usb_IsDataAvailableInDRAM( Plustek_Device *dev )
1441 {
1442 /* Compute polling timeout
1443 * Height (Inches) / MaxScanSpeed (Inches/Second) = Seconds to move the
1444 * module from top to bottom. Then convert the seconds to milliseconds
1445 * by multiply 1000. We add extra 2 seconds to get some tolerance.
1446 */
1447 u_char a_bBand[3];
1448 long dwTicks;
1449 struct timeval t;
1450 u_char *regs = dev->usbDev.a_bRegs;
1451
1452 DBG( _DBG_INFO, "usb_IsDataAvailableInDRAM()\n" );
1453
1454 gettimeofday( &t, NULL);
1455 dwTicks = t.tv_sec + 30;
1456
1457 for(;;) {
1458
1459 _UIO( sanei_lm983x_read( dev->fd, 0x01, a_bBand, 3, SANE_FALSE ));
1460
1461 gettimeofday( &t, NULL);
1462 if( t.tv_sec > dwTicks )
1463 break;
1464
1465 if( usb_IsEscPressed()) {
1466 DBG(_DBG_INFO,"usb_IsDataAvailableInDRAM() - Cancel detected...\n");
1467 return SANE_FALSE;
1468 }
1469
1470 /* It is not stable for read */
1471 if((a_bBand[0] != a_bBand[1]) && (a_bBand[1] != a_bBand[2]))
1472 continue;
1473
1474 if( a_bBand[0] > m_bOldScanData ) {
1475
1476 if( m_pParam->bSource != SOURCE_Reflection )
1477
1478 usleep(1000*(30 * regs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600));
1479 else
1480 usleep(1000*(20 * regs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600));
1481
1482 DBG( _DBG_INFO, "Data is available\n" );
1483 return SANE_TRUE;
1484 }
1485 }
1486
1487 DBG( _DBG_INFO, "NO Data available\n" );
1488 return SANE_FALSE;
1489 }
1490
1491 /**
1492 */
1493 static SANE_Bool
usb_ScanReadImage(Plustek_Device * dev,void * pBuf,u_long dwSize)1494 usb_ScanReadImage( Plustek_Device *dev, void *pBuf, u_long dwSize )
1495 {
1496 u_char *regs = dev->usbDev.a_bRegs;
1497 SANE_Status res;
1498
1499 DBG( _DBG_READ, "usb_ScanReadImage(%lu)\n", dwSize );
1500
1501 if( m_fFirst ) {
1502
1503 m_fFirst = SANE_FALSE;
1504
1505 /* Wait for data band ready */
1506 if (!usb_IsDataAvailableInDRAM( dev )) {
1507 DBG( _DBG_ERROR, "Nothing to read...\n" );
1508 return SANE_FALSE;
1509 }
1510
1511 /* restore the fast forward stepsize...*/
1512 sanei_lm983x_write(dev->fd, 0x48, ®s[0x48], 2, SANE_TRUE);
1513 }
1514 res = sanei_lm983x_read(dev->fd, 0x00, (u_char *)pBuf, dwSize, SANE_FALSE);
1515
1516 /* check for pressed ESC button, as sanei_lm983x_read() may take some time
1517 */
1518 if( usb_IsEscPressed()) {
1519 DBG(_DBG_INFO,"usb_ScanReadImage() - Cancel detected...\n");
1520 return SANE_FALSE;
1521 }
1522
1523 DBG( _DBG_READ, "usb_ScanReadImage() done, result: %d\n", res );
1524 if( SANE_STATUS_GOOD == res ) {
1525 return SANE_TRUE;
1526 }
1527
1528 DBG( _DBG_ERROR, "usb_ScanReadImage() failed\n" );
1529 return SANE_FALSE;
1530 }
1531
1532 /** calculate the number of pixels per line and lines out of a given
1533 * crop-area. The size of the area is given on a 300dpi base!
1534 */
1535 static void
usb_GetImageInfo(Plustek_Device * dev,ImgDef * pInfo,WinInfo * pSize)1536 usb_GetImageInfo( Plustek_Device *dev, ImgDef *pInfo, WinInfo *pSize )
1537 {
1538 DBG( _DBG_INFO, "usb_GetImageInfo()\n" );
1539
1540 pSize->dwPixels = (u_long)pInfo->crArea.cx * pInfo->xyDpi.x / 300UL;
1541 pSize->dwLines = (u_long)pInfo->crArea.cy * pInfo->xyDpi.y / 300UL;
1542
1543 DBG( _DBG_INFO2,"Area: cx=%u, cy=%u\n",pInfo->crArea.cx,pInfo->crArea.cy);
1544
1545 switch( pInfo->wDataType ) {
1546
1547 case COLOR_TRUE48:
1548 pSize->dwBytes = pSize->dwPixels * 6UL;
1549 break;
1550
1551 case COLOR_TRUE24:
1552 if( dev->scanning.fGrayFromColor > 7 ){
1553 pSize->dwBytes = (pSize->dwPixels + 7UL) >> 3;
1554 pSize->dwPixels = pSize->dwBytes * 8;
1555 } else {
1556 pSize->dwBytes = pSize->dwPixels * 3UL;
1557 }
1558 break;
1559
1560 case COLOR_GRAY16:
1561 pSize->dwBytes = pSize->dwPixels << 1;
1562 break;
1563
1564 case COLOR_256GRAY:
1565 pSize->dwBytes = pSize->dwPixels;
1566 break;
1567
1568 default:
1569 pSize->dwBytes = (pSize->dwPixels + 7UL) >> 3;
1570 pSize->dwPixels = pSize->dwBytes * 8;
1571 break;
1572 }
1573 }
1574
1575 /**
1576 */
1577 static void
usb_SaveImageInfo(Plustek_Device * dev,ImgDef * pInfo)1578 usb_SaveImageInfo( Plustek_Device *dev, ImgDef *pInfo )
1579 {
1580 HWDef *hw = &dev->usbDev.HwSetting;
1581 ScanParam *pParam = &dev->scanning.sParam;
1582
1583 DBG( _DBG_INFO, "usb_SaveImageInfo()\n" );
1584
1585 /* Dpi & Origins */
1586 pParam->UserDpi = pInfo->xyDpi;
1587 pParam->Origin.x = pInfo->crArea.x;
1588 pParam->Origin.y = pInfo->crArea.y;
1589
1590 /* Source & Bits */
1591 pParam->bBitDepth = 8;
1592
1593 switch( pInfo->wDataType ) {
1594
1595 case COLOR_TRUE48:
1596 pParam->bBitDepth = 16;
1597 /* fall through... */
1598
1599 case COLOR_TRUE24:
1600 pParam->bDataType = SCANDATATYPE_Color;
1601
1602 /* AFE operation: one or 3 channels ! */
1603 if( hw->bReg_0x26 & _ONE_CH_COLOR )
1604 pParam->bChannels = 1;
1605 else
1606 pParam->bChannels = 3;
1607 break;
1608
1609 case COLOR_GRAY16:
1610 pParam->bBitDepth = 16;
1611 /* fall through... */
1612
1613 case COLOR_256GRAY:
1614 pParam->bDataType = SCANDATATYPE_Gray;
1615 pParam->bChannels = 1;
1616 break;
1617
1618 default:
1619 pParam->bBitDepth = 1;
1620 pParam->bDataType = SCANDATATYPE_BW;
1621 pParam->bChannels = 1;
1622 }
1623
1624 DBG( _DBG_INFO, "* dwFlag = 0x%08lx\n", pInfo->dwFlag );
1625
1626 if( pInfo->dwFlag & SCANDEF_Transparency )
1627 pParam->bSource = SOURCE_Transparency;
1628 else if( pInfo->dwFlag & SCANDEF_Negative )
1629 pParam->bSource = SOURCE_Negative;
1630 else if( pInfo->dwFlag & SCANDEF_Adf )
1631 pParam->bSource = SOURCE_ADF;
1632 else
1633 pParam->bSource = SOURCE_Reflection;
1634
1635 /* it seems, that we need to adjust the Origin.x when we have a
1636 * sheetfed device to avoid stripes in the resulting pictures
1637 */
1638 if( usb_IsSheetFedDevice(dev)) {
1639
1640 int step, div, org, xdpi;
1641
1642 xdpi = usb_SetAsicDpiX( dev, pParam->UserDpi.x );
1643
1644 if ((xdpi * 2) <= 300)
1645 div = 300;
1646 else if ((xdpi * 2) <= 600)
1647 div = 600;
1648 else if ((xdpi * 2) <= 1200)
1649 div = 1200;
1650 else
1651 div = 2400;
1652
1653 step = div / xdpi;
1654 org = pParam->Origin.x;
1655
1656 pParam->Origin.x = (pParam->Origin.x / step) * step;
1657
1658 if (org != pParam->Origin.x)
1659 DBG(_DBG_INFO, "* Origin.x adjusted: %i -> %i\n",
1660 org, pParam->Origin.x);
1661 }
1662 }
1663
1664 /* END PLUSTEK-USBSCAN.C ....................................................*/
1665