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