diff options
Diffstat (limited to 'backend/u12-io.c')
-rw-r--r-- | backend/u12-io.c | 851 |
1 files changed, 851 insertions, 0 deletions
diff --git a/backend/u12-io.c b/backend/u12-io.c new file mode 100644 index 0000000..cd65b72 --- /dev/null +++ b/backend/u12-io.c @@ -0,0 +1,851 @@ +/** @file u12-io.c + * @brief The I/O functions to the U12 backend stuff. + * + * Copyright (c) 2003-2004 Gerhard Jaeger <gerhard@gjaeger.de> + * GeneSys Logic I/O stuff derived from canon630u-common.c which has + * been written by Nathan Rutman <nathan@gordian.com> + * + * History: + * - 0.01 - initial version + * - 0.02 - changed u12io_GetFifoLength() behaviour + * - added delays to reset function + * . + * <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> + */ + +/** Format: + * cacheLen[0] = ASIC-ID + * cacheLen[1] = SCANSTATE ? + * cacheLen[2] = REG-STATUS ? + * cacheLen[3] = ?? + * cacheLen[4] = FIFO-LEN (RED) HiByte LW + * cacheLen[5] = FIFO-LEN (RED) LoByte LW + * cacheLen[6] = FIFO-LEN (RED) LoByte HW + * cacheLen[7] = FIFO-LEN (GREEN) HiByte LW + * cacheLen[8] = FIFO-LEN (GREEN) LoByte LW + * cacheLen[9] = FIFO-LEN (GREEN) LoByte HW + * cacheLen[10] = FIFO-LEN (BLUE) HiByte LW + * cacheLen[11] = FIFO-LEN (BLUE) LoByte LW + * cacheLen[12] = FIFO-LEN (BLUE) LoByte HW + */ +static SANE_Byte cacheLen[13]; + +/** This function is used to detect a cancel condition, + * our ESC key is the SIGUSR1 signal. It is sent by the backend when the + * cancel button has been pressed + * + * @param - none + * @return the function returns SANE_TRUE if a cancel condition has been + * detected, if not, it returns SANE_FALSE + */ +static SANE_Bool u12io_IsEscPressed( void ) +{ + sigset_t sigs; + + sigpending( &sigs ); + if( sigismember( &sigs, SIGUSR1 )) { + DBG( _DBG_INFO, "SIGUSR1 is pending --> Cancel detected\n" ); + return SANE_TRUE; + } + + return SANE_FALSE; +} + +/** fall asleep for some micro-seconds... + */ +static void u12io_udelay( unsigned long usec ) +{ + struct timeval now, deadline; + + if( usec == 0 ) + return; + + gettimeofday( &deadline, NULL ); + deadline.tv_usec += usec; + deadline.tv_sec += deadline.tv_usec / 1000000; + deadline.tv_usec %= 1000000; + + do { + gettimeofday( &now, NULL ); + } while ((now.tv_sec < deadline.tv_sec) || + (now.tv_sec == deadline.tv_sec && now.tv_usec < deadline.tv_usec)); +} + +/** Initializes a timer. + * @param timer - pointer to the timer to start + * @param us - timeout value in micro-seconds + */ +static void u12io_StartTimer( TimerDef *timer , unsigned long us ) +{ + struct timeval start_time; + + gettimeofday( &start_time, NULL ); + *timer = start_time.tv_sec * 1e6 + start_time.tv_usec + us; +} + +/** Checks if a timer has been expired or not. + * @param timer - pointer to the timer to check + * @return Function returns SANE_TRUE when the timer has been expired, + * otherwise SANE_FALSE + */ +static SANE_Bool u12io_CheckTimer( TimerDef *timer ) +{ + struct timeval current_time; + + gettimeofday(¤t_time, NULL); + + if((current_time.tv_sec * 1e6 + current_time.tv_usec) > *timer ) + return SANE_TRUE; + + return SANE_FALSE; +} + +/* GL640 communication functions for Genesys Logic GL640USB + * USB-IEEE1284 parallel port bridge + */ + +/* Assign status and verify a good return code */ +#define CHK(A) {if( (status = A) != SANE_STATUS_GOOD ) { \ + DBG( _DBG_ERROR, "Failure on line of %s: %d\n", __FILE__, \ + __LINE__ ); return A; }} + +/** Register codes for the bridge. These are NOT the registers for the ASIC + * on the other side of the bridge. + */ +typedef enum +{ + GL640_BULK_SETUP = 0x82, + GL640_EPP_ADDR = 0x83, + GL640_EPP_DATA_READ = 0x84, + GL640_EPP_DATA_WRITE = 0x85, + GL640_SPP_STATUS = 0x86, + GL640_SPP_CONTROL = 0x87, + GL640_SPP_DATA = 0x88, + GL640_GPIO_OE = 0x89, + GL640_GPIO_READ = 0x8a, + GL640_GPIO_WRITE = 0x8b +} GL640_Request; + +/** for setting up bulk transfers */ +static SANE_Byte bulk_setup_data[] = { 0, 0x11, 0, 0, 0, 0, 0, 0 }; + +/** Write to the usb-parallel port bridge. + */ +static SANE_Status +gl640WriteControl(int fd, GL640_Request req, u_char * data, unsigned int size) +{ + SANE_Status status; + + status = sanei_usb_control_msg( fd, + /* rqttype */ USB_TYPE_VENDOR | + USB_RECIP_DEVICE | USB_DIR_OUT /*0x40 */ , + /* rqt */ (size > 1) ? 0x04 : 0x0C, + /* val */ (SANE_Int) req, + /* ind */ 0, + /* len */ size, + /* dat */ data); + + if( status != SANE_STATUS_GOOD ) { + DBG( _DBG_ERROR, "gl640WriteControl error\n"); + } + return status; +} + +/** Read from the usb-parallel port bridge. + */ +static SANE_Status +gl640ReadControl( int fd, GL640_Request req, u_char *data, unsigned int size ) +{ + SANE_Status status; + + status = sanei_usb_control_msg( fd, + /* rqttype */ USB_TYPE_VENDOR | + USB_RECIP_DEVICE | USB_DIR_IN /*0xc0 */ , + /* rqt */ (size > 1) ? 0x04 : 0x0C, + /* val */ (SANE_Int) req, + /* ind */ 0, + /* len */ size, + /* dat */ data); + + if( status != SANE_STATUS_GOOD ) { + DBG( _DBG_ERROR, "gl640ReadControl error\n"); + } + return status; +} + +/** Wrappers to write a single byte to the bridge */ +static inline SANE_Status +gl640WriteReq( int fd, GL640_Request req, u_char data ) +{ + return gl640WriteControl( fd, req, &data, 1); +} + +/** Wrappers to read a single byte from the bridge */ +static inline SANE_Status +gl640ReadReq( int fd, GL640_Request req, u_char *data ) +{ + return gl640ReadControl( fd, req, data, 1 ); +} + +/** Write USB bulk data + * setup is an apparently scanner-specific sequence: + * {(0=read, 1=write), 0x00, 0x00, 0x00, sizelo, sizehi, 0x00, 0x00} + * setup[1] = 0x11 --> data to register + * setup[1] = 0x01 --> data to scanner memory + */ +static SANE_Status +gl640WriteBulk( int fd, u_char *setup, u_char *data, size_t size ) +{ + SANE_Status status; + + setup[0] = 1; + setup[4] = (size) & 0xFF; + setup[5] = (size >> 8) & 0xFF; + setup[6] = 0; + + CHK (gl640WriteControl (fd, GL640_BULK_SETUP, setup, 8)); + + status = sanei_usb_write_bulk (fd, data, &size); + if( status != SANE_STATUS_GOOD ) { + DBG( _DBG_ERROR, "gl640WriteBulk error\n"); + } + return status; +} + +/** Read USB bulk data + * setup is an apparently scanner-specific sequence: + * {(0=read, 1=write), 0x00, 0x00, 0x00, sizelo, sizehi, 0x00, 0x00} + * setup[1] = 0x00 --> data from scanner memory + * setup[1] = 0x0c --> data from scanner fifo? + */ +static SANE_Status +gl640ReadBulk( int fd, u_char *setup, u_char *data, size_t size, int mod ) +{ + SANE_Byte *len_info; + size_t complete, current, toget; + SANE_Status status; + + setup[0] = 0; + setup[4] = (size) & 0xFF; + setup[5] = (size >> 8) & 0xFF; + setup[6] = mod; + + CHK (gl640WriteControl (fd, GL640_BULK_SETUP, setup, 8)); + + len_info = NULL; + toget = size; + if( mod ) { + toget *= mod; + len_info = data + toget; + toget += 13; + } + + for( complete = 0; complete < toget; ) { + + current = toget - complete; + status = sanei_usb_read_bulk( fd, data, ¤t ); + if( status != SANE_STATUS_GOOD ) { + DBG( _DBG_ERROR, "gl640ReadBulk error\n"); + break; + } + data += current; + complete += current; + } + if( len_info ) { + memcpy( cacheLen, len_info, 13 ); + } + return status; +} + +/* now the functions to access PP registers */ + +/** read the contents of the status register */ +static SANE_Byte +inb_status( int fd ) +{ + u_char data = 0xff; + + gl640ReadReq( fd, GL640_SPP_STATUS, &data ); + return data; +} + +/** write a byte to the SPP data port */ +static SANE_Status +outb_data( int fd, u_char data ) +{ + return gl640WriteReq( fd, GL640_SPP_DATA, data); +} + +/** write to the parport control register */ +static SANE_Status +outb_ctrl( int fd, u_char data ) +{ + return gl640WriteReq( fd, GL640_SPP_CONTROL, data); +} + +/************************* ASIC access stuff *********************************/ + +/** write a register number to the ASIC + */ +static void u12io_RegisterToScanner( U12_Device *dev, SANE_Byte reg ) +{ + if( dev->mode == _PP_MODE_EPP ) { + + gl640WriteReq( dev->fd, GL640_EPP_ADDR, reg ); + + } else { + + /* write register number to read from to SPP data-port + */ + outb_data( dev->fd, reg ); + + /* signal that to the ASIC */ + outb_ctrl( dev->fd, _CTRL_SIGNAL_REGWRITE ); + _DODELAY(20); + outb_ctrl( dev->fd, _CTRL_END_REGWRITE ); + } +} + +/** as the name says, we switch to SPP mode + */ +static void u12io_SwitchToSPPMode( U12_Device *dev ) +{ + dev->mode = _PP_MODE_SPP; + outb_ctrl( dev->fd, _CTRL_GENSIGNAL ); +} + +/** as the name says, we switch to SPP mode + */ +static void u12io_SwitchToEPPMode( U12_Device *dev ) +{ + u12io_RegisterToScanner( dev, REG_EPPENABLE ); + dev->mode = _PP_MODE_EPP; +} + +/** read data from SPP status port + */ +static SANE_Byte u12io_DataFromSPP( U12_Device *dev ) +{ + SANE_Byte data, tmp; + + /* read low nibble */ + tmp = inb_status( dev->fd ); + + outb_ctrl( dev->fd, (_CTRL_GENSIGNAL + _CTRL_STROBE)); + + /* read high nibble */ + data = inb_status( dev->fd ); + data &= 0xf0; + + /* combine with low nibble */ + data |= (tmp >> 4); + return data; +} + +/** Read the content of specific ASIC register + */ +static SANE_Byte u12io_DataFromRegister( U12_Device *dev, SANE_Byte reg ) +{ + SANE_Byte val; + + if( dev->mode == _PP_MODE_EPP ) { + gl640WriteReq( dev->fd, GL640_EPP_ADDR, reg ); + gl640ReadReq ( dev->fd, GL640_EPP_DATA_READ, &val ); + } else { + + u12io_RegisterToScanner( dev, reg ); + val = u12io_DataFromSPP( dev ); + } + return val; +} + +/** + */ +static void u12io_CloseScanPath( U12_Device *dev ) +{ + DBG( _DBG_INFO, "u12io_CloseScanPath()\n" ); +/* FIXME: Probaly not needed */ +#if 0 + u12io_RegisterToScanner( dev, 0xff ); +#endif + u12io_RegisterToScanner( dev, REG_SWITCHBUS ); + + dev->mode = _PP_MODE_SPP; +} + +/** try to connect to scanner + */ +static SANE_Bool u12io_OpenScanPath( U12_Device *dev ) +{ + u_char tmp; + + DBG( _DBG_INFO, "u12io_OpenScanPath()\n" ); + + u12io_SwitchToSPPMode( dev ); + + outb_data( dev->fd, _ID_TO_PRINTER ); + _DODELAY(20); + + outb_data( dev->fd, _ID1ST ); + _DODELAY(5); + + outb_data( dev->fd, _ID2ND ); + _DODELAY(5); + + outb_data( dev->fd, _ID3RD ); + _DODELAY(5); + + outb_data( dev->fd, _ID4TH ); + _DODELAY(5); + + tmp = u12io_DataFromRegister( dev, REG_ASICID ); + if( ASIC_ID == tmp ) { + u12io_SwitchToEPPMode( dev ); + return SANE_TRUE; + } + + DBG( _DBG_ERROR, "u12io_OpenScanPath() failed!\n" ); + return SANE_FALSE; +} + +/** Write data to asic (SPP mode only) + */ +static void u12io_DataToScanner( U12_Device *dev , SANE_Byte bValue ) +{ + if( dev->mode != _PP_MODE_SPP ) { + DBG( _DBG_ERROR, "u12io_DataToScanner() in wrong mode!\n" ); + return; + } + + /* output data */ + outb_data( dev->fd, bValue ); + + /* notify asic there is data */ + outb_ctrl( dev->fd, _CTRL_SIGNAL_DATAWRITE ); + + /* end write cycle */ + outb_ctrl( dev->fd, _CTRL_END_DATAWRITE ); +} + +/** Write data to specific ASIC's register + */ +static SANE_Status u12io_DataToRegister( U12_Device *dev, + SANE_Byte reg, SANE_Byte data ) +{ + SANE_Status status; + SANE_Byte buf[2]; + + if( dev->mode == _PP_MODE_EPP ) { + + buf[0] = reg; + buf[1] = data; + + bulk_setup_data[1] = 0x11; + CHK( gl640WriteBulk ( dev->fd, bulk_setup_data, buf, 2 )); + + } else { + + u12io_RegisterToScanner( dev, reg ); + u12io_DataToScanner( dev, data ); + } + return SANE_STATUS_GOOD; +} + +/** Write data-buffer to specific ASIC's register + * The format in the buffer is + * reg(0),val(0),reg(1),val(1),..., reg(len-1),val(len-1) + */ +static SANE_Status u12io_DataToRegs( U12_Device *dev, SANE_Byte *buf, int len ) +{ + SANE_Status status; + + if( dev->mode != _PP_MODE_EPP ) { + DBG( _DBG_ERROR, "u12io_DataToRegs() in wrong mode!\n" ); + return SANE_STATUS_IO_ERROR; + } + + bulk_setup_data[1] = 0x11; + CHK( gl640WriteBulk ( dev->fd, bulk_setup_data, buf, len*2 )); + return SANE_STATUS_GOOD; +} + +/** write data to the DAC + */ +static void +u12io_DataRegisterToDAC( U12_Device *dev, SANE_Byte reg, SANE_Byte val ) +{ + SANE_Byte buf[6]; + + buf[0] = REG_ADCADDR; + buf[1] = reg; + buf[2] = REG_ADCDATA; + buf[3] = val; + buf[4] = REG_ADCSERIALOUT; + buf[5] = val; + + u12io_DataToRegs( dev, buf, 3 ); +} + +/** write data block to scanner + */ +static SANE_Status u12io_MoveDataToScanner( U12_Device *dev, + SANE_Byte *buf, int len ) +{ + SANE_Status status; + +/* u12io_RegisterToScanner( dev, REG_INITDATAFIFO ); */ + u12io_RegisterToScanner( dev, REG_WRITEDATAMODE ); + + bulk_setup_data[1] = 0x01; + CHK( gl640WriteBulk( dev->fd, bulk_setup_data, buf, len )); + bulk_setup_data[1] = 0x11; + + return SANE_STATUS_GOOD; +} + +static SANE_Status u12io_ReadData( U12_Device *dev, SANE_Byte *buf, int len ) +{ + SANE_Status status; + + u12io_DataToRegister( dev, REG_MODECONTROL, dev->regs.RD_ModeControl ); +/* u12io_RegisterToScanner( dev, REG_INITDATAFIFO ); */ + u12io_RegisterToScanner( dev, REG_READDATAMODE ); + + bulk_setup_data[1] = 0x00; + CHK (gl640ReadBulk( dev->fd, bulk_setup_data, buf, len, 0 )); + bulk_setup_data[1] = 0x11; + + return SANE_STATUS_GOOD; +} + +/** perform a SW reset of ASIC P98003 + */ +static void u12io_SoftwareReset( U12_Device *dev ) +{ + DBG( _DBG_INFO, "Device reset (%i)!!!\n", dev->fd ); + + u12io_DataToRegister( dev, REG_TESTMODE, _SW_TESTMODE ); + + outb_data( dev->fd, _ID_TO_PRINTER ); + _DODELAY(20); + + outb_data( dev->fd, _RESET1ST ); + _DODELAY(5); + outb_data( dev->fd, _RESET2ND ); + _DODELAY(5); + outb_data( dev->fd, _RESET3RD ); + _DODELAY(5); + outb_data( dev->fd, _RESET4TH ); + _DODELAY(250); +} + +/** + */ +static SANE_Bool u12io_IsConnected( U12_Device *dev ) +{ + int c, mode; + SANE_Byte tmp, rb[6]; + + DBG( _DBG_INFO, "u12io_IsConnected()\n" ); + tmp = inb_status( dev->fd ); + DBG( _DBG_INFO, "* tmp1 = 0x%02x\n", tmp ); + + gl640WriteReq( dev->fd, GL640_EPP_ADDR, REG_ASICID ); + gl640ReadReq ( dev->fd, GL640_EPP_DATA_READ, &tmp ); + DBG( _DBG_INFO, "* REG_ASICID = 0x%02x\n", tmp ); + + if( tmp != ASIC_ID ) { + + DBG( _DBG_INFO, "* Scanner is NOT connected!\n" ); + + tmp = inb_status( dev->fd ); + DBG( _DBG_INFO, "* tmp2 = 0x%02x\n", tmp ); + + gl640WriteReq( dev->fd, GL640_EPP_ADDR, REG_ASICID ); + gl640ReadReq ( dev->fd, GL640_EPP_DATA_READ, &tmp ); + DBG( _DBG_INFO, "* REG_ASICID = 0x%02x\n", tmp ); + + if( tmp == 0x02 ) { + + mode = dev->mode; + dev->mode = _PP_MODE_EPP; + u12io_DataToRegister( dev, REG_ADCADDR, 0x01 ); + u12io_DataToRegister( dev, REG_ADCDATA, 0x00 ); + u12io_DataToRegister( dev, REG_ADCSERIALOUT, 0x00 ); + + c = 0; + _SET_REG( rb, c, REG_MODECONTROL, 0x19 ); + _SET_REG( rb, c, REG_STEPCONTROL, 0xff ); + _SET_REG( rb, c, REG_MOTOR0CONTROL, 0 ); + u12io_DataToRegs( dev, rb, c ); + dev->mode = mode ; + } + return SANE_FALSE; + } + + u12io_SwitchToEPPMode( dev ); + DBG( _DBG_INFO, "* Scanner is connected!\n" ); + return SANE_TRUE; +} + +/** + */ +static SANE_Byte u12io_GetExtendedStatus( U12_Device *dev ) +{ + SANE_Byte b; + + b = u12io_DataFromRegister( dev, REG_STATUS2 ); + if( b == 0xff ) + return 0; + return b; +} + +/** + */ +static SANE_Status u12io_ReadMonoData( U12_Device *dev, SANE_Byte *buf, u_long len ) +{ + SANE_Status status; + + bulk_setup_data[1] = 0x0c; + bulk_setup_data[2] = ((dev->regs.RD_ModeControl >> 3) + 1); + + CHK (gl640ReadBulk( dev->fd, bulk_setup_data, buf, len, 1 )); + bulk_setup_data[1] = 0x11; + bulk_setup_data[2] = 0; + + return SANE_STATUS_GOOD; +} + +/** + */ +static SANE_Status +u12io_ReadColorData( U12_Device *dev, SANE_Byte *buf, u_long len ) +{ + SANE_Status status; + + bulk_setup_data[1] = 0x0c; + + CHK (gl640ReadBulk( dev->fd, bulk_setup_data, buf, len, 3 )); + bulk_setup_data[1] = 0x11; + return SANE_STATUS_GOOD; +} + +/** read the recent state count + */ +static SANE_Byte u12io_GetScanState( U12_Device *dev ) +{ + if( cacheLen[0] == 0x83 ) { + DBG( _DBG_READ, "u12io_GetScanState(cached) = 0x%02x\n", cacheLen[1] ); + return cacheLen[1]; + } + return u12io_DataFromRegister( dev, REG_GETSCANSTATE ); +} + +/** download a scanstate-table + */ +static SANE_Status u12io_DownloadScanStates( U12_Device *dev ) +{ + SANE_Status status; + TimerDef timer; + + u12io_RegisterToScanner( dev, REG_SCANSTATECONTROL ); + + bulk_setup_data[1] = 0x01; + CHK( gl640WriteBulk( dev->fd, bulk_setup_data, + dev->scanStates, _SCANSTATE_BYTES )); + bulk_setup_data[1] = 0x11; + +/* FIXME: refreshState probably always FALSE */ + if( dev->scan.refreshState ) { + + u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE ); + + u12io_StartTimer( &timer, (_SECOND/2)); + do { + + if (!( u12io_GetScanState( dev ) & _SCANSTATE_STOP)) + break; + } + while( !u12io_CheckTimer(&timer)); + } + return SANE_STATUS_GOOD; +} + +/** - initializes the scan states + * - sets all necessary registers + * FIXME: first copy to buffer, then use u12io_DataToRegs() + */ +static void u12io_PutOnAllRegisters( U12_Device *dev ) +{ + SANE_Byte *val, reg; + SANE_Byte *rb, buf[100]; + int c; + + /* setup scan states */ + u12io_DownloadScanStates( dev ); + + c = 0; + rb = buf; + + *(rb++) = REG_MODECONTROL; + *(rb++) = dev->regs.RD_ModeControl; + c++; + *(rb++) = REG_STEPCONTROL; + *(rb++) = dev->regs.RD_StepControl; + c++; + *(rb++) = REG_MOTOR0CONTROL; + *(rb++) = dev->regs.RD_Motor0Control; + c++; + *(rb++) = REG_LINECONTROL; + *(rb++) = dev->regs.RD_LineControl; + c++; + *(rb++) = REG_XSTEPTIME; + *(rb++) = dev->regs.RD_XStepTime; + c++; + *(rb++) = REG_MODELCONTROL; + *(rb++) = dev->regs.RD_ModelControl; + c++; + /* the 1st register to write */ + val = (SANE_Byte*)&dev->regs.RD_Dpi; + + /* 0x21 - 0x28 */ + for( reg = REG_DPILO; reg <= REG_THRESHOLDHI; reg++, val++ ) { + *(rb++) = reg; + *(rb++) = *val; + c++; + } + + u12io_DataToRegs( dev, buf, c ); + + u12io_RegisterToScanner( dev, REG_INITDATAFIFO ); + u12io_DataToRegister( dev, REG_MODECONTROL, _ModeScan ); +} + +/** + */ +static void u12io_ResetFifoLen( void ) +{ + memset( cacheLen, 0, 13 ); +} + +/** + */ +static u_long u12io_GetFifoLength( U12_Device *dev ) +{ + SANE_Status status; + size_t toget; + SANE_Byte data[64]; + u_long len, len_r, len_g, len_b; + + if( cacheLen[0] == 0x83 ) { + + DBG( _DBG_READ, "Using cached FIFO len\n" ); + memcpy( data, cacheLen, 13 ); + u12io_ResetFifoLen(); + + } else { + + memset( bulk_setup_data, 0, 8 ); + bulk_setup_data[1] = 0x0c; + + CHK (gl640WriteControl(dev->fd, GL640_BULK_SETUP, bulk_setup_data, 8)); + + toget = 13; + status = sanei_usb_read_bulk( dev->fd, data, &toget ); + if( status != SANE_STATUS_GOOD ) { + DBG( _DBG_ERROR, "ReadBulk error\n"); + return SANE_FALSE; + } + bulk_setup_data[1] = 0x11; + + memcpy( cacheLen, data, 13 ); + } + len_r = (u_long)data[5] * 256 + (u_long)data[4]; + len_g = (u_long)data[8] * 256 + (u_long)data[7]; + len_b = (u_long)data[11] * 256 + (u_long)data[10]; + + if( dev->DataInf.wPhyDataType < COLOR_TRUE24 ) { + len = len_g; + } else { + + len = len_r; + if( len_g < len ) + len = len_g; + if( len_b < len ) + len = len_b; + } + + DBG( _DBG_READ, "FIFO-LEN: %lu %lu %lu = %lu\n", len_r, len_g, len_b, len ); + return len; +} + +/** + */ +static SANE_Bool +u12io_ReadOneShadingLine( U12_Device *dev, SANE_Byte *buf, u_long len ) +{ + TimerDef timer; + SANE_Status status; + + DBG( _DBG_READ, "u12io_ReadOneShadingLine()\n" ); + u12io_StartTimer( &timer, _SECOND ); + + dev->scan.bFifoSelect = REG_GFIFOOFFSET; + + do { + u12io_ResetFifoLen(); + if( u12io_GetFifoLength( dev ) >= dev->regs.RD_Pixels ) { + + status = u12io_ReadColorData( dev, buf, len ); + if( status != SANE_STATUS_GOOD ) { + DBG( _DBG_ERROR, "ReadColorData error\n"); + return SANE_FALSE; + } + DBG( _DBG_READ, "* done\n" ); + return SANE_TRUE; + } + } while( !u12io_CheckTimer( &timer )); + + DBG( _DBG_ERROR, "u12io_ReadOneShadingLine() failed!\n" ); + return SANE_FALSE; +} + +/* END U12-IO.C .............................................................*/ |