kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			852 wiersze
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			852 wiersze
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
| /** @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 .............................................................*/
 |