1/** @file u12-if.c 2 * @brief The interface functions to the U12 backend stuff. 3 * 4 * Copyright (c) 2003-2004 Gerhard Jaeger <gerhard@gjaeger.de> 5 * 6 * History: 7 * - 0.01 - initial version 8 * - 0.02 - added model tweaking 9 * - fixed autodetection bug 10 * - added line-scaling stuff 11 * - removed u12if_setScanEnv() 12 * . 13 * <hr> 14 * This file is part of the SANE package. 15 * 16 * This program is free software; you can redistribute it and/or 17 * modify it under the terms of the GNU General Public License as 18 * published by the Free Software Foundation; either version 2 of the 19 * License, or (at your option) any later version. 20 * 21 * This program is distributed in the hope that it will be useful, but 22 * WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 * General Public License for more details. 25 * 26 * You should have received a copy of the GNU General Public License 27 * along with this program. If not, see <https://www.gnu.org/licenses/>. 28 * 29 * As a special exception, the authors of SANE give permission for 30 * additional uses of the libraries contained in this release of SANE. 31 * 32 * The exception is that, if you link a SANE library with other files 33 * to produce an executable, this does not by itself cause the 34 * resulting executable to be covered by the GNU General Public 35 * License. Your use of that executable is in no way restricted on 36 * account of linking the SANE library code into it. 37 * 38 * This exception does not, however, invalidate any other reasons why 39 * the executable file might be covered by the GNU General Public 40 * License. 41 * 42 * If you submit changes to SANE to the maintainers to be included in 43 * a subsequent release, you agree by submitting the changes that 44 * those changes may be distributed with this exception intact. 45 * 46 * If you write modifications of your own for SANE, it is your choice 47 * whether to permit this exception to apply to your modifications. 48 * If you do not wish that, delete this exception notice. 49 * <hr> 50 */ 51 52#define _DEF_BRIGHTEST_SKIP 3 53#define _DEF_DARKEST_SKIP 5 54 55/** useful for description tables 56 */ 57typedef struct { 58 int id; 59 char *desc; 60} TabDef; 61 62typedef struct { 63 char *vp; 64 char *name; 65} DevDesc; 66 67#define _PLUSTEK_VENID 0x07B3 68#define _KYE_VENID 0x0458 69 70/** to allow different vendors... 71 */ 72static TabDef u12Vendors[] = { 73 74 { _PLUSTEK_VENID, "Plustek" }, 75 { _KYE_VENID, "KYE/Genius" }, 76 { 0xFFFF, NULL } 77}; 78 79/** list of supported devices 80 */ 81static DevDesc u12Devices[] = { 82 { "0x07B3-0x0001", "1212U/U12" }, 83 { "0x0458-0x2004", "Colorpage HR6" }, 84 { NULL, NULL } 85}; 86 87/** for autodetection */ 88static SANE_Char USB_devname[1024]; 89 90/********************** the USB scanner interface ****************************/ 91 92/** 93 */ 94static SANE_Status u12_initDev( U12_Device *dev, int handle, int vendor ) 95{ 96 int i; 97 SANE_Status res; 98 TimerDef timer; 99 100 /* well now we patch the vendor string... 101 * if not found, the default vendor will be Plustek 102 */ 103 for( i = 0; u12Vendors[i].desc != NULL; i++ ) { 104 105 if( u12Vendors[i].id == vendor ) { 106 dev->sane.vendor = u12Vendors[i].desc; 107 DBG( _DBG_INFO, "Vendor adjusted to: >%s<\n", dev->sane.vendor ); 108 break; 109 } 110 } 111 dev->fd = handle; 112 113 dev->adj.upNormal = 0; 114 dev->adj.upNegative = 20; 115 dev->adj.upPositive = -30; 116 dev->adj.leftNormal = 51; 117 118 res = SANE_STATUS_IO_ERROR; 119 if( !(u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER)) { 120 121 u12motor_PositionModuleToHome( dev ); 122 123 u12io_StartTimer( &timer, _SECOND * 20); 124 do { 125 if( u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER) { 126 res = SANE_STATUS_GOOD; 127 break; 128 } 129 } while( !u12io_CheckTimer( &timer )); 130 } else { 131 res = u12hw_InitAsic( dev, SANE_FALSE ); 132 } 133 134 if( res == SANE_STATUS_GOOD ) 135 u12hw_PutToIdleMode( dev ); 136 return res; 137} 138 139/** will be called upon sane_exit 140 */ 141static void u12if_shutdown( U12_Device *dev ) 142{ 143 SANE_Int handle; 144 TimerDef timer; 145 146 DBG( _DBG_INFO, "Shutdown called (dev->fd=%d, %s)\n", 147 dev->fd, dev->sane.name ); 148 if( SANE_STATUS_GOOD == sanei_usb_open( dev->sane.name, &handle )) { 149 150 dev->fd = handle; 151 u12io_OpenScanPath( dev ); 152 153 u12hw_PutToIdleMode( dev ); 154 155 if( !(u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER)) { 156 157 u12motor_PositionModuleToHome( dev ); 158 159 u12io_StartTimer( &timer, _SECOND * 20); 160 do { 161 if( u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER) { 162 break; 163 } 164 } while( !u12io_CheckTimer( &timer )); 165 } 166 DBG( _DBG_INFO, "* Home position reached.\n" ); 167 168 if( 0 != dev->adj.lampOffOnEnd ) { 169 170 DBG( _DBG_INFO, "* Switching lamp off...\n" ); 171 dev->regs.RD_ScanControl &= ~_SCAN_LAMPS_ON; 172 u12io_DataToRegister(dev,REG_SCANCONTROL, dev->regs.RD_ScanControl ); 173 } 174 175 u12io_CloseScanPath( dev ); 176 dev->fd = -1; 177 sanei_usb_close( handle ); 178 } 179 180#if 0 181 usb_StopLampTimer( dev ); 182#endif 183 DBG( _DBG_INFO, "Shutdown done.\n" ); 184} 185 186/** This function checks whether a device, described by a given 187 * string(vendor and product ID), is supported by this backend or not 188 * 189 * @param usbIdStr - string consisting out of product and vendor ID 190 * format: "0xVVVV-0xPPPP" VVVV = Vendor ID, PPP = Product ID 191 * @returns; SANE_TRUE if supported, SANE_FALSE if not 192 */ 193static SANE_Bool u12if_IsDeviceSupported( U12_Device *dev ) 194{ 195 int i; 196 197 for( i = 0; NULL != u12Devices[i].name; i++ ) { 198 199 if( !strcmp( dev->usbId, u12Devices[i].vp )) { 200 dev->sane.model = u12Devices[i].name; 201 return SANE_TRUE; 202 } 203 } 204 205 return SANE_FALSE; 206} 207 208/** 209 */ 210static SANE_Status u12if_usbattach( SANE_String_Const dev_name ) 211{ 212 if( USB_devname[0] == '\0' ) { 213 DBG( _DBG_INFO, "Found device at >%s<\n", dev_name ); 214 strncpy( USB_devname, dev_name, 1023 ); 215 USB_devname[1023] = '\0'; 216 } else { 217 DBG( _DBG_INFO, "Device >%s< ignoring\n", dev_name ); 218 } 219 220 return SANE_STATUS_GOOD; 221} 222 223#ifndef _FAKE_DEVICE 224/** here we roam through our list of supported devices and 225 * cross check with the ones the system reports... 226 * @param vendor - pointer to receive vendor ID 227 * @param product - pointer to receive product ID 228 * @return SANE_TRUE if a matching device has been found or 229 * SANE_FALSE if nothing supported found... 230 */ 231static SANE_Bool usbDev_autodetect( SANE_Word *vendor, SANE_Word *product ) 232{ 233 int i; 234 SANE_Word p, v; 235 236 DBG( _DBG_INFO, "Autodetection...\n" ); 237 238 for( i = 0; NULL != u12Devices[i].name; i++ ) { 239 240 v = strtol( &(u12Devices[i].vp)[0], 0, 0 ); 241 p = strtol( &(u12Devices[i].vp)[7], 0, 0 ); 242 DBG( _DBG_INFO, "* checking for 0x%04x-0x%04x\n", v, p ); 243 244 sanei_usb_find_devices( v, p, u12if_usbattach ); 245 246 if( USB_devname[0] != '\0' ) { 247 248 *vendor = v; 249 *product = p; 250 DBG( _DBG_INFO, "* using device >%s<\n", USB_devname ); 251 return SANE_TRUE; 252 } 253 } 254 255 return SANE_FALSE; 256} 257#endif 258 259/** 260 */ 261static int u12if_open( U12_Device *dev ) 262{ 263 char devStr[50]; 264 int result; 265 SANE_Int handle; 266 SANE_Word vendor, product; 267 SANE_Bool was_empty; 268 269 DBG( _DBG_INFO, "u12if_open(%s,%s)\n", dev->name, dev->usbId ); 270 271 USB_devname[0] = '\0'; 272 273#ifdef _FAKE_DEVICE 274 dev->name = strdup( "auto" ); 275 dev->sane.name = dev->name; 276 was_empty = SANE_FALSE; 277 278 result = SANE_STATUS_UNSUPPORTED; 279#else 280 if( !strcmp( dev->name, "auto" )) { 281 282 if( dev->usbId[0] == '\0' ) { 283 284 if( !usbDev_autodetect( &vendor, &product )) { 285 DBG( _DBG_ERROR, "No supported device found!\n" ); 286 return -1; 287 } 288 289 } else { 290 291 vendor = strtol( &dev->usbId[0], 0, 0 ); 292 product = strtol( &dev->usbId[7], 0, 0 ); 293 294 sanei_usb_find_devices( vendor, product, u12if_usbattach ); 295 296 if( USB_devname[0] == '\0' ) { 297 DBG( _DBG_ERROR, "No matching device found!\n" ); 298 return -1; 299 } 300 } 301 302 if( SANE_STATUS_GOOD != sanei_usb_open( USB_devname, &handle )) { 303 return -1; 304 } 305 306 /* replace the old devname, so we are able to have multiple 307 * auto-detected devices 308 */ 309 free( dev->name ); 310 dev->name = strdup( USB_devname ); 311 dev->sane.name = dev->name; 312 313 } else { 314 315 if( SANE_STATUS_GOOD != sanei_usb_open( dev->name, &handle )) 316 return -1; 317 } 318 was_empty = SANE_FALSE; 319 320 result = sanei_usb_get_vendor_product( handle, &vendor, &product ); 321#endif 322 323 if( SANE_STATUS_GOOD == result ) { 324 325 sprintf( devStr, "0x%04X-0x%04X", vendor, product ); 326 327 DBG(_DBG_INFO,"Vendor ID=0x%04X, Product ID=0x%04X\n",vendor,product); 328 329 if( dev->usbId[0] != '\0' ) { 330 331 if( 0 != strcmp( dev->usbId, devStr )) { 332 DBG( _DBG_ERROR, "Specified Vendor and Product ID " 333 "doesn't match with the ones\n" 334 "in the config file\n" ); 335 sanei_usb_close( handle ); 336 return -1; 337 } 338 } else { 339 sprintf( dev->usbId, "0x%04X-0x%04X", vendor, product ); 340 was_empty = SANE_TRUE; 341 } 342 343 } else { 344 345 DBG( _DBG_INFO, "Can't get vendor & product ID from driver...\n" ); 346 347 /* if the ioctl stuff is not supported by the kernel and we have 348 * nothing specified, we have to give up... 349 */ 350 if( dev->usbId[0] == '\0' ) { 351 DBG( _DBG_ERROR, "Cannot autodetect Vendor an Product ID, " 352 "please specify in config file.\n" ); 353 sanei_usb_close( handle ); 354 return -1; 355 } 356 357 vendor = strtol( &dev->usbId[0], 0, 0 ); 358 product = strtol( &dev->usbId[7], 0, 0 ); 359 DBG( _DBG_INFO, "... using the specified: " 360 "0x%04X-0x%04X\n", vendor, product ); 361 } 362 363 /* before accessing the scanner, check if supported! 364 */ 365 if( !u12if_IsDeviceSupported( dev )) { 366 DBG( _DBG_ERROR, "Device >%s<, is not supported!\n", dev->usbId ); 367 sanei_usb_close( handle ); 368 return -1; 369 } 370 371 dev->mode = _PP_MODE_SPP; 372 dev->fd = handle; 373 374 /* is it accessible ? */ 375 if( SANE_STATUS_GOOD != u12hw_CheckDevice( dev )) { 376 dev->fd = -1; 377 sanei_usb_close( handle ); 378 return -1; 379 } 380 381 DBG( _DBG_INFO, "Detected vendor & product ID: " 382 "0x%04X-0x%04X\n", vendor, product ); 383 384 if( was_empty ) 385 dev->usbId[0] = '\0'; 386 387 /* now initialize the device */ 388 if( SANE_STATUS_GOOD != u12_initDev( dev, handle, vendor )) { 389 dev->fd = -1; 390 sanei_usb_close( handle ); 391 return -1; 392 } 393 394 if( _PLUSTEK_VENID == vendor ) { 395 if( dev->Tpa ) 396 dev->sane.model = "UT12"; 397 } 398 399 dev->initialized = SANE_TRUE; 400 return handle; 401} 402 403/** 404 */ 405static int u12if_close( U12_Device *dev ) 406{ 407 DBG( _DBG_INFO, "u12if_close()\n" ); 408 u12io_CloseScanPath( dev ); 409 sanei_usb_close( dev->fd ); 410 dev->fd = -1; 411 return 0; 412} 413 414/** 415 */ 416static SANE_Status u12if_getCaps( U12_Device *dev ) 417{ 418 int cntr; 419 int res_x = 600 ; /*dev->caps.OpticDpi.x */ 420 DBG( _DBG_INFO, "u12if_getCaps()\n" ); 421 422/* FIXME: set dpi_range.max, max_x & max_y on a per model base */ 423 dev->dpi_max_x = 600; 424 dev->dpi_max_y = 1200; 425 426 /* A4 devices */ 427 dev->max_x = 8.5 * (double)_MM_PER_INCH; 428 dev->max_y = 11.6934 * (double)_MM_PER_INCH; 429 430 /* limit the range */ 431 dev->dpi_range.min = _DEF_DPI; 432 dev->dpi_range.max = dev->dpi_max_y; 433 dev->dpi_range.quant = 0; 434 dev->x_range.min = 0; 435 dev->x_range.max = SANE_FIX(dev->max_x); 436 dev->x_range.quant = 0; 437 dev->y_range.min = 0; 438 dev->y_range.max = SANE_FIX(dev->max_y); 439 dev->y_range.quant = 0; 440 441 /* calculate the size of the resolution list + 442 * one more to avoid a buffer overflow, then allocate it... 443 */ 444 dev->res_list = (SANE_Int *) 445 calloc((((res_x * 16)-_DEF_DPI)/25+1), 446 sizeof (SANE_Int)); 447 448 if (NULL == dev->res_list) { 449 DBG( _DBG_ERROR, "alloc fail, resolution problem\n" ); 450 u12if_close(dev); 451 return SANE_STATUS_INVAL; 452 } 453 454 /* build up the resolution table */ 455 dev->res_list_size = 0; 456 for( cntr = _DEF_DPI; cntr <= (res_x*16); cntr += 25 ) { 457 dev->res_list_size++; 458 dev->res_list[dev->res_list_size - 1] = (SANE_Int)cntr; 459 } 460 461 return SANE_STATUS_GOOD; 462} 463 464/** 465 */ 466static SANE_Status u12if_startScan( U12_Device *dev ) 467{ 468 DBG( _DBG_INFO, "u12if_startScan()\n" ); 469 u12hw_StopLampTimer( dev ); 470 u12hw_SetGeneralRegister( dev ); 471 u12hw_ControlLampOnOff( dev ); 472 return SANE_STATUS_GOOD; 473} 474 475/** 476 */ 477static SANE_Status u12if_stopScan( U12_Device *dev ) 478{ 479 DBG( _DBG_INFO, "u12if_stopScan()\n" ); 480 481#if 0 482 u12motor_ToHomePosition( dev, SANE_FALSE ); 483#else 484#if 0 485 u12motor_ToHomePosition( dev, SANE_TRUE ); 486 u12io_SoftwareReset( dev ); 487#endif 488 u12hw_CancelSequence( dev ); 489#endif 490 u12hw_StartLampTimer( dev ); 491 dev->DataInf.dwAppLinesPerArea = 0; 492 dev->DataInf.dwScanFlag &= ~_SCANDEF_SCANNING; 493 return SANE_STATUS_GOOD; 494} 495 496/** 497 */ 498static SANE_Status u12if_prepare( U12_Device *dev ) 499{ 500 SANE_Status res; 501 502 DBG( _DBG_INFO, "u12if_prepare()\n" ); 503 504 u12motor_ToHomePosition( dev, SANE_TRUE ); 505 506 res = u12hw_WarmupLamp( dev ); 507 if( res != SANE_STATUS_GOOD ) 508 return res; 509 510 res = u12shading_DoCalibration( dev ); 511 if( res != SANE_STATUS_GOOD ) 512 return res; 513 514 u12image_PrepareScaling( dev ); 515 516 u12motor_ForceToLeaveHomePos( dev ); 517 if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) 518 u12hw_SetupPreviewCondition( dev ); 519 else 520 u12hw_SetupScanningCondition( dev ); 521 522 res = u12motor_WaitForPositionY( dev ); 523 524 _DODELAY(100); 525 u12io_ResetFifoLen(); 526 u12io_GetFifoLength(dev); 527 528 dev->scan.bModuleState = _MotorAdvancing; 529 dev->scan.oldScanState = u12io_GetScanState( dev ); 530 dev->scan.oldScanState &= _SCANSTATE_MASK; 531 dev->DataInf.dwScanFlag |= _SCANDEF_SCANNING; 532 DBG( _DBG_INFO, "* oldScanState = %u\n", dev->scan.oldScanState ); 533 DBG( _DBG_INFO, "u12if_prepare() done.\n" ); 534 return res; 535} 536 537/** 538 */ 539static SANE_Status u12if_readLine( U12_Device *dev, SANE_Byte *line_buffer ) 540{ 541 SANE_Status res; 542 543 DBG( _DBG_READ, "u12if_readLine()\n" ); 544 545 if( u12io_IsEscPressed()) { 546 DBG( _DBG_INFO, "u12if_readLine() - cancel detected!\n" ); 547 return SANE_STATUS_CANCELLED; 548 } 549 550 if( dev->scaleBuf != NULL ) { 551 res = u12image_ReadOneImageLine( dev, dev->scaleBuf ); 552 if( SANE_STATUS_GOOD != res ) 553 return res; 554 555 u12image_ScaleX( dev, dev->scaleBuf, line_buffer ); 556 557 } else { 558 res = u12image_ReadOneImageLine( dev, line_buffer ); 559 if( SANE_STATUS_GOOD != res ) 560 return res; 561 } 562 return SANE_STATUS_GOOD; 563} 564 565/** 566 */ 567static SANE_Status u12if_SetupBuffer( U12_Device *dev ) 568{ 569 void *buffer; 570 571 DBG( _DBG_INFO, "u12if_SetupBuffer()\n" ); 572 buffer = malloc(_SIZE_TOTAL_BUF_TPA); 573 if( buffer == NULL ) 574 return SANE_STATUS_NO_MEM; 575 576 dev->shade.pHilight = NULL; 577 dev->bufs.b1.pReadBuf = buffer; 578 dev->bufs.b2.pSumBuf = dev->bufs.b1.pReadBuf + _SIZE_DATA_BUF; 579 dev->bufs.TpaBuf.pb = &((SANE_Byte*)dev->bufs.b2.pSumBuf)[_SIZE_SHADING_SUM_BUF]; 580 581/* CHECK: We might should play around with these values... */ 582 dev->shade.skipHilight = _DEF_BRIGHTEST_SKIP; 583 dev->shade.skipShadow = _DEF_DARKEST_SKIP; 584 585 if( dev->shade.skipHilight && dev->shade.skipShadow ) { 586 587 u_long skipSize; 588 589 skipSize = (u_long)((dev->shade.skipHilight + dev->shade.skipShadow) 590 * _SIZE_DATA_BUF * 3); 591 dev->shade.pHilight = (RGBUShortDef*)malloc( skipSize ); 592 if( NULL != dev->shade.pHilight ) { 593 dev->shade.dwDiv = (u_long)(32UL - dev->shade.skipHilight - 594 dev->shade.skipShadow); 595 } 596 } 597 return SANE_STATUS_GOOD; 598} 599 600/* END U12-IF.C .............................................................*/ 601