diff options
author | msmith <msmith@FreeBSD.org> | 1998-08-03 19:14:33 +0000 |
---|---|---|
committer | msmith <msmith@FreeBSD.org> | 1998-08-03 19:14:33 +0000 |
commit | 2fdb23234a18b64b994328bb4be606a420e3b56d (patch) | |
tree | f8a4d5d9ba99cb367e9263ec96d08ecb8919f529 /sys/isa/ppc.c | |
parent | cfef94c8ca2347c78a745676fe6061eb1f172be7 (diff) | |
download | FreeBSD-src-2fdb23234a18b64b994328bb4be606a420e3b56d.zip FreeBSD-src-2fdb23234a18b64b994328bb4be606a420e3b56d.tar.gz |
Major ppbus updates from the author.
- ppbus now supports PLIP via the if_plip driver
- ieee1284 infrastructure added, including parallel-port PnP
- port microsequencer added, for scripting the sort of port I/O
that is common with parallel devices without endless calls up and down
through the driver structure.
- improved bus ownership behaviour among the ppbus-using drivers.
- improved I/O chipset feature detection
The vpo driver is now implemented using the microsequencer, leading to
some performance improvements as well as providing an extensive example
of its use.
Reviewed by: msmith
Submitted by: Nicolas Souchu <Nicolas.Souchu@prism.uvsq.fr>
Diffstat (limited to 'sys/isa/ppc.c')
-rw-r--r-- | sys/isa/ppc.c | 720 |
1 files changed, 555 insertions, 165 deletions
diff --git a/sys/isa/ppc.c b/sys/isa/ppc.c index 39d0ece..71daa85 100644 --- a/sys/isa/ppc.c +++ b/sys/isa/ppc.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997 Nicolas Souchu + * Copyright (c) 1997, 1998 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ppc.c,v 1.2 1997/09/01 02:08:41 bde Exp $ + * $Id: ppc.c,v 1.3 1998/04/17 22:36:37 des Exp $ * */ #include "ppc.h" @@ -44,6 +44,8 @@ #include <i386/isa/isa_device.h> #include <dev/ppbus/ppbconf.h> +#include <dev/ppbus/ppb_msq.h> + #include <i386/isa/ppcreg.h> static int ppcprobe(struct isa_device *); @@ -57,14 +59,26 @@ static struct ppc_data *ppcdata[NPPC]; static int nppc = 0; static char *ppc_types[] = { - "SMC", "SMC FDC37C665GT", "SMC FDC37C666GT", - "NatSemi", "PC87332", "PC87306", - "Intel 82091AA", "Generic", 0 + "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", + "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", 0 +}; + +/* list of available modes */ +static char *ppc_avms[] = { + "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", + "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", + "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", + "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 }; +/* list of current executing modes + * Note that few modes do not actually exist. + */ static char *ppc_modes[] = { - "AUTODETECT", "NIBBLE", "PS/2", "EPP", "ECP+EPP", "ECP+PS/2", "ECP", - "UNKNOWN", 0 + "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", + "EPP", "EPP", "EPP", "ECP", + "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", + "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 }; static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; @@ -110,12 +124,19 @@ static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); } static void ppc_reset_epp_timeout(int); static void ppc_ecp_sync(int); +static int ppc_exec_microseq(int, struct ppb_microseq *, int *); +static int ppc_generic_setmode(int, int); + static struct ppb_adapter ppc_adapter = { 0, /* no intr handler, filled by chipset dependent code */ ppc_reset_epp_timeout, ppc_ecp_sync, + ppc_exec_microseq, + + ppc_generic_setmode, + ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, @@ -143,8 +164,8 @@ ppc_ecp_sync(int unit) { DELAY(100); } - printf("ppc: ECP sync failed as data still " \ - "present in FIFO.\n"); + printf("ppc%d: ECP sync failed as data still " \ + "present in FIFO.\n", unit); return; } @@ -158,6 +179,35 @@ ppcintr(int unit) return; } +static void +ppc_ecp_config(struct ppc_data *ppc, int chipset_mode) +{ + /* XXX disable DMA, enable interrupts */ + if (chipset_mode & PPB_EPP) + /* select EPP mode */ + w_ecr(ppc, 0x80); + else if (chipset_mode & PPB_PS2) + /* select PS2 mode with ECP */ + w_ecr(ppc, 0x20); + else + /* keep ECP mode alone, default for NIBBLE */ + w_ecr(ppc, 0x70); + + return; +} + +static int +ppc_detect_port(struct ppc_data *ppc) +{ + + w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ + w_dtr(ppc, 0xaa); + if (r_dtr(ppc) != (char) 0xaa) + return (0); + + return (1); +} + /* * ppc_pc873xx_detect * @@ -170,11 +220,11 @@ static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; static int -ppc_pc873xx_detect(struct ppc_data *ppc) +ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ { static int index = 0; int base, idport; - int val, mode; + int val; while ((idport = pc873xx_basetab[index++])) { @@ -235,7 +285,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc) printf("PC873xx locked\n"); /* work out what mode we're in */ - mode = PPB_NIBBLE; /* worst case */ + ppc->ppc_avm |= PPB_NIBBLE; /* worst case */ outb(idport, PC873_PCR); val = inb(idport + 1); @@ -243,10 +293,10 @@ ppc_pc873xx_detect(struct ppc_data *ppc) outb(idport, PC873_PTR); val = inb(idport + 1); if (!(val & PC873_EPPRDIR)) { - mode = PPB_EPP; /* As we would have done it anwyay */ + ppc->ppc_avm |= PPB_EPP; /* As we would have done it anwyay */ } } else if ((val & PC873_ECPEN) && (val & PC873_ECPCLK)) { - mode = PPB_PS2; /* tolerable alternative */ + ppc->ppc_avm |= PPB_PS2; /* tolerable alternative */ } } else { if (bootverbose) @@ -299,7 +349,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc) outb(idport + 1, val); /* we are an EPP-32 port */ - mode = PPB_EPP; + ppc->ppc_avm |= PPB_EPP; } else { if (bootverbose) printf("ECP\n"); @@ -309,44 +359,21 @@ ppc_pc873xx_detect(struct ppc_data *ppc) outb(idport + 1, inb(idport + 1) | PC873_ECPEN | PC873_ECPCLK); /* we look like a PS/2 port */ - mode = PPB_PS2; + ppc->ppc_avm |= PPB_PS2; } } - return(mode); + + return(chipset_mode); } - return(0); + return(-1); } static int -ppc_detect_ps2(struct ppc_data *ppc) +ppc_check_epp_timeout(struct ppc_data *ppc) { - char save_control, r; - - save_control = r_ctr(ppc); - - /* Try PS/2 mode */ - w_ctr(ppc, 0xec); - w_dtr(ppc, 0x55); - - /* needed if in ECP mode */ - if (ppc->ppc_mode == PPB_ECP) - w_ctr(ppc, PCD | 0xec); - r = r_dtr(ppc); - - if (r != (char) 0xff) { - if (r != (char) 0x55) - return 0; - - w_dtr(ppc, 0xaa); - r = r_dtr(ppc); - if (r != (char) 0xaa) - return 0; - - return (PPB_NIBBLE); - } else - w_ctr(ppc, save_control); + ppc_reset_epp_timeout(ppc->ppc_unit); - return (PPB_PS2); + return (!(r_str(ppc) & TIMEOUT)); } /* @@ -355,11 +382,10 @@ ppc_detect_ps2(struct ppc_data *ppc) * SMC FDC37C66xGT configuration. */ static int -ppc_smc37c66xgt_detect(struct ppc_data *ppc, int mode) +ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) { int s, i; char r; - int retry = 0; /* boolean */ int type = -1; int csr = SMC66x_CSR; /* initial value is 0x3F0 */ @@ -404,7 +430,7 @@ config: * If chipset not found, do not continue. */ if (type == -1) - return (0); + return (-1); /* select CR1 */ outb(csr, 0x1); @@ -412,65 +438,72 @@ config: /* read the port's address: bits 0 and 1 of CR1 */ r = inb(cio) & SMC_CR1_ADDR; if (port_address[r] != ppc->ppc_base) - return (0); + return (-1); ppc->ppc_type = type; /* * CR1 and CR4 registers bits 3 and 0/1 for mode configuration - * If SPP mode is detected, try to set ECP+EPP mode end retry - * detection to verify. + * If SPP mode is detected, try to set ECP+EPP mode */ -retry: - /* select CR1 register */ + if (bootverbose) { + outb(csr, 0x1); + printf("SMC registers CR1=0x%x", ppc->ppc_unit, + inb(cio) & 0xff); + + outb(csr, 0x4); + printf(" CR4=0x%x", inb(cio) & 0xff); + } + + /* select CR1 */ outb(csr, 0x1); - if (!mode) { + if (!chipset_mode) { /* autodetect mode */ - /* 666GT chipset is hardwired to an extended mode */ - if (type == SMC_37C666GT) - mode = PPB_ECP_EPP; + /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ + if (type == SMC_37C666GT) { + ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - else if ((inb(cio) & SMC_CR1_MODE) == 0) { + } else + if ((inb(cio) & SMC_CR1_MODE) == 0) { /* already in extended parallel port mode, read CR4 */ outb(csr, 0x4); r = (inb(cio) & SMC_CR4_EMODE); switch (r) { case SMC_SPP: - /* let's detect NIBBLE or PS/2 later */ + ppc->ppc_avm |= PPB_SPP; break; case SMC_EPPSPP: - mode = PPB_EPP; + ppc->ppc_avm |= PPB_EPP | PPB_SPP; break; case SMC_ECP: - /* - * Yet, don't know what to do with it! XXX - * So, consider ECP mode as PS/2. - * (see configuration later). - */ - mode = PPB_ECP; + ppc->ppc_avm |= PPB_ECP | PPB_SPP; break; case SMC_ECPEPP: - mode = PPB_ECP_EPP; + ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; break; } - } + } else { + /* not an extended port mode */ + ppc->ppc_avm |= PPB_SPP; + } + } else { /* mode forced */ - /* 666GT chipset is hardwired to an extended mode */ + /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ if (type == SMC_37C666GT) goto end_detect; r = inb(cio); - if (mode == PPB_NIBBLE || mode == PPB_PS2) { - /* do not use ECP when the mode is forced to SPP */ + if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { + /* do not use ECP when the mode is not forced to */ outb(cio, r | SMC_CR1_MODE); } else { /* an extended mode is selected */ @@ -480,30 +513,26 @@ retry: outb(csr, 0x4); r = inb(cio) & ~SMC_CR4_EMODE; - switch (mode) { - case PPB_EPP: + if (chipset_mode & PPB_ECP) { + if (chipset_mode & PPB_EPP) { + outb(cio, r | SMC_ECPEPP); + } else { + outb(cio, r | SMC_ECP); + } + } else { + /* PPB_EPP is set */ outb(cio, r | SMC_EPPSPP); - break; - - case PPB_ECP: - case PPB_ECP_PS2: - outb(cio, r | SMC_ECP); - break; - - case PPB_ECP_EPP: - outb(cio, r | SMC_ECPEPP); - break; - - default: - printf("ppc: unknown mode (%d)\n", - mode); - return (0); } } + ppc->ppc_avm = chipset_mode; } end_detect: - if (PPB_IS_EPP(mode)) { + + if (bootverbose) + printf ("\n"); + + if (chipset_mode & PPB_EPP) { /* select CR4 */ outb(csr, 0x4); r = inb(cio); @@ -511,11 +540,9 @@ end_detect: /* * Set the EPP protocol... * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 - * ...then check the result. */ if (ppc->ppc_epp == EPP_1_9) outb(cio, (r & ~SMC_CR4_EPPTYPE)); - else outb(cio, (r | SMC_CR4_EPPTYPE)); } @@ -523,86 +550,214 @@ end_detect: /* end config mode */ outb(csr, 0xaa); - /* - * Write 100 to the mode bits and disable DMA, enable intr. - */ - if (mode == PPB_ECP_EPP) - w_ecr(ppc, 0x80); + if (ppc->ppc_avm & PPB_ECP) + ppc_ecp_config(ppc, chipset_mode); - /* - * Write 001 to the mode bits and disable DMA, enable intr. - */ - if (mode == PPB_ECP) - w_ecr(ppc, 0x20); + return (chipset_mode); +} + +/* + * Winbond W83877F stuff + * + * EFER: extended function enable register + * EFIR: extended function index register + * EFDR: extended function data register + */ +#define efir ((efer == 0x250) ? 0x251 : 0x3f0) +#define efdr ((efer == 0x250) ? 0x252 : 0x3f1) + +static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; +static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; +static int w83877f_keyiter[] = { 1, 2, 2, 1 }; +static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; + +static int +ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) +{ + int i, j, efer, base; + unsigned char r, hefere, hefras; + + for (i = 0; i < 4; i ++) { + /* first try to enable configuration registers */ + efer = w83877f_efers[i]; + + /* write the key to the EFER */ + for (j = 0; j < w83877f_keyiter[i]; j ++) + outb (efer, w83877f_keys[i]); + + /* then check HEFERE and HEFRAS bits */ + outb (efir, 0x0c); + hefere = inb(efdr) & WINB_HEFERE; + + outb (efir, 0x16); + hefras = inb(efdr) & WINB_HEFRAS; - if (PPB_IS_EPP(mode)) { /* - * Try to reset EPP timeout bit. - * If it fails, try PS/2 and NIBBLE modes. + * HEFRAS HEFERE + * 0 1 write 89h to 250h (power-on default) + * 1 0 write 86h twice to 3f0h + * 1 1 write 87h twice to 3f0h + * 0 0 write 88h to 250h */ - ppc_reset_epp_timeout(ppc->ppc_unit); + if ((hefere | hefras) == w83877f_hefs[i]) + goto found; + } - r = r_str(ppc); - if (!(r & TIMEOUT)) - return (mode); - } else { - if (mode) - return (mode); + return (-1); /* failed */ + +found: + /* check base port address - read from CR23 */ + outb(efir, 0x23); + if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ + return (-1); + + /* read CHIP ID from CR9/bits0-3 */ + outb(efir, 0x9); + + switch (inb(efdr) & WINB_CHIPID) { + case WINB_W83877F_ID: + ppc->ppc_type = WINB_W83877F; + break; + + case WINB_W83877AF_ID: + ppc->ppc_type = WINB_W83877AF; + break; + + default: + ppc->ppc_type = WINB_UNKNOWN; } - /* detect PS/2 or NIBBLE mode */ - return (ppc_detect_ps2(ppc)); -} + if (bootverbose) { + /* dump of registers */ + printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]); + for (i = 0; i <= 0xd; i ++) { + outb(efir, i); + printf("0x%x ", inb(efdr)); + } + for (i = 0x10; i <= 0x17; i ++) { + outb(efir, i); + printf("0x%x ", inb(efdr)); + } + outb(efir, 0x1e); + printf("0x%x ", inb(efdr)); + for (i = 0x20; i <= 0x29; i ++) { + outb(efir, i); + printf("0x%x ", inb(efdr)); + } + printf("\n"); + } -static int -ppc_check_ecpepp_timeout(struct ppc_data *ppc) -{ - char r; + if (!chipset_mode) { + /* autodetect mode */ - ppc_reset_epp_timeout(ppc->ppc_unit); + /* select CR0 */ + outb(efir, 0x0); + r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); + + /* select CR9 */ + outb(efir, 0x9); + r |= (inb(efdr) & WINB_PRTMODS2); + + switch (r) { + case WINB_W83757: + if (bootverbose) + printf("ppc%d: W83757 compatible mode\n", + ppc->ppc_unit); + return (-1); /* generic or SMC-like */ + + case WINB_EXTFDC: + case WINB_EXTADP: + case WINB_EXT2FDD: + case WINB_JOYSTICK: + if (bootverbose) + printf("ppc%d: not in parallel port mode\n", + ppc->ppc_unit); + return (-1); + + case (WINB_PARALLEL | WINB_EPP_SPP): + ppc->ppc_avm |= PPB_EPP | PPB_SPP; + break; - r = r_str(ppc); - if (!(r & TIMEOUT)) { - return (PPB_ECP_EPP); + case (WINB_PARALLEL | WINB_ECP): + ppc->ppc_avm |= PPB_ECP | PPB_SPP; + break; + + case (WINB_PARALLEL | WINB_ECP_EPP): + ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; + break; + default: + printf("%s: unknown case (0x%x)!\n", __FUNCTION__, r); + } + + } else { + /* mode forced */ + + /* select CR9 and set PRTMODS2 bit */ + outb(efir, 0x9); + outb(efdr, inb(efdr) & ~WINB_PRTMODS2); + + /* select CR0 and reset PRTMODSx bits */ + outb(efir, 0x0); + outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); + + if (chipset_mode & PPB_ECP) { + if (chipset_mode & PPB_EPP) + outb(efdr, inb(efdr) | WINB_ECP_EPP); + else + outb(efdr, inb(efdr) | WINB_ECP); + } else { + /* select EPP_SPP otherwise */ + outb(efdr, inb(efdr) | WINB_EPP_SPP); + } + ppc->ppc_avm = chipset_mode; } + + /* exit configuration mode */ + outb(efer, 0xaa); - /* If EPP timeout bit is not reset, DON'T use EPP */ - w_ecr(ppc, 0x20); + if (ppc->ppc_avm & PPB_ECP) + ppc_ecp_config(ppc, chipset_mode); - return (PPB_ECP_PS2); + return (chipset_mode); } /* * ppc_generic_detect */ static int -ppc_generic_detect(struct ppc_data *ppc, int mode) +ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) { - char save_control, r; + char save_control; + + if (!chipset_mode) { + /* first, check for ECP */ + w_ecr(ppc, 0x20); + if ((r_ecr(ppc) & 0xe0) == 0x20) { + ppc->ppc_avm |= PPB_ECP | PPB_SPP; - /* don't know what to do here */ - if (mode) - return (mode); + /* search for SMC style ECP+EPP mode */ + w_ecr(ppc, 0x80); + } - /* try to reset EPP timeout bit */ - ppc_reset_epp_timeout(ppc->ppc_unit); + /* try to reset EPP timeout bit */ + if (ppc_check_epp_timeout(ppc)) { + ppc->ppc_avm |= PPB_EPP; - r = r_str(ppc); - if (!(r & TIMEOUT)) { - return (PPB_EPP); - } + if (ppc->ppc_avm & PPB_ECP) + /* SMC like chipset found */ + ppc->ppc_type = SMC_LIKE; + } - /* Now check for ECP */ - w_ecr(ppc, 0x20); - r = r_ecr(ppc); - if ((r & 0xe0) == 0x20) { - /* Search for SMC style EPP+ECP mode */ - w_ecr(ppc, 0x80); + /* XXX try to detect NIBBLE mode */ + ppc->ppc_avm |= PPB_NIBBLE; - return (ppc_check_ecpepp_timeout(ppc)); - } + } else + ppc->ppc_avm = chipset_mode; + + if (ppc->ppc_avm & PPB_ECP) + ppc_ecp_config(ppc, chipset_mode); - return (ppc_detect_ps2(ppc)); + return (chipset_mode); } /* @@ -611,22 +766,258 @@ ppc_generic_detect(struct ppc_data *ppc, int mode) * mode is the mode suggested at boot */ static int -ppc_detect(struct ppc_data *ppc, int mode) { +ppc_detect(struct ppc_data *ppc, int chipset_mode) { - if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_pc873xx_detect(ppc))) - goto end_detect; + int i, mode; - if (!ppc->ppc_mode && (ppc->ppc_mode = - ppc_smc37c66xgt_detect(ppc, mode))) - goto end_detect; + /* list of supported chipsets */ + int (*chipset_detect[])(struct ppc_data *, int) = { + ppc_pc873xx_detect, + ppc_smc37c66xgt_detect, + ppc_w83877f_detect, + ppc_generic_detect, + NULL + }; - if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_generic_detect(ppc, mode))) - goto end_detect; + /* if can't find the port and mode not forced return error */ + if (!ppc_detect_port(ppc) && chipset_mode == 0) + return (EIO); /* failed, port not present */ - printf("ppc: port not present at 0x%x.\n", ppc->ppc_base); - return (PPC_ENOPORT); + /* assume centronics compatible mode is supported */ + ppc->ppc_avm = PPB_COMPATIBLE; -end_detect: + /* we have to differenciate available chipset modes, + * chipset running modes and IEEE-1284 operating modes + * + * after detection, the port must support running in compatible mode + */ + for (i=0; chipset_detect[i] != NULL; i++) { + if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { + ppc->ppc_mode = mode; + break; + } + } + + return (0); +} + +/* + * ppc_exec_microseq() + * + * Execute a microsequence. + * Microsequence mechanism is supposed to handle fast I/O operations. + */ +static int +ppc_exec_microseq(int unit, struct ppb_microseq *msq, int *ppbpc) +{ + struct ppc_data *ppc = ppcdata[unit]; + struct ppb_microseq *pc; + char cc, *p; + int i, iter, reg; + int error; + + /* static to be reused after few ppc_exec_microseq()/return calls + * XXX should be in a context variable shared with ppb level */ + static int accum; + static char *ptr; + + struct ppb_microseq *microseq_stack = 0; + struct ppb_microseq *pc_stack = 0; + +/* microsequence registers are equivalent to PC-like port registers */ +#define r_reg(register,ppc) ((char)inb((ppc)->ppc_base + register)) +#define w_reg(register,ppc,byte) outb((ppc)->ppc_base + register, byte) + +#define INCR_PC (pc ++) /* increment program counter */ +#define mi pc /* microinstruction currently executed */ + + /* get the state of pc from ppb level of execution */ + pc = &msq[*ppbpc]; + + for (;;) { + + switch (mi->opcode) { + case MS_OP_RSET: + cc = r_reg(mi->arg[0].i, ppc); + cc &= mi->arg[2].c; /* clear mask */ + cc |= mi->arg[1].c; /* assert mask */ + w_reg(mi->arg[0].i, ppc, cc); + INCR_PC; + break; + + case MS_OP_RASSERT_P: + for (i=0; i<mi->arg[0].i; i++) + w_reg(mi->arg[1].i, ppc, *ptr++); + INCR_PC; + break; + + case MS_OP_RFETCH_P: + for (i=0; i<mi->arg[0].i; i++) + *ptr++ = r_reg(mi->arg[1].i, ppc) & + mi->arg[2].c; + INCR_PC; + break; + + case MS_OP_RFETCH: + *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & + mi->arg[1].c; + INCR_PC; + break; + + case MS_OP_RASSERT: + + /* let's suppose the next instr. is the same */ + prefetch: + for (;mi->opcode == MS_OP_RASSERT; INCR_PC) + w_reg(mi->arg[0].i, ppc, mi->arg[1].c); + + if (mi->opcode == MS_OP_DELAY) { + DELAY(mi->arg[0].i); + INCR_PC; + goto prefetch; + } + break; + + case MS_OP_DELAY: + DELAY(mi->arg[0].i); + INCR_PC; + break; + + case MS_OP_TRIG: + reg = mi->arg[0].i; + iter = mi->arg[1].i; + p = (char *)mi->arg[2].p; + + for (i=0; i<iter; i++) { + w_reg(reg, ppc, *p++); + DELAY((unsigned char)*p++); + } + INCR_PC; + break; + + case MS_OP_SET: + accum = mi->arg[0].i; + INCR_PC; + break; + + case MS_OP_DBRA: + if (--accum > 0) + pc += mi->arg[0].i; + else + INCR_PC; + break; + + case MS_OP_BRSET: + cc = r_str(ppc); + if ((cc & mi->arg[0].c) == mi->arg[0].c) + pc += mi->arg[1].i; + else + INCR_PC; + break; + + case MS_OP_BRCLEAR: + cc = r_str(ppc); + if ((cc & mi->arg[0].c) == 0) + pc += mi->arg[1].i; + else + INCR_PC; + break; + + case MS_OP_C_CALL: + /* + * If the C call returns !0 then end the microseq. + * The current state of ptr is passed to the C function + */ + if ((error = mi->arg[0].f(mi->arg[1].p, ptr))) + return (error); + + INCR_PC; + break; + + case MS_OP_PTR: + ptr = (char *)mi->arg[0].p; + INCR_PC; + break; + + case MS_OP_CALL: + if (microseq_stack) + panic("%s: too much calls", __FUNCTION__); + + if (mi->arg[0].p) { + /* store the state of the actual + * microsequence + */ + microseq_stack = msq; + pc_stack = pc; + + /* jump to the new microsequence */ + msq = (struct ppb_microseq *)mi->arg[0].p; + pc = msq; + } else + INCR_PC; + + break; + + case MS_OP_SUBRET: + /* retrieve microseq and pc state before the call */ + msq = microseq_stack; + pc = pc_stack; + + /* reset the stack */ + microseq_stack = 0; + + /* XXX return code */ + + INCR_PC; + break; + + case MS_OP_PUT: + case MS_OP_GET: + case MS_OP_RET: + /* can't return to ppb level during the execution + * of a submicrosequence */ + if (microseq_stack) + panic("%s: can't return to ppb level", + __FUNCTION__); + + /* update pc for ppb level of execution */ + *ppbpc = (int)(pc - msq); + + /* return to ppb level of execution */ + return (0); + + default: + panic("%s: unknown microsequence opcode 0x%x", + __FUNCTION__, mi->opcode); + } + } + + /* unreached */ +} + +/* + * Configure current operating mode + */ +static int +ppc_generic_setmode(int unit, int mode) +{ + struct ppc_data *ppc = ppcdata[unit]; + + /* back to compatible mode, XXX don't know yet what to do here */ + if (mode == 0) { + ppc->ppc_mode = PPB_COMPATIBLE; + return (0); + } + + /* check if mode is available */ + if (!(ppc->ppc_avm & mode)) + return (EOPNOTSUPP); + + /* if ECP mode, configure ecr register */ + if (ppc->ppc_avm & PPB_ECP) + ppc_ecp_config(ppc, mode); + + ppc->ppc_mode = mode; return (0); } @@ -688,16 +1079,14 @@ ppcprobe(struct isa_device *dvp) ppc->ppc_unit = dvp->id_unit; ppc->ppc_type = GENERIC; - /* PPB_AUTODETECT is default to allow chipset detection even if - * mode is forced by dvp->id_flags (see later, ppc_detect() call) */ - ppc->ppc_mode = PPB_AUTODETECT; - ppc->ppc_epp = (dvp->id_flags & 0x8) >> 3; + ppc->ppc_mode = PPB_COMPATIBLE; + ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4; /* * XXX * Try and detect if interrupts are working. */ - if (!(dvp->id_flags & 0x10)) + if (!(dvp->id_flags & 0x20)) ppc->ppc_irq = (dvp->id_irq); ppcdata[ppc->ppc_unit] = ppc; @@ -706,7 +1095,7 @@ ppcprobe(struct isa_device *dvp) /* * Try to detect the chipset and its mode. */ - if (ppc_detect(ppc, dvp->id_flags & 0x7)) + if (ppc_detect(ppc, dvp->id_flags & 0xf)) goto error; end_probe: @@ -722,6 +1111,7 @@ ppcattach(struct isa_device *isdp) { struct ppc_data *ppc = ppcdata[isdp->id_unit]; struct ppb_data *ppbus; + char * mode; /* * Link the Parallel Port Chipset (adapter) to @@ -730,9 +1120,9 @@ ppcattach(struct isa_device *isdp) ppc->ppc_link.adapter_unit = ppc->ppc_unit; ppc->ppc_link.adapter = &ppc_adapter; - printf("ppc%d: %s chipset in %s mode%s\n", ppc->ppc_unit, - ppc_types[ppc->ppc_type], ppc_modes[ppc->ppc_mode], - (PPB_IS_EPP(ppc->ppc_mode)) ? + printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit, + ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm], + ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? ppc_epp_protocol[ppc->ppc_epp] : ""); /* |