1141cc406Sopenharmony_ci/*............................................................................. 2141cc406Sopenharmony_ci * Project : SANE library for Plustek flatbed scanners. 3141cc406Sopenharmony_ci *............................................................................. 4141cc406Sopenharmony_ci */ 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci/** @file plustek-usbio.c 7141cc406Sopenharmony_ci * @brief Some I/O stuff. 8141cc406Sopenharmony_ci * 9141cc406Sopenharmony_ci * Based on sources acquired from Plustek Inc.<br> 10141cc406Sopenharmony_ci * Copyright (C) 2001-2007 Gerhard Jaeger <gerhard@gjaeger.de> 11141cc406Sopenharmony_ci * 12141cc406Sopenharmony_ci * History: 13141cc406Sopenharmony_ci * History: 14141cc406Sopenharmony_ci * - 0.40 - starting version of the USB support 15141cc406Sopenharmony_ci * - 0.41 - moved some functions to a sane library (sanei_lm983x.c) 16141cc406Sopenharmony_ci * - 0.42 - no changes 17141cc406Sopenharmony_ci * - 0.43 - no changes 18141cc406Sopenharmony_ci * - 0.44 - added dump registers and dumpPic functions 19141cc406Sopenharmony_ci * - beautified output of ASIC detection 20141cc406Sopenharmony_ci * - 0.45 - fixed dumpRegs 21141cc406Sopenharmony_ci * - added dimension stuff to dumpPic 22141cc406Sopenharmony_ci * - 0.46 - disabled reset prior to the detection of Merlin 23141cc406Sopenharmony_ci * - 0.47 - no changes 24141cc406Sopenharmony_ci * - 0.48 - cleanup 25141cc406Sopenharmony_ci * - 0.49 - no changes 26141cc406Sopenharmony_ci * - 0.50 - usbio_DetectLM983x() now returns error if register 27141cc406Sopenharmony_ci * could not be red 28141cc406Sopenharmony_ci * - usbio_ResetLM983x() checks for reg7 value before writing 29141cc406Sopenharmony_ci * - 0.51 - allow dumpRegs to be called without valid fd 30141cc406Sopenharmony_ci * - 0.52 - no changes 31141cc406Sopenharmony_ci * . 32141cc406Sopenharmony_ci * <hr> 33141cc406Sopenharmony_ci * This file is part of the SANE package. 34141cc406Sopenharmony_ci * 35141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or 36141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as 37141cc406Sopenharmony_ci * published by the Free Software Foundation; either version 2 of the 38141cc406Sopenharmony_ci * License, or (at your option) any later version. 39141cc406Sopenharmony_ci * 40141cc406Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 41141cc406Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 42141cc406Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 43141cc406Sopenharmony_ci * General Public License for more details. 44141cc406Sopenharmony_ci * 45141cc406Sopenharmony_ci * You should have received a copy of the GNU General Public License 46141cc406Sopenharmony_ci * along with this program. If not, see <https://www.gnu.org/licenses/>. 47141cc406Sopenharmony_ci * 48141cc406Sopenharmony_ci * As a special exception, the authors of SANE give permission for 49141cc406Sopenharmony_ci * additional uses of the libraries contained in this release of SANE. 50141cc406Sopenharmony_ci * 51141cc406Sopenharmony_ci * The exception is that, if you link a SANE library with other files 52141cc406Sopenharmony_ci * to produce an executable, this does not by itself cause the 53141cc406Sopenharmony_ci * resulting executable to be covered by the GNU General Public 54141cc406Sopenharmony_ci * License. Your use of that executable is in no way restricted on 55141cc406Sopenharmony_ci * account of linking the SANE library code into it. 56141cc406Sopenharmony_ci * 57141cc406Sopenharmony_ci * This exception does not, however, invalidate any other reasons why 58141cc406Sopenharmony_ci * the executable file might be covered by the GNU General Public 59141cc406Sopenharmony_ci * License. 60141cc406Sopenharmony_ci * 61141cc406Sopenharmony_ci * If you submit changes to SANE to the maintainers to be included in 62141cc406Sopenharmony_ci * a subsequent release, you agree by submitting the changes that 63141cc406Sopenharmony_ci * those changes may be distributed with this exception intact. 64141cc406Sopenharmony_ci * 65141cc406Sopenharmony_ci * If you write modifications of your own for SANE, it is your choice 66141cc406Sopenharmony_ci * whether to permit this exception to apply to your modifications. 67141cc406Sopenharmony_ci * If you do not wish that, delete this exception notice. 68141cc406Sopenharmony_ci * <hr> 69141cc406Sopenharmony_ci */ 70141cc406Sopenharmony_ci 71141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 72141cc406Sopenharmony_ci#include "../include/sane/sanei_lm983x.h" 73141cc406Sopenharmony_ci 74141cc406Sopenharmony_ci#define _UIO(func) \ 75141cc406Sopenharmony_ci { \ 76141cc406Sopenharmony_ci SANE_Status status; \ 77141cc406Sopenharmony_ci status = func; \ 78141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { \ 79141cc406Sopenharmony_ci DBG( _DBG_ERROR, "UIO error\n" ); \ 80141cc406Sopenharmony_ci return SANE_FALSE; \ 81141cc406Sopenharmony_ci } \ 82141cc406Sopenharmony_ci } 83141cc406Sopenharmony_ci 84141cc406Sopenharmony_ci#define usbio_ReadReg(fd, reg, value) \ 85141cc406Sopenharmony_ci sanei_lm983x_read (fd, reg, value, 1, 0) 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_citypedef struct { 88141cc406Sopenharmony_ci 89141cc406Sopenharmony_ci u_char depth; 90141cc406Sopenharmony_ci u_long x; 91141cc406Sopenharmony_ci u_long y; 92141cc406Sopenharmony_ci} PicDef, *pPicDef; 93141cc406Sopenharmony_ci 94141cc406Sopenharmony_cistatic PicDef dPix; 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_ci/** 97141cc406Sopenharmony_ci */ 98141cc406Sopenharmony_cistatic void dumpPic( char* name, SANE_Byte *buffer, u_long len, int is_gray ) 99141cc406Sopenharmony_ci{ 100141cc406Sopenharmony_ci u_short type; 101141cc406Sopenharmony_ci FILE *fp; 102141cc406Sopenharmony_ci 103141cc406Sopenharmony_ci if( DBG_LEVEL < _DBG_DPIC ) 104141cc406Sopenharmony_ci return; 105141cc406Sopenharmony_ci 106141cc406Sopenharmony_ci if( NULL == buffer ) { 107141cc406Sopenharmony_ci 108141cc406Sopenharmony_ci DBG( _DBG_DPIC, "Creating file '%s'\n", name ); 109141cc406Sopenharmony_ci 110141cc406Sopenharmony_ci fp = fopen( name, "w+b" ); 111141cc406Sopenharmony_ci 112141cc406Sopenharmony_ci if( NULL != fp ) { 113141cc406Sopenharmony_ci 114141cc406Sopenharmony_ci if( 0 != dPix.x ) { 115141cc406Sopenharmony_ci 116141cc406Sopenharmony_ci if (is_gray) 117141cc406Sopenharmony_ci type = 5; 118141cc406Sopenharmony_ci else 119141cc406Sopenharmony_ci type = 6; 120141cc406Sopenharmony_ci 121141cc406Sopenharmony_ci DBG( _DBG_DPIC, "> X=%lu, Y=%lu, depth=%u\n", 122141cc406Sopenharmony_ci dPix.x, dPix.y, dPix.depth ); 123141cc406Sopenharmony_ci if( dPix.depth > 8 ) 124141cc406Sopenharmony_ci fprintf( fp, "P%u\n%lu %lu\n65535\n", type, dPix.x, dPix.y); 125141cc406Sopenharmony_ci else 126141cc406Sopenharmony_ci fprintf( fp, "P%u\n%lu %lu\n255\n", type, dPix.x, dPix.y); 127141cc406Sopenharmony_ci } 128141cc406Sopenharmony_ci } 129141cc406Sopenharmony_ci } else { 130141cc406Sopenharmony_ci fp = fopen( name, "a+b" ); 131141cc406Sopenharmony_ci } 132141cc406Sopenharmony_ci 133141cc406Sopenharmony_ci if( NULL == fp ) { 134141cc406Sopenharmony_ci DBG( _DBG_DPIC, "Can not open file '%s'\n", name ); 135141cc406Sopenharmony_ci return; 136141cc406Sopenharmony_ci } 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_ci fwrite( buffer, 1, len, fp ); 139141cc406Sopenharmony_ci fclose( fp ); 140141cc406Sopenharmony_ci} 141141cc406Sopenharmony_ci 142141cc406Sopenharmony_ci/** 143141cc406Sopenharmony_ci */ 144141cc406Sopenharmony_cistatic void dumpPicInit( ScanParam *sd, char* name ) 145141cc406Sopenharmony_ci{ 146141cc406Sopenharmony_ci dPix.x = sd->Size.dwPhyBytes; 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_ci if( sd->bDataType == SCANDATATYPE_Color ) 149141cc406Sopenharmony_ci dPix.x /= 3; 150141cc406Sopenharmony_ci 151141cc406Sopenharmony_ci if( sd->bBitDepth > 8 ) 152141cc406Sopenharmony_ci dPix.x /= 2; 153141cc406Sopenharmony_ci 154141cc406Sopenharmony_ci dPix.y = sd->Size.dwLines; 155141cc406Sopenharmony_ci dPix.depth = sd->bBitDepth; 156141cc406Sopenharmony_ci 157141cc406Sopenharmony_ci if( sd->bDataType == SCANDATATYPE_Color ) 158141cc406Sopenharmony_ci dumpPic(name, NULL, 0, 0); 159141cc406Sopenharmony_ci else 160141cc406Sopenharmony_ci dumpPic(name, NULL, 0, 1); 161141cc406Sopenharmony_ci} 162141cc406Sopenharmony_ci 163141cc406Sopenharmony_ci/** 164141cc406Sopenharmony_ci * dump the LM983x registers 165141cc406Sopenharmony_ci */ 166141cc406Sopenharmony_cistatic void dumpregs( int fd, SANE_Byte *cmp ) 167141cc406Sopenharmony_ci{ 168141cc406Sopenharmony_ci char buf[256], b2[10]; 169141cc406Sopenharmony_ci SANE_Byte regs[0x80]; 170141cc406Sopenharmony_ci int i; 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_ci if( DBG_LEVEL < _DBG_DREGS ) 173141cc406Sopenharmony_ci return; 174141cc406Sopenharmony_ci 175141cc406Sopenharmony_ci buf[0] = '\0'; 176141cc406Sopenharmony_ci 177141cc406Sopenharmony_ci if( fd >= 0 ) { 178141cc406Sopenharmony_ci usbio_ReadReg(fd, 0x01, ®s[0x01]); 179141cc406Sopenharmony_ci usbio_ReadReg(fd, 0x02, ®s[0x02]); 180141cc406Sopenharmony_ci usbio_ReadReg(fd, 0x03, ®s[0x03]); 181141cc406Sopenharmony_ci usbio_ReadReg(fd, 0x04, ®s[0x04]); 182141cc406Sopenharmony_ci usbio_ReadReg(fd, 0x07, ®s[0x07]); 183141cc406Sopenharmony_ci 184141cc406Sopenharmony_ci sanei_lm983x_read( fd, 0x08, ®s[0x8], 0x80-0x8, SANE_TRUE ); 185141cc406Sopenharmony_ci 186141cc406Sopenharmony_ci for( i = 0x0; i < 0x80; i++ ) { 187141cc406Sopenharmony_ci 188141cc406Sopenharmony_ci if((i%16) ==0 ) { 189141cc406Sopenharmony_ci 190141cc406Sopenharmony_ci if( buf[0] ) 191141cc406Sopenharmony_ci DBG( _DBG_DREGS, "%s\n", buf ); 192141cc406Sopenharmony_ci sprintf( buf, "0x%02x:", i ); 193141cc406Sopenharmony_ci } 194141cc406Sopenharmony_ci 195141cc406Sopenharmony_ci if((i%8)==0) 196141cc406Sopenharmony_ci strcat( buf, " "); 197141cc406Sopenharmony_ci 198141cc406Sopenharmony_ci /* the dataport read returns with "0 Bytes read", of course. */ 199141cc406Sopenharmony_ci if((i == 0) || (i == 5) || (i == 6)) 200141cc406Sopenharmony_ci strcat( buf, "XX "); 201141cc406Sopenharmony_ci else { 202141cc406Sopenharmony_ci 203141cc406Sopenharmony_ci sprintf( b2, "%02x ", regs[i]); 204141cc406Sopenharmony_ci strcat( buf, b2 ); 205141cc406Sopenharmony_ci } 206141cc406Sopenharmony_ci } 207141cc406Sopenharmony_ci DBG( _DBG_DREGS, "%s\n", buf ); 208141cc406Sopenharmony_ci } 209141cc406Sopenharmony_ci 210141cc406Sopenharmony_ci if( cmp ) { 211141cc406Sopenharmony_ci 212141cc406Sopenharmony_ci buf[0] = '\0'; 213141cc406Sopenharmony_ci 214141cc406Sopenharmony_ci DBG( _DBG_DREGS, "Internal setting:\n" ); 215141cc406Sopenharmony_ci for( i = 0x0; i < 0x80; i++ ) { 216141cc406Sopenharmony_ci 217141cc406Sopenharmony_ci if((i%16) ==0 ) { 218141cc406Sopenharmony_ci 219141cc406Sopenharmony_ci if( buf[0] ) 220141cc406Sopenharmony_ci DBG( _DBG_DREGS, "%s\n", buf ); 221141cc406Sopenharmony_ci sprintf( buf, "0x%02x:", i ); 222141cc406Sopenharmony_ci } 223141cc406Sopenharmony_ci 224141cc406Sopenharmony_ci if((i%8)==0) 225141cc406Sopenharmony_ci strcat( buf, " "); 226141cc406Sopenharmony_ci 227141cc406Sopenharmony_ci if((i == 0) || (i == 5) || (i == 6)) 228141cc406Sopenharmony_ci strcat( buf, "XX "); 229141cc406Sopenharmony_ci else { 230141cc406Sopenharmony_ci sprintf( b2, "%02x ", cmp[i]); 231141cc406Sopenharmony_ci strcat( buf, b2 ); 232141cc406Sopenharmony_ci } 233141cc406Sopenharmony_ci } 234141cc406Sopenharmony_ci DBG( _DBG_DREGS, "%s\n", buf ); 235141cc406Sopenharmony_ci } 236141cc406Sopenharmony_ci} 237141cc406Sopenharmony_ci 238141cc406Sopenharmony_ci/** 239141cc406Sopenharmony_ci * function to read the contents of a LM983x register and regarding some 240141cc406Sopenharmony_ci * extra stuff, like flushing register 2 when writing register 0x58, etc 241141cc406Sopenharmony_ci * 242141cc406Sopenharmony_ci * @param handle - 243141cc406Sopenharmony_ci * @param reg - 244141cc406Sopenharmony_ci * @param value - 245141cc406Sopenharmony_ci * @return 246141cc406Sopenharmony_ci */ 247141cc406Sopenharmony_cistatic SANE_Bool usbio_WriteReg( SANE_Int handle, 248141cc406Sopenharmony_ci SANE_Byte reg, SANE_Byte value ) 249141cc406Sopenharmony_ci{ 250141cc406Sopenharmony_ci int i; 251141cc406Sopenharmony_ci SANE_Byte data; 252141cc406Sopenharmony_ci 253141cc406Sopenharmony_ci /* retry loop... */ 254141cc406Sopenharmony_ci for( i = 0; i < 100; i++ ) { 255141cc406Sopenharmony_ci 256141cc406Sopenharmony_ci sanei_lm983x_write_byte( handle, reg, value ); 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_ci /* Flush register 0x02 when register 0x58 is written */ 259141cc406Sopenharmony_ci if( 0x58 == reg ) { 260141cc406Sopenharmony_ci _UIO( usbio_ReadReg( handle, 2, &data )); 261141cc406Sopenharmony_ci _UIO( usbio_ReadReg( handle, 2, &data )); 262141cc406Sopenharmony_ci } 263141cc406Sopenharmony_ci 264141cc406Sopenharmony_ci if( reg != 7 ) 265141cc406Sopenharmony_ci return SANE_TRUE; 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci /* verify register 7 */ 268141cc406Sopenharmony_ci _UIO( usbio_ReadReg( handle, 7, &data )); 269141cc406Sopenharmony_ci if( data == value ) { 270141cc406Sopenharmony_ci return SANE_TRUE; 271141cc406Sopenharmony_ci } 272141cc406Sopenharmony_ci } 273141cc406Sopenharmony_ci 274141cc406Sopenharmony_ci return SANE_FALSE; 275141cc406Sopenharmony_ci} 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci/** try and read register 0x69 from a LM983x to find out which version we have. 278141cc406Sopenharmony_ci */ 279141cc406Sopenharmony_cistatic SANE_Status usbio_DetectLM983x( SANE_Int fd, SANE_Byte *version ) 280141cc406Sopenharmony_ci{ 281141cc406Sopenharmony_ci char buf[256]; 282141cc406Sopenharmony_ci SANE_Byte value; 283141cc406Sopenharmony_ci SANE_Status res; 284141cc406Sopenharmony_ci 285141cc406Sopenharmony_ci DBG( _DBG_INFO, "usbio_DetectLM983x\n"); 286141cc406Sopenharmony_ci 287141cc406Sopenharmony_ci res = usbio_ReadReg(fd, 0x69, &value); 288141cc406Sopenharmony_ci if( res != SANE_STATUS_GOOD ) { 289141cc406Sopenharmony_ci DBG( _DBG_ERROR, " * could not read version register!\n"); 290141cc406Sopenharmony_ci return res; 291141cc406Sopenharmony_ci } 292141cc406Sopenharmony_ci 293141cc406Sopenharmony_ci value &= 7; 294141cc406Sopenharmony_ci if (version) 295141cc406Sopenharmony_ci *version = value; 296141cc406Sopenharmony_ci 297141cc406Sopenharmony_ci res = SANE_STATUS_GOOD; 298141cc406Sopenharmony_ci 299141cc406Sopenharmony_ci sprintf( buf, "usbio_DetectLM983x: found " ); 300141cc406Sopenharmony_ci 301141cc406Sopenharmony_ci switch((SANE_Int)value ) { 302141cc406Sopenharmony_ci 303141cc406Sopenharmony_ci case 4: strcat( buf, "LM9832/3" ); break; 304141cc406Sopenharmony_ci case 3: strcat( buf, "LM9831" ); break; 305141cc406Sopenharmony_ci case 2: strcat( buf, "LM9830 --> unsupported!!!" ); 306141cc406Sopenharmony_ci res = SANE_STATUS_INVAL; 307141cc406Sopenharmony_ci break; 308141cc406Sopenharmony_ci default: DBG( _DBG_INFO, "Unknown chip v%d", value ); 309141cc406Sopenharmony_ci res = SANE_STATUS_INVAL; 310141cc406Sopenharmony_ci break; 311141cc406Sopenharmony_ci } 312141cc406Sopenharmony_ci 313141cc406Sopenharmony_ci DBG( _DBG_INFO, "%s\n", buf ); 314141cc406Sopenharmony_ci return res; 315141cc406Sopenharmony_ci} 316141cc406Sopenharmony_ci 317141cc406Sopenharmony_ci/** well, this is more or less a reset function, for LM9831 based devices 318141cc406Sopenharmony_ci * we issue a real reset command, while for LM9832/3 based devices, checking 319141cc406Sopenharmony_ci * and resetting register 7 will be enough... 320141cc406Sopenharmony_ci */ 321141cc406Sopenharmony_cistatic SANE_Status usbio_ResetLM983x( Plustek_Device *dev ) 322141cc406Sopenharmony_ci{ 323141cc406Sopenharmony_ci SANE_Byte value; 324141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 325141cc406Sopenharmony_ci 326141cc406Sopenharmony_ci if( _LM9831 == hw->chip ) { 327141cc406Sopenharmony_ci 328141cc406Sopenharmony_ci DBG( _DBG_INFO," * resetting LM9831 device!\n"); 329141cc406Sopenharmony_ci _UIO( sanei_lm983x_write_byte( dev->fd, 0x07, 0)); 330141cc406Sopenharmony_ci _UIO( sanei_lm983x_write_byte( dev->fd, 0x07,0x20)); 331141cc406Sopenharmony_ci _UIO( sanei_lm983x_write_byte( dev->fd, 0x07, 0)); 332141cc406Sopenharmony_ci _UIO( usbio_ReadReg( dev->fd, 0x07, &value)); 333141cc406Sopenharmony_ci if (value != 0) { 334141cc406Sopenharmony_ci DBG( _DBG_ERROR, "usbio_ResetLM983x: reset was not " 335141cc406Sopenharmony_ci "successful, status=%d\n", value ); 336141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 337141cc406Sopenharmony_ci } 338141cc406Sopenharmony_ci 339141cc406Sopenharmony_ci } else { 340141cc406Sopenharmony_ci _UIO( usbio_ReadReg( dev->fd, 0x07, &value)); 341141cc406Sopenharmony_ci if (value != 0 ) { 342141cc406Sopenharmony_ci DBG( _DBG_INFO," * setting device to idle state!\n"); 343141cc406Sopenharmony_ci _UIO( sanei_lm983x_write_byte( dev->fd, 0x07, 0)); 344141cc406Sopenharmony_ci } 345141cc406Sopenharmony_ci } 346141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 347141cc406Sopenharmony_ci} 348141cc406Sopenharmony_ci 349141cc406Sopenharmony_ci/* END PLUSTEK-USBIO.C ......................................................*/ 350