diff options
Diffstat (limited to 'backend/u12-if.c')
-rw-r--r-- | backend/u12-if.c | 602 |
1 files changed, 602 insertions, 0 deletions
diff --git a/backend/u12-if.c b/backend/u12-if.c new file mode 100644 index 0000000..be213b4 --- /dev/null +++ b/backend/u12-if.c @@ -0,0 +1,602 @@ +/** @file u12-if.c + * @brief The interface functions to the U12 backend stuff. + * + * Copyright (c) 2003-2004 Gerhard Jaeger <gerhard@gjaeger.de> + * + * History: + * - 0.01 - initial version + * - 0.02 - added model tweaking + * - fixed autodetection bug + * - added line-scaling stuff + * - removed u12if_setScanEnv() + * . + * <hr> + * This file is part of the SANE package. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + * + * As a special exception, the authors of SANE give permission for + * additional uses of the libraries contained in this release of SANE. + * + * The exception is that, if you link a SANE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public + * License. Your use of that executable is in no way restricted on + * account of linking the SANE library code into it. + * + * This exception does not, however, invalidate any other reasons why + * the executable file might be covered by the GNU General Public + * License. + * + * If you submit changes to SANE to the maintainers to be included in + * a subsequent release, you agree by submitting the changes that + * those changes may be distributed with this exception intact. + * + * If you write modifications of your own for SANE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * <hr> + */ + +#define _DEF_BRIGHTEST_SKIP 3 +#define _DEF_DARKEST_SKIP 5 + +/** useful for description tables + */ +typedef struct { + int id; + char *desc; +} TabDef; + +typedef struct { + char *vp; + char *name; +} DevDesc; + +#define _PLUSTEK_VENID 0x07B3 +#define _KYE_VENID 0x0458 + +/** to allow different vendors... + */ +static TabDef u12Vendors[] = { + + { _PLUSTEK_VENID, "Plustek" }, + { _KYE_VENID, "KYE/Genius" }, + { 0xFFFF, NULL } +}; + +/** list of supported devices + */ +static DevDesc u12Devices[] = { + { "0x07B3-0x0001", "1212U/U12" }, + { "0x0458-0x2004", "Colorpage HR6" }, + { NULL, NULL } +}; + +/** for autodetection */ +static SANE_Char USB_devname[1024]; + +/********************** the USB scanner interface ****************************/ + +/** + */ +static SANE_Status u12_initDev( U12_Device *dev, int handle, int vendor ) +{ + int i; + SANE_Status res; + TimerDef timer; + + /* well now we patch the vendor string... + * if not found, the default vendor will be Plustek + */ + for( i = 0; u12Vendors[i].desc != NULL; i++ ) { + + if( u12Vendors[i].id == vendor ) { + dev->sane.vendor = u12Vendors[i].desc; + DBG( _DBG_INFO, "Vendor adjusted to: >%s<\n", dev->sane.vendor ); + break; + } + } + dev->fd = handle; + + dev->adj.upNormal = 0; + dev->adj.upNegative = 20; + dev->adj.upPositive = -30; + dev->adj.leftNormal = 51; + + res = SANE_STATUS_IO_ERROR; + if( !(u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER)) { + + u12motor_PositionModuleToHome( dev ); + + u12io_StartTimer( &timer, _SECOND * 20); + do { + if( u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER) { + res = SANE_STATUS_GOOD; + break; + } + } while( !u12io_CheckTimer( &timer )); + } else { + res = u12hw_InitAsic( dev, SANE_FALSE ); + } + + if( res == SANE_STATUS_GOOD ) + u12hw_PutToIdleMode( dev ); + return res; +} + +/** will be called upon sane_exit + */ +static void u12if_shutdown( U12_Device *dev ) +{ + SANE_Int handle; + TimerDef timer; + + DBG( _DBG_INFO, "Shutdown called (dev->fd=%d, %s)\n", + dev->fd, dev->sane.name ); + if( SANE_STATUS_GOOD == sanei_usb_open( dev->sane.name, &handle )) { + + dev->fd = handle; + u12io_OpenScanPath( dev ); + + u12hw_PutToIdleMode( dev ); + + if( !(u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER)) { + + u12motor_PositionModuleToHome( dev ); + + u12io_StartTimer( &timer, _SECOND * 20); + do { + if( u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER) { + break; + } + } while( !u12io_CheckTimer( &timer )); + } + DBG( _DBG_INFO, "* Home position reached.\n" ); + + if( 0 != dev->adj.lampOffOnEnd ) { + + DBG( _DBG_INFO, "* Switching lamp off...\n" ); + dev->regs.RD_ScanControl &= ~_SCAN_LAMPS_ON; + u12io_DataToRegister(dev,REG_SCANCONTROL, dev->regs.RD_ScanControl ); + } + + u12io_CloseScanPath( dev ); + dev->fd = -1; + sanei_usb_close( handle ); + } + +#if 0 + usb_StopLampTimer( dev ); +#endif + DBG( _DBG_INFO, "Shutdown done.\n" ); +} + +/** This function checks wether a device, described by a given + * string(vendor and product ID), is supported by this backend or not + * + * @param usbIdStr - sting consisting out of product and vendor ID + * format: "0xVVVV-0xPPPP" VVVV = Vendor ID, PPP = Product ID + * @returns; SANE_TRUE if supported, SANE_FALSE if not + */ +static SANE_Bool u12if_IsDeviceSupported( U12_Device *dev ) +{ + int i; + + for( i = 0; NULL != u12Devices[i].name; i++ ) { + + if( !strcmp( dev->usbId, u12Devices[i].vp )) { + dev->sane.model = u12Devices[i].name; + return SANE_TRUE; + } + } + + return SANE_FALSE; +} + +/** + */ +static SANE_Status u12if_usbattach( SANE_String_Const dev_name ) +{ + if( USB_devname[0] == '\0' ) { + DBG( _DBG_INFO, "Found device at >%s<\n", dev_name ); + strncpy( USB_devname, dev_name, 1023 ); + USB_devname[1023] = '\0'; + } else { + DBG( _DBG_INFO, "Device >%s< ignoring\n", dev_name ); + } + + return SANE_STATUS_GOOD; +} + +#ifndef _FAKE_DEVICE +/** here we roam through our list of supported devices and + * cross check with the ones the system reports... + * @param vendor - pointer to receive vendor ID + * @param product - pointer to receive product ID + * @return SANE_TRUE if a matching device has been found or + * SANE_FALSE if nothing supported found... + */ +static SANE_Bool usbDev_autodetect( SANE_Word *vendor, SANE_Word *product ) +{ + int i; + SANE_Word p, v; + + DBG( _DBG_INFO, "Autodetection...\n" ); + + for( i = 0; NULL != u12Devices[i].name; i++ ) { + + v = strtol( &(u12Devices[i].vp)[0], 0, 0 ); + p = strtol( &(u12Devices[i].vp)[7], 0, 0 ); + DBG( _DBG_INFO, "* checking for 0x%04x-0x%04x\n", v, p ); + + sanei_usb_find_devices( v, p, u12if_usbattach ); + + if( USB_devname[0] != '\0' ) { + + *vendor = v; + *product = p; + DBG( _DBG_INFO, "* using device >%s<\n", USB_devname ); + return SANE_TRUE; + } + } + + return SANE_FALSE; +} +#endif + +/** + */ +static int u12if_open( U12_Device *dev ) +{ + char devStr[50]; + int result; + SANE_Int handle; + SANE_Word vendor, product; + SANE_Bool was_empty; + + DBG( _DBG_INFO, "u12if_open(%s,%s)\n", dev->name, dev->usbId ); + + USB_devname[0] = '\0'; + +#ifdef _FAKE_DEVICE + dev->name = strdup( "auto" ); + dev->sane.name = dev->name; + was_empty = SANE_FALSE; + + result = SANE_STATUS_UNSUPPORTED; +#else + if( !strcmp( dev->name, "auto" )) { + + if( dev->usbId[0] == '\0' ) { + + if( !usbDev_autodetect( &vendor, &product )) { + DBG( _DBG_ERROR, "No supported device found!\n" ); + return -1; + } + + } else { + + vendor = strtol( &dev->usbId[0], 0, 0 ); + product = strtol( &dev->usbId[7], 0, 0 ); + + sanei_usb_find_devices( vendor, product, u12if_usbattach ); + + if( USB_devname[0] == '\0' ) { + DBG( _DBG_ERROR, "No matching device found!\n" ); + return -1; + } + } + + if( SANE_STATUS_GOOD != sanei_usb_open( USB_devname, &handle )) { + return -1; + } + + /* replace the old devname, so we are able to have multiple + * auto-detected devices + */ + free( dev->name ); + dev->name = strdup( USB_devname ); + dev->sane.name = dev->name; + + } else { + + if( SANE_STATUS_GOOD != sanei_usb_open( dev->name, &handle )) + return -1; + } + was_empty = SANE_FALSE; + + result = sanei_usb_get_vendor_product( handle, &vendor, &product ); +#endif + + if( SANE_STATUS_GOOD == result ) { + + sprintf( devStr, "0x%04X-0x%04X", vendor, product ); + + DBG(_DBG_INFO,"Vendor ID=0x%04X, Product ID=0x%04X\n",vendor,product); + + if( dev->usbId[0] != '\0' ) { + + if( 0 != strcmp( dev->usbId, devStr )) { + DBG( _DBG_ERROR, "Specified Vendor and Product ID " + "doesn't match with the ones\n" + "in the config file\n" ); + sanei_usb_close( handle ); + return -1; + } + } else { + sprintf( dev->usbId, "0x%04X-0x%04X", vendor, product ); + was_empty = SANE_TRUE; + } + + } else { + + DBG( _DBG_INFO, "Can't get vendor & product ID from driver...\n" ); + + /* if the ioctl stuff is not supported by the kernel and we have + * nothing specified, we have to give up... + */ + if( dev->usbId[0] == '\0' ) { + DBG( _DBG_ERROR, "Cannot autodetect Vendor an Product ID, " + "please specify in config file.\n" ); + sanei_usb_close( handle ); + return -1; + } + + vendor = strtol( &dev->usbId[0], 0, 0 ); + product = strtol( &dev->usbId[7], 0, 0 ); + DBG( _DBG_INFO, "... using the specified: " + "0x%04X-0x%04X\n", vendor, product ); + } + + /* before accessing the scanner, check if supported! + */ + if( !u12if_IsDeviceSupported( dev )) { + DBG( _DBG_ERROR, "Device >%s<, is not supported!\n", dev->usbId ); + sanei_usb_close( handle ); + return -1; + } + + dev->mode = _PP_MODE_SPP; + dev->fd = handle; + + /* is it accessible ? */ + if( SANE_STATUS_GOOD != u12hw_CheckDevice( dev )) { + dev->fd = -1; + sanei_usb_close( handle ); + return -1; + } + + DBG( _DBG_INFO, "Detected vendor & product ID: " + "0x%04X-0x%04X\n", vendor, product ); + + if( was_empty ) + dev->usbId[0] = '\0'; + + /* now initialize the device */ + if( SANE_STATUS_GOOD != u12_initDev( dev, handle, vendor )) { + dev->fd = -1; + sanei_usb_close( handle ); + return -1; + } + + if( _PLUSTEK_VENID == vendor ) { + if( dev->Tpa ) + dev->sane.model = "UT12"; + } + + dev->initialized = SANE_TRUE; + return handle; +} + +/** + */ +static int u12if_close( U12_Device *dev ) +{ + DBG( _DBG_INFO, "u12if_close()\n" ); + u12io_CloseScanPath( dev ); + sanei_usb_close( dev->fd ); + dev->fd = -1; + return 0; +} + +/** + */ +static SANE_Status u12if_getCaps( U12_Device *dev ) +{ + int cntr; + int res_x = 600 ; /*dev->caps.OpticDpi.x */ + DBG( _DBG_INFO, "u12if_getCaps()\n" ); + +/* FIXME: set dpi_range.max, max_x & max_y on a per model base */ + dev->dpi_max_x = 600; + dev->dpi_max_y = 1200; + + /* A4 devices */ + dev->max_x = 8.5 * (double)_MM_PER_INCH; + dev->max_y = 11.6934 * (double)_MM_PER_INCH; + + /* limit the range */ + dev->dpi_range.min = _DEF_DPI; + dev->dpi_range.max = dev->dpi_max_y; + dev->dpi_range.quant = 0; + dev->x_range.min = 0; + dev->x_range.max = SANE_FIX(dev->max_x); + dev->x_range.quant = 0; + dev->y_range.min = 0; + dev->y_range.max = SANE_FIX(dev->max_y); + dev->y_range.quant = 0; + + /* calculate the size of the resolution list + + * one more to avoid a buffer overflow, then allocate it... + */ + dev->res_list = (SANE_Int *) + calloc((((res_x * 16)-_DEF_DPI)/25+1), + sizeof (SANE_Int)); + + if (NULL == dev->res_list) { + DBG( _DBG_ERROR, "alloc fail, resolution problem\n" ); + u12if_close(dev); + return SANE_STATUS_INVAL; + } + + /* build up the resolution table */ + dev->res_list_size = 0; + for( cntr = _DEF_DPI; cntr <= (res_x*16); cntr += 25 ) { + dev->res_list_size++; + dev->res_list[dev->res_list_size - 1] = (SANE_Int)cntr; + } + + return SANE_STATUS_GOOD; +} + +/** + */ +static SANE_Status u12if_startScan( U12_Device *dev ) +{ + DBG( _DBG_INFO, "u12if_startScan()\n" ); + u12hw_StopLampTimer( dev ); + u12hw_SetGeneralRegister( dev ); + u12hw_ControlLampOnOff( dev ); + return SANE_STATUS_GOOD; +} + +/** + */ +static SANE_Status u12if_stopScan( U12_Device *dev ) +{ + DBG( _DBG_INFO, "u12if_stopScan()\n" ); + +#if 0 + u12motor_ToHomePosition( dev, SANE_FALSE ); +#else +#if 0 + u12motor_ToHomePosition( dev, SANE_TRUE ); + u12io_SoftwareReset( dev ); +#endif + u12hw_CancelSequence( dev ); +#endif + u12hw_StartLampTimer( dev ); + dev->DataInf.dwAppLinesPerArea = 0; + dev->DataInf.dwScanFlag &= ~_SCANDEF_SCANNING; + return SANE_STATUS_GOOD; +} + +/** + */ +static SANE_Status u12if_prepare( U12_Device *dev ) +{ + SANE_Status res; + + DBG( _DBG_INFO, "u12if_prepare()\n" ); + + u12motor_ToHomePosition( dev, SANE_TRUE ); + + res = u12hw_WarmupLamp( dev ); + if( res != SANE_STATUS_GOOD ) + return res; + + res = u12shading_DoCalibration( dev ); + if( res != SANE_STATUS_GOOD ) + return res; + + u12image_PrepareScaling( dev ); + + u12motor_ForceToLeaveHomePos( dev ); + if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) + u12hw_SetupPreviewCondition( dev ); + else + u12hw_SetupScanningCondition( dev ); + + res = u12motor_WaitForPositionY( dev ); + + _DODELAY(100); + u12io_ResetFifoLen(); + u12io_GetFifoLength(dev); + + dev->scan.bModuleState = _MotorAdvancing; + dev->scan.oldScanState = u12io_GetScanState( dev ); + dev->scan.oldScanState &= _SCANSTATE_MASK; + dev->DataInf.dwScanFlag |= _SCANDEF_SCANNING; + DBG( _DBG_INFO, "* oldScanState = %u\n", dev->scan.oldScanState ); + DBG( _DBG_INFO, "u12if_prepare() done.\n" ); + return res; +} + +/** + */ +static SANE_Status u12if_readLine( U12_Device *dev, SANE_Byte *line_buffer ) +{ + SANE_Status res; + + DBG( _DBG_READ, "u12if_readLine()\n" ); + + if( u12io_IsEscPressed()) { + DBG( _DBG_INFO, "u12if_readLine() - cancel detected!\n" ); + return SANE_STATUS_CANCELLED; + } + + if( dev->scaleBuf != NULL ) { + res = u12image_ReadOneImageLine( dev, dev->scaleBuf ); + if( SANE_STATUS_GOOD != res ) + return res; + + u12image_ScaleX( dev, dev->scaleBuf, line_buffer ); + + } else { + res = u12image_ReadOneImageLine( dev, line_buffer ); + if( SANE_STATUS_GOOD != res ) + return res; + } + return SANE_STATUS_GOOD; +} + +/** + */ +static SANE_Status u12if_SetupBuffer( U12_Device *dev ) +{ + void *buffer; + + DBG( _DBG_INFO, "u12if_SetupBuffer()\n" ); + buffer = malloc(_SIZE_TOTAL_BUF_TPA); + if( buffer == NULL ) + return SANE_STATUS_NO_MEM; + + dev->shade.pHilight = NULL; + dev->bufs.b1.pReadBuf = buffer; + dev->bufs.b2.pSumBuf = dev->bufs.b1.pReadBuf + _SIZE_DATA_BUF; + dev->bufs.TpaBuf.pb = &((SANE_Byte*)dev->bufs.b2.pSumBuf)[_SIZE_SHADING_SUM_BUF]; + +/* CHECK: We might should play around with these values... */ + dev->shade.skipHilight = _DEF_BRIGHTEST_SKIP; + dev->shade.skipShadow = _DEF_DARKEST_SKIP; + + if( dev->shade.skipHilight && dev->shade.skipShadow ) { + + u_long skipSize; + + skipSize = (u_long)((dev->shade.skipHilight + dev->shade.skipShadow) + * _SIZE_DATA_BUF * 3); + dev->shade.pHilight = (RGBUShortDef*)malloc( skipSize ); + if( NULL != dev->shade.pHilight ) { + dev->shade.dwDiv = (u_long)(32UL - dev->shade.skipHilight - + dev->shade.skipShadow); + } + } + return SANE_STATUS_GOOD; +} + +/* END U12-IF.C .............................................................*/ |