/* Test if the peripheral is IEEE 1284 compliant. * return values are: * 0 - handshake failed; peripheral is not compliant (or none present) * 1 - handshake OK; IEEE1284 peripheral present but no data available * 2 - handshake OK; IEEE1284 peripheral and data available */ int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) { /* make sure it's a valid state, set nStrobe & nAutoFeed high */ parport_write_control(port, (parport_read_control(port) \ & ~1 ) & ~2); udelay(1); parport_write_data(port, mode); udelay(1); /* nSelectIn high, nAutoFd low */ parport_write_control(port, (parport_read_control(port) & ~8) | 2); if (parport_wait_peripheral(port, 0x78, 0x38)) { parport_write_control(port, (parport_read_control(port) & ~2) | 8); return 0; } /* nStrobe low */ parport_write_control(port, parport_read_control(port) | 1); udelay(1); /* Strobe wait */ /* nStrobe high, nAutoFeed low, last step before transferring * reverse data */ parport_write_control(port, (parport_read_control(port) \ & ~1) & ~2); udelay(1); /* Data available? */ return (parport_wait_peripheral(port, 0x20, 0))?1:2; }
int parport_negotiate (struct parport *port, int mode) { #ifndef CONFIG_PARPORT_1284 if (mode == IEEE1284_MODE_COMPAT) return 0; printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n"); return -1; #else int m = mode & ~IEEE1284_ADDR; int r; unsigned char xflag; port = port->physport; /* Is there anything to do? */ if (port->ieee1284.mode == mode) return 0; /* Is the difference just an address-or-not bit? */ if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){ port->ieee1284.mode = mode; return 0; } /* Go to compability forward idle mode */ if (port->ieee1284.mode != IEEE1284_MODE_COMPAT) parport_ieee1284_terminate (port); if (mode == IEEE1284_MODE_COMPAT) /* Compatibility mode: no negotiation. */ return 0; switch (mode) { case IEEE1284_MODE_ECPSWE: m = IEEE1284_MODE_ECP; break; case IEEE1284_MODE_EPPSL: case IEEE1284_MODE_EPPSWE: m = IEEE1284_MODE_EPP; break; case IEEE1284_MODE_BECP: return -ENOSYS; /* FIXME (implement BECP) */ } if (mode & IEEE1284_EXT_LINK) m = 1<<7; /* request extensibility link */ port->ieee1284.phase = IEEE1284_PH_NEGOTIATION; /* Start off with nStrobe and nAutoFd high, and nSelectIn low */ parport_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); udelay(1); /* Event 0: Set data */ parport_data_forward (port); parport_write_data (port, m); udelay (400); /* Shouldn't need to wait this long. */ /* Event 1: Set nSelectIn high, nAutoFd low */ parport_frob_control (port, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); /* Event 2: PError, Select, nFault go high, nAck goes low */ if (parport_wait_peripheral (port, PARPORT_STATUS_ERROR | PARPORT_STATUS_SELECT | PARPORT_STATUS_PAPEROUT | PARPORT_STATUS_ACK, PARPORT_STATUS_ERROR | PARPORT_STATUS_SELECT | PARPORT_STATUS_PAPEROUT)) { /* Timeout */ parport_frob_control (port, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_SELECT); DPRINTK (KERN_DEBUG "%s: Peripheral not IEEE1284 compliant (0x%02X)\n", port->name, parport_read_status (port)); port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; return -1; /* Not IEEE1284 compliant */ } /* Event 3: Set nStrobe low */ parport_frob_control (port, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); /* Event 4: Set nStrobe and nAutoFd high */ udelay (5); parport_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD, 0); /* Event 6: nAck goes high */ if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK)) { /* This shouldn't really happen with a compliant device. */ DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported? (0x%02x)\n", port->name, mode, port->ops->read_status (port)); parport_ieee1284_terminate (port); return 1; } xflag = parport_read_status (port) & PARPORT_STATUS_SELECT; /* xflag should be high for all modes other than nibble (0). */ if (mode && !xflag) { /* Mode not supported. */ DPRINTK (KERN_DEBUG "%s: Mode 0x%02x rejected by peripheral\n", port->name, mode); parport_ieee1284_terminate (port); return 1; } /* More to do if we've requested extensibility link. */ if (mode & IEEE1284_EXT_LINK) { m = mode & 0x7f; udelay (1); parport_write_data (port, m); udelay (1); /* Event 51: Set nStrobe low */ parport_frob_control (port, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); /* Event 52: nAck goes low */ if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) { /* This peripheral is _very_ slow. */ DPRINTK (KERN_DEBUG "%s: Event 52 didn't happen\n", port->name); parport_ieee1284_terminate (port); return 1; } /* Event 53: Set nStrobe high */ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); /* Event 55: nAck goes high */ if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK)) { /* This shouldn't really happen with a compliant * device. */ DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported? (0x%02x)\n", port->name, mode, port->ops->read_status (port)); parport_ieee1284_terminate (port); return 1; } /* Event 54: Peripheral sets XFlag to reflect support */ xflag = parport_read_status (port) & PARPORT_STATUS_SELECT; /* xflag should be high. */ if (!xflag) { /* Extended mode not supported. */ DPRINTK (KERN_DEBUG "%s: Extended mode 0x%02x not " "supported\n", port->name, mode); parport_ieee1284_terminate (port); return 1; } /* Any further setup is left to the caller. */ } /* Mode is supported */ DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode); port->ieee1284.mode = mode; /* But ECP is special */ if (!(mode & IEEE1284_EXT_LINK) && (m & IEEE1284_MODE_ECP)) { port->ieee1284.phase = IEEE1284_PH_ECP_SETUP; /* Event 30: Set nAutoFd low */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); /* Event 31: PError goes high. */ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); if (r) { DPRINTK (KERN_INFO "%s: Timeout at event 31\n", port->name); } port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", port->name); } else switch (mode) { case IEEE1284_MODE_NIBBLE: case IEEE1284_MODE_BYTE: port->ieee1284.phase = IEEE1284_PH_REV_IDLE; break; default: port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; } return 0; #endif /* IEEE1284 support */ }
/* Terminate a negotiated mode. */ static void parport_ieee1284_terminate (struct parport *port) { int r; port = port->physport; /* EPP terminates differently. */ switch (port->ieee1284.mode) { case IEEE1284_MODE_EPP: case IEEE1284_MODE_EPPSL: case IEEE1284_MODE_EPPSWE: /* Terminate from EPP mode. */ /* Event 68: Set nInit low */ parport_frob_control (port, PARPORT_CONTROL_INIT, 0); udelay (50); /* Event 69: Set nInit high, nSelectIn low */ parport_frob_control (port, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT); break; case IEEE1284_MODE_ECP: case IEEE1284_MODE_ECPRLE: case IEEE1284_MODE_ECPSWE: /* In ECP we can only terminate from fwd idle phase. */ if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { /* Event 47: Set nInit high */ parport_frob_control (port, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD); /* Event 49: PError goes high */ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); if (r) DPRINTK (KERN_INFO "%s: Timeout at event 49\n", port->name); parport_data_forward (port); DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", port->name); port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; } /* fall-though.. */ default: /* Terminate from all other modes. */ /* Event 22: Set nSelectIn low, nAutoFd high */ parport_frob_control (port, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_SELECT); /* Event 24: nAck goes low */ r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0); if (r) DPRINTK (KERN_INFO "%s: Timeout at event 24\n", port->name); /* Event 25: Set nAutoFd low */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); /* Event 27: nAck goes high */ r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); if (r) DPRINTK (KERN_INFO "%s: Timeout at event 27\n", port->name); /* Event 29: Set nAutoFd high */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); } port->ieee1284.mode = IEEE1284_MODE_COMPAT; port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n", port->name); }
int parport_negotiate (struct parport *port, int mode) { #ifndef CONFIG_PARPORT_1284 if (mode == IEEE1284_MODE_COMPAT) return 0; printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n"); return -1; #else int m = mode & ~IEEE1284_ADDR; int r; unsigned char xflag; port = port->physport; if (port->ieee1284.mode == mode) return 0; if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){ port->ieee1284.mode = mode; return 0; } if (port->ieee1284.mode != IEEE1284_MODE_COMPAT) parport_ieee1284_terminate (port); if (mode == IEEE1284_MODE_COMPAT) return 0; switch (mode) { case IEEE1284_MODE_ECPSWE: m = IEEE1284_MODE_ECP; break; case IEEE1284_MODE_EPPSL: case IEEE1284_MODE_EPPSWE: m = IEEE1284_MODE_EPP; break; case IEEE1284_MODE_BECP: return -ENOSYS; } if (mode & IEEE1284_EXT_LINK) m = 1<<7; port->ieee1284.phase = IEEE1284_PH_NEGOTIATION; parport_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); udelay(1); parport_data_forward (port); parport_write_data (port, m); udelay (400); parport_frob_control (port, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); if (parport_wait_peripheral (port, PARPORT_STATUS_ERROR | PARPORT_STATUS_SELECT | PARPORT_STATUS_PAPEROUT | PARPORT_STATUS_ACK, PARPORT_STATUS_ERROR | PARPORT_STATUS_SELECT | PARPORT_STATUS_PAPEROUT)) { parport_frob_control (port, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_SELECT); DPRINTK (KERN_DEBUG "%s: Peripheral not IEEE1284 compliant (0x%02X)\n", port->name, parport_read_status (port)); port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; return -1; } parport_frob_control (port, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); udelay (5); parport_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD, 0); if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK)) { DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported? (0x%02x)\n", port->name, mode, port->ops->read_status (port)); parport_ieee1284_terminate (port); return 1; } xflag = parport_read_status (port) & PARPORT_STATUS_SELECT; if (mode && !xflag) { DPRINTK (KERN_DEBUG "%s: Mode 0x%02x rejected by peripheral\n", port->name, mode); parport_ieee1284_terminate (port); return 1; } if (mode & IEEE1284_EXT_LINK) { m = mode & 0x7f; udelay (1); parport_write_data (port, m); udelay (1); parport_frob_control (port, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) { DPRINTK (KERN_DEBUG "%s: Event 52 didn't happen\n", port->name); parport_ieee1284_terminate (port); return 1; } parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK)) { DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported? (0x%02x)\n", port->name, mode, port->ops->read_status (port)); parport_ieee1284_terminate (port); return 1; } xflag = parport_read_status (port) & PARPORT_STATUS_SELECT; if (!xflag) { DPRINTK (KERN_DEBUG "%s: Extended mode 0x%02x not " "supported\n", port->name, mode); parport_ieee1284_terminate (port); return 1; } } DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode); port->ieee1284.mode = mode; if (!(mode & IEEE1284_EXT_LINK) && (m & IEEE1284_MODE_ECP)) { port->ieee1284.phase = IEEE1284_PH_ECP_SETUP; parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); if (r) { DPRINTK (KERN_INFO "%s: Timeout at event 31\n", port->name); } port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", port->name); } else switch (mode) { case IEEE1284_MODE_NIBBLE: case IEEE1284_MODE_BYTE: port->ieee1284.phase = IEEE1284_PH_REV_IDLE; break; default: port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; } return 0; #endif }
static void parport_ieee1284_terminate (struct parport *port) { int r; port = port->physport; switch (port->ieee1284.mode) { case IEEE1284_MODE_EPP: case IEEE1284_MODE_EPPSL: case IEEE1284_MODE_EPPSWE: parport_frob_control (port, PARPORT_CONTROL_INIT, 0); udelay (50); parport_frob_control (port, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT); break; case IEEE1284_MODE_ECP: case IEEE1284_MODE_ECPRLE: case IEEE1284_MODE_ECPSWE: if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { parport_frob_control (port, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD); r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); if (r) DPRINTK (KERN_INFO "%s: Timeout at event 49\n", port->name); parport_data_forward (port); DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", port->name); port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; } default: parport_frob_control (port, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_SELECT); r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0); if (r) DPRINTK (KERN_INFO "%s: Timeout at event 24\n", port->name); parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); if (r) DPRINTK (KERN_INFO "%s: Timeout at event 27\n", port->name); parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); } port->ieee1284.mode = IEEE1284_MODE_COMPAT; port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n", port->name); }