schreite@helena.physik.uni-stuttgart.de
Thu, 01 Oct 98 12:05:30 +0100
--- parport_ieee1284.c.inter	Thu Oct  1 12:45:23 1998
+++ parport_ieee1284.c	Wed Sep 30 13:55:32 1998
@@ -860,6 +860,442 @@
         data->sum_delay=0;
         parport_ieee1284_set_mode_p(data);
         return DRESULT;
 }
 
         
+/******************************************************
+ *** ECP emulation by software for non-ECP parports ***
+ ******************************************************/
+
+#define EOF -1
+void ECPemu_quit_read_p(struct parport_argument_packet *data);
+int decode_ECP(struct parport_argument_packet *data);
+void read_ECPemu_p(struct parport_argument_packet *data)
+{
+	int ret, mydepth;
+
+	if (!data->in_function[data->depth]) {
+		DDATA=0;   /* RLE count */
+		DSAVE_RESULT=0; /* number of chars read so far */
+	}
+	STATE_INI(read_ECPemu_p);
+
+	while (data->pc[mydepth]<=STATE_B) {
+		switch (data->pc[mydepth]) {
+		case STATE_NULL:
+			WRITE_CONTROL(PARPORT_CONTROL_AUTOFD|
+			              PARPORT_CONTROL_DIRECTION);
+			UDELAY(1);
+			if (parport_read_status(DPORT)&PARPORT_STATUS_PAPEROUT) {
+				SET_STATE(STATE_C);
+				break;
+			}
+			SET_STATE(STATE_A);
+			WAIT_RESET;
+		
+		case STATE_A:
+			if ((ret=parport_wait_status(data, PARPORT_STATUS_PAPEROUT|
+			                                  
PARPORT_STATUS_ACK, 0, 4))==
+			    TIMEOUT) {
+				SET_STATE(STATE_C);
+				break;
+			}
+			if (ret==TRYING_AGAIN) STILL_TRYING;
+		
+			if (decode_ECP(data)) {
+				WRITE_CONTROL(PARPORT_CONTROL_AUTOFD|
+				              PARPORT_CONTROL_INIT);
+				UDELAY(1);
+				RETURN_ERROR;
+			}
+
+			WRITE_CONTROL(PARPORT_CONTROL_DIRECTION);
+			UDELAY(1);
+			SET_STATE(STATE_B);
+			WAIT_RESET;
+	
+		case STATE_B:
+			if ((ret=parport_wait_status(data, PARPORT_STATUS_ACK|
+			                                   PARPORT_STATUS_PAPEROUT,
+			                                   PARPORT_STATUS_ACK, 4))==
+			    TIMEOUT) {
+				printk("read_ECPemu_p: peripheral doesn't "
+				       "acknowledge our receive acknowledge\n");
+				WRITE_CONTROL(PARPORT_CONTROL_AUTOFD|
+				          PARPORT_CONTROL_INIT);
+				UDELAY(1);
+				RETURN_ERROR;
+			}
+			if (ret==TRYING_AGAIN) STILL_TRYING;
+			SET_STATE(STATE_NULL);
+		}
+	}
+
+	switch (data->pc[mydepth]) {
+	case STATE_C:
+		SET_STATE(STATE_D);
+		CALL(ECPemu_quit_read_p);
+	}
+
+	RETURN(DRESULT);
+}
+
+
+void ECPemu_quit_read_p(struct parport_argument_packet *data)
+{
+	int ret, mydepth;
+
+	STATE_INI(ECPemu_quit_read_p);
+	
+	switch (data->pc[mydepth]) {
+	case STATE_NULL:
+		WRITE_CONTROL(PARPORT_CONTROL_AUTOFD|
+		              PARPORT_CONTROL_INIT);
+		UDELAY(1);
+		if (DDATA) {
+			printk("ECPemu_quit_read_p: RLE data not complete\n");
+			RETURN_ERROR;
+		}
+		SET_STATE(STATE_A);
+		WAIT_RESET;
+		
+	case STATE_A:
+		if ((ret=parport_wait_status(data, PARPORT_STATUS_PAPEROUT,
+		                             PARPORT_STATUS_PAPEROUT, 4))==
+		    TIMEOUT) {
+			printk("ECPemu_quit_read_p: Peripheral doesn't "
+			       "acknowledge quit read\n");
+			RETURN_ERROR;
+		}
+		if (ret==TRYING_AGAIN) STILL_TRYING;
+	}
+
+	RETURN(DSAVE_RESULT);
+}
+
+
+int decode_ECP(struct parport_argument_packet *data)
+{
+	unsigned char b;
+	
+	b=parport_read_data(DPORT);
+	DSTATUS=parport_read_status(DPORT);
+	
+	if (DSTATUS&PARPORT_STATUS_BUSY) { /* command received */
+		if (DDATA) {
+			printk("decode_ECP: previous RLE data not complete\n");
+			return -EIO;
+		}
+		
+		if ( (DPORT->cad->ieee1284.current_mode!=IEEE1284_ECPRLE) ||
+		     (b&0x80) ) {
+			printk("decode_ECP: unexpected channel change "
+			       " by peripheral\n");
+			return -EIO;
+		}
+	
+		DDATA=(b|0x80); /* use msb to indicate RLE count
+		                        (b could be 0) */
+	} else { /* data byte received */
+		if (DDATA&0x80) DDATA&=0x7f;
+		else DDATA=1;
+		
+		while (DDATA) {
+			if (DSAVE_RESULT<data->bufferlen)
+				data->buffer[DSAVE_RESULT]=b;
+			DSAVE_RESULT++;
+			DDATA--;
+		}
+	}
+	
+	return 0;
+}
+
+
+void write_ECPemu_chars_p(struct parport_argument_packet *data)
+{
+	int ret, mydepth;
+	char b;
+
+	STATE_INI(write_ECPemu_chars_p);
+
+	while ( (DSAVE_RESULT!=data->bufferlen) ||
+	        (data->pc[mydepth]!=STATE_NULL) ) {
+		switch (data->pc[mydepth]) {
+		case STATE_NULL:
+			if (data->bufferlen<0) {
+				parport_write_data(DPORT,
+				                   data->buffer[0]|0x80);
+					/* write channel, not RLE count */
+				WRITE_CONTROL(PARPORT_CONTROL_AUTOFD|
+				              PARPORT_CONTROL_INIT);
+					/* write command, not data */
+				data->bufferlen=0;
+			}
+			
+			else if ( (DDATA) ||
+			          (DPORT->cad->ieee1284.current_mode!=
+			           IEEE1284_ECPRLE) ||
+			          (DSAVE_RESULT+2>=data->bufferlen) ||
+			          (data->buffer[DSAVE_RESULT]!=
+			           data->buffer[DSAVE_RESULT+1]) ||
+			          (data->buffer[DSAVE_RESULT]!=
+			           data->buffer[DSAVE_RESULT+2]) ) {
+				DDATA=0;
+				parport_write_data(DPORT,
+				                   data->buffer
+				                     [DSAVE_RESULT++]);
+				WRITE_CONTROL(PARPORT_CONTROL_INIT);
+					/* write data, not command */
+			}
+			
+			else {
+				b=data->buffer[DSAVE_RESULT];
+				while ( (DDATA<128) &&
+				        (DSAVE_RESULT<data->bufferlen) &&
+				        (data->buffer[DSAVE_RESULT++]==b) );
+				DSAVE_RESULT--; /* store one char to send */
+				
+				parport_write_data(DPORT, DDATA);
+					/* write RLE count, not channel */
+				WRITE_CONTROL(PARPORT_CONTROL_AUTOFD|
+				              PARPORT_CONTROL_INIT);
+					/* write command, not data */
+			}
+
+			UDELAY(1);
+			SET_STATE(STATE_A);
+			WAIT_RESET;
+
+		case STATE_A:
+			if ((ret=parport_wait_status(data,
+			                             PARPORT_STATUS_PAPEROUT|
+			                             PARPORT_STATUS_BUSY,
+			                             PARPORT_STATUS_PAPEROUT|
+			                             PARPORT_STATUS_BUSY, 4))==
+			    TIMEOUT) {
+				printk("write_ECPemu_chars_p: Peripheral isn't "
+				       "ready to receive?\n");
+				RETURN_ERROR;
+			}
+			
+			if (ret==TRYING_AGAIN) STILL_TRYING;
+
+			SET_STROBE;
+			UDELAY(1);
+			SET_STATE(STATE_B);
+			WAIT_RESET;
+			
+		case STATE_B:
+			if ((ret=parport_wait_status(data,
+			                             PARPORT_STATUS_PAPEROUT|
+			                             PARPORT_STATUS_BUSY,
+			                             PARPORT_STATUS_PAPEROUT,
+			                             4))==TIMEOUT) {
+				printk("write_ECPemu_chars_p: Peripheral doesn"
+				       "'t signal receiving\n");
+				RETURN_ERROR;
+			}
+			if (ret==TRYING_AGAIN) STILL_TRYING;
+			
+			CLEAR_STROBE;
+			UDELAY(1);
+			
+			SET_STATE(STATE_C);
+			WAIT_RESET;
+			
+		case STATE_C:
+			if ((ret=parport_wait_status(data,
+			                             PARPORT_STATUS_PAPEROUT|
+			                             PARPORT_STATUS_BUSY,
+			                             PARPORT_STATUS_PAPEROUT|
+			                             PARPORT_STATUS_BUSY,
+			                             4))==TIMEOUT) {
+				printk("write_ECPemu_chars_p: Peripheral doesn"
+				       "'t signal ready for next\n");
+				RETURN_ERROR;
+			}
+			if (ret==TRYING_AGAIN) STILL_TRYING;
+			SET_STATE(STATE_NULL);
+		}
+	}
+
+	RETURN(0);
+}
+
+
+void write_ECPemu_p(struct parport_argument_packet *data)
+{
+	DDATA=0;   /* RLE count */
+	DSAVE_RESULT=0; /* number of chars written so far */
+	write_ECPemu_chars_p(data);
+	return;
+}
+
+
+void set_ECPemu_channel_p(struct parport_argument_packet *data)
+{
+	DDATA=0;   /* RLE count */
+	DSAVE_RESULT=0; /* number of chars written so far */
+	data->bufferlen=-1; /* is channel */
+	write_ECPemu_chars_p(data);
+	return;
+}
+
+
+int query_ECPemu_reversedata_available(struct parport *port)
+{
+	return (parport_read_status(port)&PARPORT_STATUS_ERROR);
+}
+
+
+/*******************
+ *** nibble mode ***
+ *******************/
+
+void read_nibblemode_p(struct parport_argument_packet *data)
+{
+	int ret, mydepth;
+	unsigned char b;
+
+	if (!data->in_function[data->depth]) {
+		DDATA=0;        /* no nibble read */
+		DSAVE_RESULT=0; /* number of chars read so far */
+	}
+	STATE_INI(read_nibblemode_p);
+
+	while (data->pc[mydepth]<=STATE_B) {
+		switch (data->pc[mydepth]) {
+		case STATE_NULL:
+			WRITE_CONTROL(PARPORT_CONTROL_AUTOFD);
+			UDELAY(1);
+			SET_STATE(STATE_A);
+			WAIT_RESET;
+			
+		case STATE_A:
+			if ((ret=parport_wait_status(data,
+			                             PARPORT_STATUS_ACK,
+			                             0, 4))==
+			    TIMEOUT) {
+				WRITE_CONTROL(0);
+				UDELAY(1);
+				SET_STATE(STATE_C);
+				break;
+			}
+			
+			if (ret==TRYING_AGAIN) STILL_TRYING;
+
+			b=(DSTATUS=parport_read_status(DPORT))>>3;
+			if (DSAVE_RESULT<data->bufferlen) {
+				b&=~8; /* decode nibble */
+				if (!(b&0x10)) b|=8;
+				b&=0xf;
+				if (DDATA) {
+					data->buffer[DSAVE_RESULT]|=
+						(b<<4);
+				} else {
+					data->buffer[DSAVE_RESULT]=b;
+				}
+			}
+			if (DDATA) {
+				DSAVE_RESULT++;
+				DDATA=0;
+			} else DDATA=1;
+
+			WRITE_CONTROL(0);
+			UDELAY(1);
+			SET_STATE(STATE_B);
+			WAIT_RESET;
+
+		case STATE_B:
+			if ((ret=parport_wait_status(data,
+			                             PARPORT_STATUS_ACK,
+			                             PARPORT_STATUS_ACK, 4))==
+			    TIMEOUT) {
+				printk("read_nibblemode_p: peripheral doesn't "
+				       "acknowledge our receive acknowledge\n");
+				RETURN_ERROR;
+			}
+			
+			if (ret==TRYING_AGAIN) STILL_TRYING;
+			SET_STATE(STATE_NULL);
+		}
+	}
+	
+	WRITE_CONTROL(0);
+	UDELAY(1);
+	if (DDATA) {
+		printk("read_nibblemode_p: byte not completely received\n");
+		RETURN_ERROR;
+	}
+	
+	RETURN(DSAVE_RESULT);	
+}
+
+
+/*****************
+ *** byte mode ***
+ *****************/
+void read_bytemode_p(struct parport_argument_packet *data)
+{
+	int ret, mydepth;
+	unsigned char b;
+
+	if (!data->in_function[data->depth]) {
+		DSAVE_RESULT=0; /* number of chars read so far */
+	}
+	STATE_INI(read_bytemode_p);
+
+	while (data->pc[mydepth]<=STATE_B) {
+		switch (data->pc[mydepth]) {
+		case STATE_NULL:
+			WRITE_CONTROL(PARPORT_CONTROL_AUTOFD| \
+			              PARPORT_CONTROL_DIRECTION);
+			UDELAY(1);
+			SET_STATE(STATE_A);
+			WAIT_RESET;
+			
+		case STATE_A:
+			if ((ret=parport_wait_status(data,
+			                             PARPORT_STATUS_ACK,
+			                             0, 4))==
+			    TIMEOUT) {
+				WRITE_CONTROL(0);
+				UDELAY(1);
+				SET_STATE(STATE_C);
+			}
+			
+			if (ret==TRYING_AGAIN) STILL_TRYING;
+
+			b=parport_read_data(DPORT);
+			if (DSAVE_RESULT<data->bufferlen)
+				data->buffer[DSAVE_RESULT]=b;
+			DSAVE_RESULT++;
+
+			WRITE_CONTROL(PARPORT_CONTROL_DIRECTION);
+			SET_STROBE;
+			UDELAY(5);
+			CLEAR_STROBE;
+			SET_STATE(STATE_B);
+			WAIT_RESET;
+
+		case STATE_B:
+			if ((ret=parport_wait_status(data,
+			                             PARPORT_STATUS_ACK,
+		                                     PARPORT_STATUS_ACK, 4))==
+		            TIMEOUT) {
+				printk("read_bytemode_p: peripheral doesn't "
+				       "acknowledge our receive acknowledge\n");
+				RETURN_ERROR;
+			}
+			
+		        if (ret==TRYING_AGAIN) STILL_TRYING;
+			SET_STATE(STATE_NULL);
+		}
+	}
+	
+	WRITE_CONTROL(PARPORT_CONTROL_DIRECTION);
+	UDELAY(1);
+	
+	RETURN(DSAVE_RESULT);	
+}
--  To unsubscribe, send mail to: linux-parport-request@torque.net --
--  with the single word "unsubscribe" in the body of the message. --
This archive was generated by hypermail 2.0b3 on Wed 30 Dec 1998 - 10:18:29 EST