diff options
Diffstat (limited to 'backend/plustek-usb.c')
-rw-r--r-- | backend/plustek-usb.c | 1526 |
1 files changed, 1526 insertions, 0 deletions
diff --git a/backend/plustek-usb.c b/backend/plustek-usb.c new file mode 100644 index 0000000..6c9e67a --- /dev/null +++ b/backend/plustek-usb.c @@ -0,0 +1,1526 @@ +/*............................................................................. + * Project : SANE library for Plustek flatbed scanners. + *............................................................................. + */ + +/** @file plustek-usb.c + * @brief The interface functions to the USB driver stuff. + * + * Based on sources acquired from Plustek Inc.<br> + * Copyright (C) 2001-2007 Gerhard Jaeger <gerhard@gjaeger.de> + * + * History: + * - 0.40 - starting version of the USB support + * - 0.41 - removed CHECK + * - added Canon to the manufacturer list + * - 0.42 - added warmup stuff + * - added setmap function + * - changed detection stuff, so we first check whether + * - the vendor and product Ids match with the ones in our list + * - 0.43 - cleanup + * - 0.44 - changes to integration CIS based devices + * - 0.45 - added skipFine assignment + * - added auto device name detection if only product and vendor id<br> + * has been specified + * - made 16-bit gray mode work + * - added special handling for Genius devices + * - added TPA autodetection for EPSON Photo + * - fixed bug that causes warmup each time autodetected<br> + * TPA on EPSON is used + * - removed Genius from PCB-Id check + * - added Compaq to the list + * - removed the scaler stuff for CIS devices + * - removed homeing stuff from readline function + * - fixed flag setting in usbDev_startScan() + * - 0.46 - added additional branch to support alternate calibration + * - 0.47 - added special handling with 0x400 vendor ID and model override + * - removed PATH_MAX + * - change usbDev_stopScan and usbDev_open prototype + * - cleanup + * - 0.48 - added function usb_CheckAndCopyAdjs() + * - 0.49 - changed autodetection + * - added support for LiDE25 (pid 0x2220) + * - 0.50 - minor fix for startup reset + * removed unnecessary calls to usbio_ResetLM983x() + * 1200DPI CIS devices don't use GrayFromColor any longer + * - 0.51 - added Syscan to the vendor list + * - added SCANFLAG_Calibration handling + * - 0.52 - added _WAF_LOFF_ON_START and _WAF_INC_DARKTGT + * handling in usbDev_startScan() + * added Visioneer + * . + * <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> + */ + +/** useful for description tables + */ +typedef struct { + int id; + char *desc; + char *desc_alt; +} TabDef, *pTabDef; + +/** to allow different vendors... + */ +static TabDef usbVendors[] = { + + { 0x07B3, "Plustek", NULL }, + { 0x0400, "NSC", "Mustek" }, + { 0x0458, "KYE/Genius", NULL }, + { 0x03F0, "Hewlett-Packard", NULL }, + { 0x04B8, "Epson", NULL }, + { 0x04A7, "Visioneer", NULL }, + { 0x04A9, "Canon", NULL }, + { 0x1606, "UMAX", NULL }, + { 0x049F, "Compaq", NULL }, + { 0x0A82, "Syscan", NULL }, + { 0x0A53, "PandP Co., Ltd.", NULL }, + { 0xFFFF, NULL, NULL } +}; + +/** we use at least 8 megs for scanning... */ +#define _SCANBUF_SIZE (8 * 1024 * 1024) + +/********************** the USB scanner interface ****************************/ + +/** remove the slash out of the model-name to obtain a valid filename + */ +static SANE_Bool usb_normFileName( char *fname, char* buffer, u_long max_len ) +{ + char *src, *dst; + + if( NULL == fname ) + return SANE_FALSE; + + if( strlen( fname ) >= max_len ) + return SANE_FALSE; + + src = fname; + dst = buffer; + while( *src != '\0' ) { + + if((*src == '/') || isspace(*src) || ispunct(*src)) + *dst = '_'; + else + *dst = *src; + + dst++; + src++; + } + *dst = '\0'; + + return SANE_TRUE; +} + +/** do some range checking and copy the adjustment values from the + * frontend to our internal structures, so that the backend can take + * care of them. + */ +static void usb_CheckAndCopyAdjs( Plustek_Device *dev ) +{ + if( dev->adj.lampOff >= 0 ) + dev->usbDev.dwLampOnPeriod = dev->adj.lampOff; + + if( dev->adj.lampOffOnEnd >= 0 ) + dev->usbDev.bLampOffOnEnd = dev->adj.lampOffOnEnd; + + if( dev->adj.skipCalibration > 0 ) + dev->usbDev.Caps.workaroundFlag |= _WAF_BYPASS_CALIBRATION; + + if( dev->adj.skipFine > 0 ) + dev->usbDev.Caps.workaroundFlag |= _WAF_SKIP_FINE; + + if( dev->adj.skipFineWhite > 0 ) + dev->usbDev.Caps.workaroundFlag |= _WAF_SKIP_WHITEFINE; + + if( dev->adj.incDarkTgt > 0 ) + dev->usbDev.Caps.workaroundFlag |= _WAF_INC_DARKTGT; + + if( dev->adj.skipDarkStrip > 0 ) + dev->usbDev.Caps.Normal.DarkShadOrgY = -1; + + if( dev->adj.invertNegatives > 0 ) + dev->usbDev.Caps.workaroundFlag |= _WAF_INV_NEGATIVE_MAP; +} + +/** + * assign the values to the structures used by the currently found scanner + */ +static void +usb_initDev( Plustek_Device *dev, int idx, int handle, int vendor ) +{ + char *ptr; + char tmp_str1[PATH_MAX]; + char tmp_str2[PATH_MAX]; + int i; + ScanParam sParam; + u_short tmp = 0; + + DBG( _DBG_INFO, "usb_initDev(%d,0x%04x,%i)\n", + idx, vendor, dev->initialized ); + /* save capability flags... */ + if( dev->initialized >= 0 ) { + tmp = DEVCAPSFLAG_TPA; + } + + /* copy the original values... */ + memcpy( &dev->usbDev.Caps, Settings[idx].pDevCaps, sizeof(DCapsDef)); + memcpy( &dev->usbDev.HwSetting, Settings[idx].pHwDef, sizeof(HWDef)); + + /* restore capability flags... */ + if( dev->initialized >= 0 ) { + dev->usbDev.Caps.wFlags |= tmp; + } + + usb_CheckAndCopyAdjs( dev ); + DBG( _DBG_INFO, "Device WAF : 0x%08lx\n", dev->usbDev.Caps.workaroundFlag ); + DBG( _DBG_INFO, "Transferrate: %lu Bytes/s\n", dev->transferRate ); + + /* adjust data origin + */ + dev->usbDev.Caps.Positive.DataOrigin.x -= dev->adj.tpa.x; + dev->usbDev.Caps.Positive.DataOrigin.y -= dev->adj.tpa.y; + + dev->usbDev.Caps.Negative.DataOrigin.x -= dev->adj.neg.x; + dev->usbDev.Caps.Negative.DataOrigin.y -= dev->adj.neg.y; + + dev->usbDev.Caps.Normal.DataOrigin.x -= dev->adj.pos.x; + dev->usbDev.Caps.Normal.DataOrigin.y -= dev->adj.pos.y; + + /** adjust shading position + */ + if( dev->adj.posShadingY >= 0 ) + dev->usbDev.Caps.Normal.ShadingOriginY = dev->adj.posShadingY; + + if( dev->adj.tpaShadingY >= 0 ) + dev->usbDev.Caps.Positive.ShadingOriginY = dev->adj.tpaShadingY; + + if( dev->adj.negShadingY >= 0 ) + dev->usbDev.Caps.Negative.ShadingOriginY = dev->adj.negShadingY; + + /* adjust the gamma settings... */ + if( dev->adj.rgamma == 1.0 ) + dev->adj.rgamma = dev->usbDev.HwSetting.gamma; + if( dev->adj.ggamma == 1.0 ) + dev->adj.ggamma = dev->usbDev.HwSetting.gamma; + if( dev->adj.bgamma == 1.0 ) + dev->adj.bgamma = dev->usbDev.HwSetting.gamma; + if( dev->adj.graygamma == 1.0 ) + dev->adj.graygamma = dev->usbDev.HwSetting.gamma; + + /* the following you normally get from the registry... + */ + bMaxITA = 0; /* Maximum integration time adjust */ + + dev->usbDev.ModelStr = Settings[idx].pModelString; + + dev->fd = handle; + + if( dev->initialized < 0 ) { + if( usb_HasTPA( dev )) + dev->usbDev.Caps.wFlags |= DEVCAPSFLAG_TPA; + } + DBG( _DBG_INFO, "Device Flags: 0x%08x\n", dev->usbDev.Caps.wFlags ); + + /* well now we patch the vendor string... + * if not found, the default vendor will be Plustek + */ + for( i = 0; usbVendors[i].desc != NULL; i++ ) { + + if( usbVendors[i].id == vendor ) { + dev->sane.vendor = usbVendors[i].desc; + if (dev->usbDev.Caps.workaroundFlag & _WAF_USE_ALT_DESC ) + if (usbVendors[i].desc_alt ) + dev->sane.vendor = usbVendors[i].desc_alt; + DBG( _DBG_INFO, "Vendor adjusted to: >%s<\n", dev->sane.vendor ); + break; + } + } + + dev->usbDev.dwTicksLampOn = 0; + dev->usbDev.currentLamp = usb_GetLampStatus( dev ); + usb_ResetRegisters( dev ); + + if( dev->initialized >= 0 ) + return; + + usb_IsScannerReady( dev ); + + sParam.bBitDepth = 8; + sParam.bCalibration = PARAM_Scan; + sParam.bChannels = 3; + sParam.bDataType = SCANDATATYPE_Color; + sParam.bSource = SOURCE_Reflection; + sParam.Origin.x = 0; + sParam.Origin.y = 0; + sParam.UserDpi.x = 150; + sParam.UserDpi.y = 150; + sParam.dMCLK = 4; + sParam.Size.dwPixels = 0; + + /* create calibration-filename */ + sprintf( tmp_str2, "%s-%s", + dev->sane.vendor, dev->usbDev.ModelStr ); + + if( !usb_normFileName( tmp_str2, tmp_str1, PATH_MAX )) { + strcpy( tmp_str1, "plustek-default" ); + } + + ptr = getenv ("HOME"); + if( NULL == ptr ) { + sprintf( tmp_str2, "/tmp/%s", tmp_str1 ); + } else { + sprintf( tmp_str2, "%s/.sane/%s", ptr, tmp_str1 ); + } + dev->calFile = strdup( tmp_str2 ); + DBG( _DBG_INFO, "Calibration file-names set to:\n" ); + DBG( _DBG_INFO, ">%s-coarse.cal<\n", dev->calFile ); + DBG( _DBG_INFO, ">%s-fine.cal<\n", dev->calFile ); + + /* initialize the ASIC registers */ + usb_SetScanParameters( dev, &sParam ); + + /* check and move sensor to its home position */ + usb_ModuleToHome( dev, SANE_FALSE ); + + /* set the global flag, that we are initialized so far */ + dev->initialized = idx; +} + +/** + * will be used for retrieving a Plustek device + */ +static int usb_CheckForPlustekDevice( int handle, Plustek_Device *dev ) +{ + char tmp[50]; + char pcbStr[10]; + u_char reg59[3], reg59s[3], pcbID; + int i, result; + + /* + * Plustek uses the misc IO 12 to get the PCB ID + * (PCB = printed circuit board), so it's possible to have one + * product ID and up to 7 different devices... + */ + DBG( _DBG_INFO, "Trying to get the pcbID of a Plustek device...\n" ); + + /* get the PCB-ID */ + result = sanei_lm983x_read( handle, 0x59, reg59s, 3, SANE_TRUE ); + if( SANE_STATUS_GOOD != result ) { + sanei_usb_close( handle ); + return -1; + } + + reg59[0] = 0x22; /* PIO1: Input, PIO2: Input */ + reg59[1] = 0x02; /* PIO3: Input, PIO4: Output as low */ + reg59[2] = 0x03; + + result = sanei_lm983x_write( handle, 0x59, reg59, 3, SANE_TRUE ); + if( SANE_STATUS_GOOD != result ) { + sanei_usb_close( handle ); + return -1; + } + + result = sanei_lm983x_read ( handle, 0x02, &pcbID, 1, SANE_TRUE ); + if( SANE_STATUS_GOOD != result ) { + sanei_usb_close( handle ); + return -1; + } + + pcbID = (u_char)((pcbID >> 2) & 0x07); + + result = sanei_lm983x_read( handle, 0x59, reg59s, 3, SANE_TRUE ); + if( SANE_STATUS_GOOD != result ) { + sanei_usb_close( handle ); + return -1; + } + + DBG( _DBG_INFO, "pcbID=0x%02x\n", pcbID ); + + /* now roam through the setting list... */ + strncpy( tmp, dev->usbId, 13 ); + tmp[13] = '\0'; + + sprintf( pcbStr, "-%u", pcbID ); + strcat ( tmp, pcbStr ); + + DBG( _DBG_INFO, "Checking for device >%s<\n", tmp ); + + for( i = 0; NULL != Settings[i].pIDString; i++ ) { + + if( 0 == strcmp( Settings[i].pIDString, tmp )) { + DBG(_DBG_INFO, "Device description for >%s< found.\n", tmp ); + usb_initDev( dev, i, handle, dev->usbDev.vendor ); + return handle; + } + } + + return -1; +} + +/** + * will be called upon sane_exit + */ +static void usbDev_shutdown( Plustek_Device *dev ) +{ + SANE_Int handle; + + DBG( _DBG_INFO, "Shutdown called (dev->fd=%d, %s)\n", + dev->fd, dev->sane.name ); + if( NULL == dev->usbDev.ModelStr ) { + DBG( _DBG_INFO, "Function ignored!\n" ); + return; + } + + if( SANE_STATUS_GOOD == sanei_usb_open( dev->sane.name, &handle )) { + + dev->fd = handle; + + DBG( _DBG_INFO, "Waiting for scanner-ready...\n" ); + usb_IsScannerReady( dev ); + + if( 0 != dev->usbDev.bLampOffOnEnd ) { + + DBG( _DBG_INFO, "Switching lamp off...\n" ); + usb_LampOn( dev, SANE_FALSE, SANE_FALSE ); + } + dev->fd = -1; + sanei_usb_close( handle ); + } + usb_StopLampTimer( dev ); +} + +/** + * This function checks wether a device, described by a given + * string(vendor and product ID), is support by this backend or not + * + * @param usbIdStr - sting consisting out of product and vendor ID + * format: "0xVVVVx0xPPPP" VVVV = Vendor ID, PPP = Product ID + * @returns; SANE_TRUE if supported, SANE_FALSE if not + */ +static SANE_Bool usb_IsDeviceInList( char *usbIdStr ) +{ + int i; + + for( i = 0; NULL != Settings[i].pIDString; i++ ) { + + if( 0 == strncmp( Settings[i].pIDString, usbIdStr, 13 )) + return SANE_TRUE; + } + return SANE_FALSE; +} + +/** get last valid entry of a list + */ +static DevList* +getLast( DevList *l ) +{ + if( l == NULL ) + return NULL; + + while( l->next != NULL ) + l = l->next; + return l; +} + +/** add a new entry to our internal device list, when a device is detected + */ +static SANE_Status usb_attach( SANE_String_Const dev_name ) +{ + int len; + DevList *tmp, *last; + + /* get some memory for the entry... */ + len = sizeof(DevList) + strlen(dev_name) + 1; + tmp = (DevList*)malloc(len); + + /* initialize and set the values */ + memset(tmp, 0, len ); + + /* the device name is part of our structure space */ + tmp->dev_name = &((char*)tmp)[sizeof(DevList)]; + strcpy( tmp->dev_name, dev_name ); + tmp->attached = SANE_FALSE; + + /* root set ? */ + if( usbDevs == NULL ) { + usbDevs = tmp; + } else { + last = getLast(usbDevs); /* append... */ + last->next = tmp; + } + return SANE_STATUS_GOOD; +} + +/** + */ +static void +usbGetList( DevList **devs ) +{ + int i; + SANE_Bool il; + SANE_Word v, p; + DevList *tmp; + + DBG( _DBG_INFO, "Retrieving all supported and conntected devices\n" ); + for( i = 0; NULL != Settings[i].pIDString; i++ ) { + + v = strtol( &(Settings[i].pIDString)[0], 0, 0 ); + p = strtol( &(Settings[i].pIDString)[7], 0, 0 ); + + /* check if this vendor- and product-ID has already been added, needed + * for Plustek devices - here one product-ID is used for more than one + * device type... + */ + il = SANE_FALSE; + for( tmp = *devs; tmp ; tmp = tmp->next ) { + if( tmp->device_id == p && tmp->vendor_id == v ) { + il = SANE_TRUE; + break; + } + } + if( il ) { + DBG( _DBG_INFO2, "Already in list: 0x%04x-0x%04x\n", v, p ); + continue; + } + + /* get the last entry... */ + tmp = getLast(*devs); + DBG( _DBG_INFO2, "Checking for 0x%04x-0x%04x\n", v, p ); + sanei_usb_find_devices( v, p, usb_attach ); + + if( getLast(*devs) != tmp ) { + + if( tmp == NULL ) + tmp = *devs; + else + tmp = tmp->next; + + while( tmp != NULL ) { + tmp->vendor_id = v; + tmp->device_id = p; + tmp = tmp->next; + } + } + } + + DBG( _DBG_INFO, "Available and supported devices:\n" ); + if( *devs == NULL ) + DBG( _DBG_INFO, "NONE.\n" ); + + for( tmp = *devs; tmp; tmp = tmp->next ) { + DBG( _DBG_INFO, "Device: >%s< - 0x%04xx0x%04x\n", + tmp->dev_name, tmp->vendor_id, tmp->device_id ); + } +} + +/** + */ +static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock ) +{ + char dn[512]; + char devStr[50]; + int result; + int i; + int lc; + SANE_Int handle; + SANE_Byte version; + SANE_Word vendor, product; + SANE_Bool was_empty; + SANE_Status status; + DevList *tmp; + + DBG( _DBG_INFO, "usbDev_open(%s,%s) - %p\n", + dev->name, dev->usbId, (void*)devs ); + + /* preset our internal usb device structure */ + memset( &dev->usbDev, 0, sizeof(DeviceDef)); + + /* devs is NULL, when called from sane_start */ + if( devs ) { + + dn[0] = '\0'; + if( !strcmp( dev->name, "auto" )) { + + /* use the first "unattached"... */ + for( tmp = devs; tmp; tmp = tmp->next ) { + if( !tmp->attached ) { + tmp->attached = SANE_TRUE; + strcpy( dn, tmp->dev_name ); + break; + } + } + } else { + + vendor = strtol( &dev->usbId[0], 0, 0 ); + product = strtol( &dev->usbId[7], 0, 0 ); + + /* check the first match... */ + for( tmp = devs; tmp; tmp = tmp->next ) { + if( tmp->vendor_id == vendor && tmp->device_id == product ) { + if( !tmp->attached ) { + tmp->attached = SANE_TRUE; + strcpy( dn, tmp->dev_name ); + break; + } + } + } + } + + if( !dn[0] ) { + DBG( _DBG_ERROR, "No supported device found!\n" ); + return -1; + } + + status = sanei_access_lock( dn, 5 ); + if( SANE_STATUS_GOOD != status ) { + DBG( _DBG_ERROR, "sanei_access_lock failed: %d\n", status ); + return -1; + } + + status = sanei_usb_open( dn, &handle ); + if( SANE_STATUS_GOOD != status ) { + DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n", + strerror(errno), errno); + sanei_access_unlock( dev->sane.name ); + return -1; + } + + /* replace the old devname, so we are able to have multiple + * auto-detected devices + */ + free( dev->name ); + dev->name = strdup(dn); + dev->sane.name = dev->name; + + } else { + + status = sanei_access_lock( dev->sane.name, 5 ); + if( SANE_STATUS_GOOD != status ) { + DBG( _DBG_ERROR, "sanei_access_lock failed: %d\n", status ); + return -1; + } + + status = sanei_usb_open( dev->name, &handle ); + if( SANE_STATUS_GOOD != status ) { + DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n", + strerror(errno), errno); + sanei_access_unlock( dev->sane.name ); + return -1; + } + } + + was_empty = SANE_FALSE; + + result = sanei_usb_get_vendor_product( handle, &vendor, &product ); + + 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_access_unlock( dev->sane.name ); + 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_access_unlock( dev->sane.name ); + 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( !usb_IsDeviceInList( dev->usbId )) { + DBG( _DBG_ERROR, "Device >%s<, is not supported!\n", dev->usbId ); + sanei_access_unlock( dev->sane.name ); + sanei_usb_close( handle ); + return -1; + } + + status = usbio_DetectLM983x( handle, &version ); + if( SANE_STATUS_GOOD != status ) { + sanei_usb_close( handle ); + sanei_access_unlock( dev->sane.name ); + return -1; + } + + if ((version < 3) || (version > 4)) { + DBG( _DBG_ERROR, "This is not a LM9831 or LM9832 chip based scanner.\n" ); + sanei_usb_close( handle ); + sanei_access_unlock( dev->sane.name ); + return -1; + } + + /* need to set the handle and the detected chiptype... */ + dev->fd = handle; + dev->usbDev.HwSetting.chip = (version==3 ? _LM9831:_LM9832); + usbio_ResetLM983x( dev ); + dev->fd = -1; + + dev->usbDev.vendor = vendor; + dev->usbDev.product = product; + + DBG( _DBG_INFO, "Detected vendor & product ID: " + "0x%04X-0x%04X\n", vendor, product ); + + /* + * Plustek uses the misc IO 1/2 to get the PCB ID + * (PCB = printed circuit board), so it's possible to have one + * product ID and up to 7 different devices... + */ + if( 0x07B3 == vendor ) { + + handle = usb_CheckForPlustekDevice( handle, dev ); + + if( was_empty ) + dev->usbId[0] = '\0'; + + if( handle >= 0 ) { + if( !keep_lock ) + sanei_access_unlock( dev->sane.name ); + return handle; + } + + } else { + + /* now roam through the setting list... */ + lc = 13; + strncpy( devStr, dev->usbId, lc ); + devStr[lc] = '\0'; + + if( 0x400 == vendor ) { + if((dev->adj.mov < 0) || (dev->adj.mov > 1)) { + DBG(_DBG_INFO, "BearPaw MOV out of range: %d\n", dev->adj.mov); + dev->adj.mov = 0; + } + sprintf( devStr, "%s-%d", dev->usbId, dev->adj.mov ); + lc = strlen(devStr); + DBG( _DBG_INFO, "BearPaw device: %s (%d)\n", devStr, lc ); + } + + if( was_empty ) + dev->usbId[0] = '\0'; + + /* if we don't use the PCD ID extension... + */ + for( i = 0; NULL != Settings[i].pIDString; i++ ) { + + if( 0 == strncmp( Settings[i].pIDString, devStr, lc )) { + DBG( _DBG_INFO, "Device description for >%s< found.\n", devStr ); + usb_initDev( dev, i, handle, vendor ); + if( !keep_lock ) + sanei_access_unlock( dev->sane.name ); + return handle; + } + } + } + + sanei_access_unlock( dev->sane.name ); + sanei_usb_close( handle ); + DBG( _DBG_ERROR, "No matching device found >%s<\n", devStr ); + return -1; +} + +/** + */ +static int usbDev_close( Plustek_Device *dev ) +{ + DBG( _DBG_INFO, "usbDev_close()\n" ); + sanei_usb_close( dev->fd ); + dev->fd = -1; + return 0; +} + +/** convert the stuff + */ +static int usbDev_getCaps( Plustek_Device *dev ) +{ + DCapsDef *scaps = &dev->usbDev.Caps; + + DBG( _DBG_INFO, "usbDev_getCaps()\n" ); + + dev->caps.dwFlag = 0; + + if(((DEVCAPSFLAG_Positive & scaps->wFlags) && + (DEVCAPSFLAG_Negative & scaps->wFlags)) || + (DEVCAPSFLAG_TPA & scaps->wFlags)) { + dev->caps.dwFlag |= SFLAG_TPA; + } + + dev->caps.wMaxExtentX = scaps->Normal.Size.x; + dev->caps.wMaxExtentY = scaps->Normal.Size.y; + return 0; +} + +/** usbDev_getCropInfo + * function to set the image relevant stuff + */ +static int usbDev_getCropInfo( Plustek_Device *dev, CropInfo *ci ) +{ + WinInfo size; + + DBG( _DBG_INFO, "usbDev_getCropInfo()\n" ); + + usb_GetImageInfo( dev, &ci->ImgDef, &size ); + + ci->dwPixelsPerLine = size.dwPixels; + ci->dwLinesPerArea = size.dwLines; + ci->dwBytesPerLine = size.dwBytes; + + if( ci->ImgDef.dwFlag & SCANFLAG_DWORDBoundary ) + ci->dwBytesPerLine = (ci->dwBytesPerLine + 3UL) & 0xfffffffcUL; + + DBG( _DBG_INFO, "PPL = %lu\n", ci->dwPixelsPerLine ); + DBG( _DBG_INFO, "LPA = %lu\n", ci->dwLinesPerArea ); + DBG( _DBG_INFO, "BPL = %lu\n", ci->dwBytesPerLine ); + + return 0; +} + +/** + */ +static int usbDev_setMap( Plustek_Device *dev, SANE_Word *map, + SANE_Word length, SANE_Word channel ) +{ + SANE_Word i, idx; + + DBG(_DBG_INFO,"Setting map[%u] at 0x%08lx\n",channel,(unsigned long)map); + + _VAR_NOT_USED( dev ); + + if( channel == _MAP_MASTER ) { + + for( i = 0; i < length; i++ ) { + a_bMap[i] = (SANE_Byte)map[i]; + a_bMap[length +i] = (SANE_Byte)map[i]; + a_bMap[(length*2)+i] = (SANE_Byte)map[i]; + } + + } else { + + idx = 0; + if( channel == _MAP_GREEN ) + idx = 1; + if( channel == _MAP_BLUE ) + idx = 2; + + for( i = 0; i < length; i++ ) { + a_bMap[(length * idx)+i] = (SANE_Byte)map[i]; + } + } + + return 0; +} + +/** + */ +static int +usbDev_setScanEnv( Plustek_Device *dev, ScanInfo *si ) +{ + ScanDef *scan = &dev->scanning; + DCapsDef *caps = &dev->usbDev.Caps; + + DBG( _DBG_INFO, "usbDev_setScanEnv()\n" ); + + /* clear all the stuff */ + memset( scan, 0, sizeof(ScanDef)); + + if((si->ImgDef.dwFlag & SCANDEF_Adf) && + (si->ImgDef.dwFlag & SCANDEF_ContinuousScan)) { + scan->sParam.dMCLK = dMCLK_ADF; + } + + /* Save necessary informations */ + scan->fGrayFromColor = 0; + + /* for some devices and settings, we tweak the physical settings + * how to get the image - but not in calibration mode + */ + if((si->ImgDef.dwFlag & SCANFLAG_Calibration) == 0) { + + if( si->ImgDef.wDataType == COLOR_256GRAY ) { + + if( !(si->ImgDef.dwFlag & SCANDEF_Adf) && !usb_IsCISDevice(dev) && + (caps->OpticDpi.x == 1200 && si->ImgDef.xyDpi.x <= 300)) { + scan->fGrayFromColor = 2; + si->ImgDef.wDataType = COLOR_TRUE24; + DBG( _DBG_INFO, "* Gray from color set!\n" ); + } + + if( caps->workaroundFlag & _WAF_GRAY_FROM_COLOR ) { + DBG( _DBG_INFO, "* Gray(8-bit) from color set!\n" ); + scan->fGrayFromColor = 2; + si->ImgDef.wDataType = COLOR_TRUE24; + } + + } else if ( si->ImgDef.wDataType == COLOR_GRAY16 ) { + if( caps->workaroundFlag & _WAF_GRAY_FROM_COLOR ) { + DBG( _DBG_INFO, "* Gray(16-bit) from color set!\n" ); + scan->fGrayFromColor = 2; + si->ImgDef.wDataType = COLOR_TRUE48; + } + + } else if ( si->ImgDef.wDataType == COLOR_BW ) { + if( caps->workaroundFlag & _WAF_BIN_FROM_COLOR ) { + DBG( _DBG_INFO, "* Binary from color set!\n" ); + scan->fGrayFromColor = 10; + si->ImgDef.wDataType = COLOR_TRUE24; + } + } + } + + usb_SaveImageInfo( dev, &si->ImgDef ); + usb_GetImageInfo ( dev, &si->ImgDef, &scan->sParam.Size ); + + /* mask the flags */ + scan->dwFlag = si->ImgDef.dwFlag & + (SCANFLAG_bgr | SCANFLAG_BottomUp | SCANFLAG_Calibration | + SCANFLAG_DWORDBoundary | SCANFLAG_RightAlign | + SCANFLAG_StillModule | SCANDEF_Adf | SCANDEF_ContinuousScan); + + if( !(SCANDEF_QualityScan & si->ImgDef.dwFlag)) { + DBG( _DBG_INFO, "* Preview Mode set!\n" ); + } else { + DBG( _DBG_INFO, "* Preview Mode NOT set!\n" ); + scan->dwFlag |= SCANDEF_QualityScan; + } + + scan->sParam.brightness = si->siBrightness; + scan->sParam.contrast = si->siContrast; + + if( scan->sParam.bBitDepth <= 8 ) + scan->dwFlag &= ~SCANFLAG_RightAlign; + + if( scan->dwFlag & SCANFLAG_DWORDBoundary ) { + if( scan->fGrayFromColor && scan->fGrayFromColor < 10) + scan->dwBytesLine = (scan->sParam.Size.dwBytes / 3 + 3) & 0xfffffffcUL; + else + scan->dwBytesLine = (scan->sParam.Size.dwBytes + 3UL) & 0xfffffffcUL; + + } else { + + if( scan->fGrayFromColor && scan->fGrayFromColor < 10) + scan->dwBytesLine = scan->sParam.Size.dwBytes / 3; + else + scan->dwBytesLine = scan->sParam.Size.dwBytes; + } + + /* on CIS based devices we have to reconfigure the illumination + * settings for the gray modes + */ + usb_AdjustCISLampSettings( dev, SANE_TRUE ); + + if( scan->dwFlag & SCANFLAG_BottomUp) + scan->lBufAdjust = -(long)scan->dwBytesLine; + else + scan->lBufAdjust = scan->dwBytesLine; + + /* LM9831 has a BUG in 16-bit mode, + * so we generate pseudo 16-bit data from 8-bit + */ + if( scan->sParam.bBitDepth > 8 ) { + + if( _LM9831 == dev->usbDev.HwSetting.chip ) { + + scan->sParam.bBitDepth = 8; + scan->dwFlag |= SCANFLAG_Pseudo48; + scan->sParam.Size.dwBytes >>= 1; + } + } + + /* Source selection */ + if( scan->sParam.bSource == SOURCE_Reflection ) { + + dev->usbDev.pSource = &caps->Normal; + scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x + + (u_long)dev->usbDev.Normal.lLeft; + scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y + + (u_long)dev->usbDev.Normal.lUp; + + } else if( scan->sParam.bSource == SOURCE_Transparency ) { + + dev->usbDev.pSource = &caps->Positive; + scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x + + (u_long)dev->usbDev.Positive.lLeft; + scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y + + (u_long)dev->usbDev.Positive.lUp; + + } else if( scan->sParam.bSource == SOURCE_Negative ) { + + dev->usbDev.pSource = &caps->Negative; + scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x + + (u_long)dev->usbDev.Negative.lLeft; + scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y + + (u_long)dev->usbDev.Negative.lUp; + + } else { + + dev->usbDev.pSource = &dev->usbDev.Caps.Adf; + scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x + + (u_long)dev->usbDev.Normal.lLeft; + scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y + + (u_long)dev->usbDev.Normal.lUp; + } + + if( scan->sParam.bSource == SOURCE_ADF ) { + + if( scan->dwFlag & SCANDEF_ContinuousScan ) + dev->usbDev.fLastScanIsAdf = SANE_TRUE; + else + dev->usbDev.fLastScanIsAdf = SANE_FALSE; + } + + return 0; +} + +/** + */ +static int +usbDev_stopScan( Plustek_Device *dev ) +{ + DBG( _DBG_INFO, "usbDev_stopScan()\n" ); + + /* in cancel-mode we first stop the motor */ + usb_ScanEnd( dev ); + + dev->scanning.dwFlag = 0; + + if( NULL != dev->scanning.pScanBuffer ) { + + free( dev->scanning.pScanBuffer ); + dev->scanning.pScanBuffer = NULL; + usb_StartLampTimer( dev ); + } + return 0; +} + +/** + */ +static int +usbDev_startScan( Plustek_Device *dev ) +{ + ScanDef *scan = &dev->scanning; + DBG( _DBG_INFO, "usbDev_startScan()\n" ); + +/* HEINER: Preview currently not working correctly */ +#if 0 + if( scan->dwFlag & SCANDEF_QualityScan ) + dev->usbDev.a_bRegs[0x0a] = 0; + else + dev->usbDev.a_bRegs[0x0a] = 1; +#endif + dev->usbDev.a_bRegs[0x0a] = 0; + + if((scan->dwFlag & SCANDEF_Adf) && (scan->dwFlag & SCANDEF_ContinuousScan)) { + scan->fCalibrated = SANE_TRUE; + } else { + scan->fCalibrated = SANE_FALSE; + } + + scan->sParam.PhyDpi.x = usb_SetAsicDpiX(dev,scan->sParam.UserDpi.x); + scan->sParam.PhyDpi.y = usb_SetAsicDpiY(dev,scan->sParam.UserDpi.y); + + /* Allocate shading/scan buffer */ + scan->pScanBuffer = (u_long*)malloc( _SCANBUF_SIZE ); + + if( scan->pScanBuffer == NULL ) + return _E_ALLOC; + + scan->dwFlag |= SCANFLAG_StartScan; + + /* some devices (esp. BearPaw) do need a lamp switch off before + * switching it on again. Otherwise it might happen that the lamp + * remains off + */ + if(dev->usbDev.Caps.workaroundFlag & _WAF_LOFF_ON_START) { + if (usb_GetLampStatus(dev)) + usb_LampOn( dev, SANE_FALSE, SANE_TRUE ); + } + + usb_LampOn( dev, SANE_TRUE, SANE_TRUE ); + + m_fStart = m_fFirst = SANE_TRUE; + m_fAutoPark = (scan->dwFlag&SCANFLAG_StillModule)?SANE_FALSE:SANE_TRUE; + + if( usb_IsSheetFedDevice(dev)) + if(usb_InCalibrationMode(dev)) + m_fAutoPark = SANE_FALSE; + + usb_StopLampTimer( dev ); + return 0; +} + +/** + * do the reading stuff here... + * first we perform the calibration step, and then we read the image + * line for line + */ +static int +usbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf ) +{ + int result; + SANE_Bool use_alt_cal = SANE_FALSE; + ScanDef *scan = &dev->scanning; + DCapsDef *scaps = &dev->usbDev.Caps; + HWDef *hw = &dev->usbDev.HwSetting; + + DBG( _DBG_INFO, "usbDev_PrepareScan()\n" ); + + /* check the current position of the sensor and move it back + * to it's home position if necessary... + */ + if( !usb_IsSheetFedDevice(dev)) + usb_SensorStatus( dev ); + + /* CIS devices need special handling... */ + if( usb_IsCISDevice(dev)) { + use_alt_cal = SANE_TRUE; + + } else { + + if( dev->adj.altCalibrate ) + use_alt_cal = SANE_TRUE; + } + + /* for the skip functionality use the "old" calibration functions */ + if( dev->usbDev.Caps.workaroundFlag & _WAF_BYPASS_CALIBRATION ) { + use_alt_cal = SANE_FALSE; + } + + if( use_alt_cal ) { + result = cano_DoCalibration( dev ); + } else { + result = usb_DoCalibration( dev ); + } + + if( SANE_TRUE != result ) { + DBG( _DBG_ERROR, "calibration failed!!!\n" ); + return _E_ABORT; + } + + if( dev->adj.cacheCalData ) + usb_SaveCalData( dev ); + + DBG( _DBG_INFO, "calibration done.\n" ); + if( usb_InCalibrationMode(dev)) + return 0; + + if( !(scan->dwFlag & SCANFLAG_Scanning)) { + + usleep( 10 * 1000 ); + + /* need to preset that here, as we need it during parameter setting + */ + scan->bLinesToSkip = (u_char)(scan->sParam.PhyDpi.y / 50); + + scan->dwLinesDiscard = 0; + if( scan->sParam.bChannels == 3 ) { + scan->dwLinesDiscard = (u_long)scaps->bSensorDistance * + scan->sParam.PhyDpi.y / scaps->OpticDpi.y; + scan->dwLinesDiscard <<= 1; + } + + if( !usb_SetScanParameters( dev, &scan->sParam )) { + DBG( _DBG_ERROR, "Setting Scan Parameters failed!\n" ); + return 0; + } + + /* if we bypass the calibration step, we wait on lamp warmup here... + */ + if( scaps->workaroundFlag & _WAF_BYPASS_CALIBRATION ) { + if( !usb_Wait4Warmup( dev )) { + DBG( _DBG_INFO, "usbDev_Prepare() - Cancel detected...\n" ); + return 0; + } + } + + scan->pbScanBufBegin = (u_char*)scan->pScanBuffer; + + if((dev->caps.dwFlag & SFLAG_ADF) && (scaps->OpticDpi.x == 600)) + scan->dwLinesScanBuf = 8; + else + scan->dwLinesScanBuf = 32; + + scan->dwBytesScanBuf = scan->dwLinesScanBuf * + scan->sParam.Size.dwPhyBytes; + + scan->dwNumberOfScanBufs = _SCANBUF_SIZE / scan->dwBytesScanBuf; + scan->dwLinesPerScanBufs = scan->dwNumberOfScanBufs * + scan->dwLinesScanBuf; + scan->pbScanBufEnd = scan->pbScanBufBegin + + scan->dwLinesPerScanBufs * + scan->sParam.Size.dwPhyBytes; + scan->dwRedShift = 0; + scan->dwBlueShift = 0; + scan->dwGreenShift = 0; + + /* CCD scanner */ + if( scan->sParam.bChannels == 3 ) { + + scan->dwLinesDiscard = (u_long)scaps->bSensorDistance * + scan->sParam.PhyDpi.y / scaps->OpticDpi.y; + + switch( scaps->bSensorOrder ) { + + case SENSORORDER_rgb: + scan->Red.pb = scan->pbScanBufBegin; + scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes; + scan->Blue.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes * 2UL; + break; + + case SENSORORDER_rbg: + scan->Red.pb = scan->pbScanBufBegin; + scan->Blue.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes; + scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes * 2UL; + break; + + case SENSORORDER_gbr: + scan->Green.pb = scan->pbScanBufBegin; + scan->Blue.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes; + scan->Red.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes * 2UL; + break; + + case SENSORORDER_grb: + scan->Green.pb = scan->pbScanBufBegin; + scan->Red.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes; + scan->Blue.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes * 2UL; + break; + + case SENSORORDER_brg: + scan->Blue.pb = scan->pbScanBufBegin; + scan->Red.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes; + scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes * 2UL; + break; + + case SENSORORDER_bgr: + scan->Blue.pb = scan->pbScanBufBegin; + scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes; + scan->Red.pb = scan->pbScanBufBegin + scan->dwLinesDiscard * + scan->sParam.Size.dwPhyBytes * 2UL; + } + + /* double it for last channel */ + scan->dwLinesDiscard <<= 1; + scan->dwGreenShift = (7UL+scan->sParam.bBitDepth) >> 3; + scan->Green.pb += scan->dwGreenShift; + scan->Blue.pb += (scan->dwGreenShift * 2); + + if( scan->dwFlag & SCANFLAG_bgr) { + + u_char *pb = scan->Blue.pb; + + scan->Blue.pb = scan->Red.pb; + scan->Red.pb = pb; + scan->dwBlueShift = 0; + scan->dwRedShift = scan->dwGreenShift << 1; + } else { + scan->dwRedShift = 0; + scan->dwBlueShift = scan->dwGreenShift << 1; + } + + } else { + + /* CIS section */ + + /* this might be a simple gray operation or AFE 1 channel op */ + scan->dwLinesDiscard = 0; + scan->Green.pb = scan->pbScanBufBegin; + + if(( scan->sParam.bDataType == SCANDATATYPE_Color ) && + ( hw->bReg_0x26 & _ONE_CH_COLOR )) { + + u_char so; + u_long len = scan->sParam.Size.dwPhyBytes / 3; + + so = scaps->bSensorOrder; + if (_WAF_RESET_SO_TO_RGB & scaps->workaroundFlag) { + if (scaps->bPCB != 0) { + if (scan->sParam.PhyDpi.x > scaps->bPCB) { + so = SENSORORDER_rgb; + DBG(_DBG_INFO, "* Resetting sensororder to RGB\n"); + } + } + } + + switch( so ) { + + case SENSORORDER_rgb: + scan->Red.pb = scan->pbScanBufBegin; + scan->Green.pb = scan->pbScanBufBegin + len; + scan->Blue.pb = scan->pbScanBufBegin + len * 2UL; + break; + + case SENSORORDER_gbr: + scan->Green.pb = scan->pbScanBufBegin; + scan->Blue.pb = scan->pbScanBufBegin + len; + scan->Red.pb = scan->pbScanBufBegin + len * 2UL; + break; + default: + DBG( _DBG_ERROR, "CIS: This bSensorOrder " + "is not defined\n" ); + return _E_INTERNAL; + } + } + } + + /* set a funtion to process the RAW data... */ + usb_GetImageProc( dev ); + + if( scan->sParam.bSource == SOURCE_ADF ) + scan->dwFlag |= SCANFLAG_StillModule; + + DBG( _DBG_INFO, "* scan->dwFlag=0x%08lx\n", scan->dwFlag ); + + if( !usb_ScanBegin( dev, + (scan->dwFlag&SCANFLAG_StillModule) ? SANE_FALSE:SANE_TRUE)) { + + return _E_INTERNAL; + } + + scan->dwFlag |= SCANFLAG_Scanning; + + if( scan->sParam.UserDpi.y != scan->sParam.PhyDpi.y ) { + + if( scan->sParam.UserDpi.y < scan->sParam.PhyDpi.y ) { + + scan->wSumY = scan->sParam.PhyDpi.y - scan->sParam.UserDpi.y; + scan->dwFlag |= SCANFLAG_SampleY; + DBG( _DBG_INFO, "SampleY Flag set (%u != %u, wSumY=%u)\n", + scan->sParam.UserDpi.y, scan->sParam.PhyDpi.y, scan->wSumY ); + } + } + } + + dumpPicInit( &scan->sParam, "plustek-pic.raw" ); + + /* here the NT driver uses an extra reading thread... + * as the SANE stuff already forked the driver to read data, I think + * we should only read data by using a function... + */ + scan->dwLinesUser = scan->sParam.Size.dwLines; + if( !scan->dwLinesUser ) + return _E_BUFFER_TOO_SMALL; + + if( scan->sParam.Size.dwLines < scan->dwLinesUser ) + scan->dwLinesUser = scan->sParam.Size.dwLines; + + scan->sParam.Size.dwLines -= scan->dwLinesUser; + if( scan->dwFlag & SCANFLAG_BottomUp ) + scan->UserBuf.pb = buf + (scan->dwLinesUser - 1) * scan->dwBytesLine; + else + scan->UserBuf.pb = buf; + + DBG(_DBG_INFO,"Reading the data now!\n" ); + DBG(_DBG_INFO,"PhyDpi.x = %u\n", scan->sParam.PhyDpi.x ); + DBG(_DBG_INFO,"PhyDpi.y = %u\n", scan->sParam.PhyDpi.y ); + DBG(_DBG_INFO,"UserDpi.x = %u\n", scan->sParam.UserDpi.x ); + DBG(_DBG_INFO,"UserDpi.y = %u\n", scan->sParam.UserDpi.y ); + DBG(_DBG_INFO,"NumberOfScanBufs = %lu\n",scan->dwNumberOfScanBufs); + DBG(_DBG_INFO,"LinesPerScanBufs = %lu\n",scan->dwLinesPerScanBufs); + DBG(_DBG_INFO,"dwPhyBytes = %lu\n",scan->sParam.Size.dwPhyBytes); + DBG(_DBG_INFO,"dwPhyPixels = %lu\n",scan->sParam.Size.dwPhyPixels); + DBG(_DBG_INFO,"dwTotalBytes = %lu\n",scan->sParam.Size.dwTotalBytes); + DBG(_DBG_INFO,"dwPixels = %lu\n",scan->sParam.Size.dwPixels); + DBG(_DBG_INFO,"dwBytes = %lu\n",scan->sParam.Size.dwBytes); + DBG(_DBG_INFO,"dwValidPixels = %lu\n",scan->sParam.Size.dwValidPixels); + DBG(_DBG_INFO,"dwBytesScanBuf = %lu\n",scan->dwBytesScanBuf ); + DBG(_DBG_INFO,"dwLinesDiscard = %lu\n",scan->dwLinesDiscard ); + DBG(_DBG_INFO,"dwLinesToSkip = %u\n", scan->bLinesToSkip ); + DBG(_DBG_INFO,"dwLinesUser = %lu\n",scan->dwLinesUser ); + DBG(_DBG_INFO,"dwBytesLine = %lu\n",scan->dwBytesLine ); + + scan->pbGetDataBuf = scan->pbScanBufBegin; + + scan->dwLinesToProcess = usb_ReadData( dev ); + if( 0 == scan->dwLinesToProcess ) + return _E_DATAREAD; + + return 0; +} + +/** as the name says, read one line... + */ +static int +usbDev_ReadLine( Plustek_Device *dev ) +{ + int wrap; + u_long cur; + ScanDef *scan = &dev->scanning; + HWDef *hw = &dev->usbDev.HwSetting; + + cur = scan->dwLinesUser; + + /* we stay within this sample loop until one line has been processed for + * the user... + */ + while( cur == scan->dwLinesUser ) { + + if( usb_IsEscPressed()) { + DBG( _DBG_INFO, "readLine() - Cancel detected...\n" ); + return _E_ABORT; + } + + if( !(scan->dwFlag & SCANFLAG_SampleY)) { + + scan->pfnProcess( dev ); + + /* Adjust user buffer pointer */ + scan->UserBuf.pb += scan->lBufAdjust; + scan->dwLinesUser--; + + } else { + + scan->wSumY += scan->sParam.UserDpi.y; + + if( scan->wSumY >= scan->sParam.PhyDpi.y ) { + scan->wSumY -= scan->sParam.PhyDpi.y; + + scan->pfnProcess( dev ); + + /* Adjust user buffer pointer */ + scan->UserBuf.pb += scan->lBufAdjust; + scan->dwLinesUser--; + } + } + + /* Adjust get buffer pointers */ + wrap = 0; + + if( scan->sParam.bDataType == SCANDATATYPE_Color ) { + + scan->Red.pb += scan->sParam.Size.dwPhyBytes; + if( scan->Red.pb >= scan->pbScanBufEnd ) { + scan->Red.pb = scan->pbScanBufBegin + scan->dwRedShift; + wrap = 1; + } + + scan->Green.pb += scan->sParam.Size.dwPhyBytes; + if( scan->Green.pb >= scan->pbScanBufEnd ) { + scan->Green.pb = scan->pbScanBufBegin + scan->dwGreenShift; + wrap = 1; + } + + scan->Blue.pb += scan->sParam.Size.dwPhyBytes; + if( scan->Blue.pb >= scan->pbScanBufEnd ) { + scan->Blue.pb = scan->pbScanBufBegin + scan->dwBlueShift; + wrap = 1; + } + } else { + scan->Green.pb += scan->sParam.Size.dwPhyBytes; + if( scan->Green.pb >= scan->pbScanBufEnd ) + scan->Green.pb = scan->pbScanBufBegin + scan->dwGreenShift; + } + + /* on any wrap-around of the get pointers in one channel mode + * we have to reset them + */ + if( wrap ) { + + u_long len = scan->sParam.Size.dwPhyBytes; + + if( hw->bReg_0x26 & _ONE_CH_COLOR ) { + + if(scan->sParam.bDataType == SCANDATATYPE_Color) { + len /= 3; + } + scan->Red.pb = scan->pbScanBufBegin; + scan->Green.pb = scan->pbScanBufBegin + len; + scan->Blue.pb = scan->pbScanBufBegin + len * 2UL; + } + } + + /* line processed, check if we have to get more... + */ + scan->dwLinesToProcess--; + + if( 0 == scan->dwLinesToProcess ) { + + scan->dwLinesToProcess = usb_ReadData( dev ); + if( 0 == scan->dwLinesToProcess ) { + + if( usb_IsEscPressed()) + return _E_ABORT; + } + } + } + return 0; +} + +/* END PLUSTEK-USB.C ........................................................*/ |