📄 ppw9xring0init.c
字号:
ring0_outb(0x55, pp_w9xring0_iobase+LPTREG_DATA); if (ring0_inb(pp_w9xring0_iobase+LPTREG_DATA) != 0x55) return 0; return PARPORT_MODE_PCSPP;}/* Check for ECP * * Old style XT ports alias io ports every 0x400, hence accessing ECR * on these cards actually accesses the CTR. * * Modern cards don't do this but reading from ECR will return 0xff * regardless of what is written here if the card does NOT support * ECP. * * We will write 0x2c to ECR and 0xcc to CTR since both of these * values are "safe" on the CTR since bits 6-7 of CTR are unused. */static int parport_ecr(void){ unsigned char r = 0xc; ring0_outb(r, pp_w9xring0_iobase + LPTREG_CONTROL); if ((ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & 0x3) == (r & 0x3)) { ring0_outb(r ^ 0x2, pp_w9xring0_iobase + LPTREG_CONTROL); /* Toggle bit 1 */ r = ring0_inb(pp_w9xring0_iobase + LPTREG_CONTROL); if ((ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & 0x2) == (r & 0x2)) goto no_reg; /* Sure that no ECR register exists */ } if ((ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & 0x3 ) != 0x1) goto no_reg; ring0_outb(0x34, pp_w9xring0_iobase + LPTREG_ECONTROL); if (ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) != 0x35) goto no_reg; ring0_outb(0xc, pp_w9xring0_iobase + LPTREG_CONTROL); /* Go to mode 000 */ ring0_outb(ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & ~0xe0, pp_w9xring0_iobase + LPTREG_ECONTROL); return PARPORT_MODE_PCECR; no_reg: ring0_outb(0xc, pp_w9xring0_iobase + LPTREG_CONTROL); return 0; }static int parport_ecp(void){ int i; int config; int pword; int fifo_depth, writeIntrThreshold, readIntrThreshold; /* Find out FIFO depth */ ring0_outb(0x00, pp_w9xring0_iobase + LPTREG_ECONTROL); /* Reset FIFO */ ring0_outb(0xc0, pp_w9xring0_iobase + LPTREG_ECONTROL); /* TEST FIFO */ for (i=0; i < 1024 && !(ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & 0x02); i++) ring0_outb(0xaa, pp_w9xring0_iobase + LPTREG_TFIFO); /* * Using LGS chipset it uses ECR register, but * it doesn't support ECP or FIFO MODE */ if (i == 1024) { ring0_outb(0x00, pp_w9xring0_iobase + LPTREG_ECONTROL); return 0; } fifo_depth = i; lprintf(3, "ECP: FIFO depth is %d bytes\n", fifo_depth); /* Find out writeIntrThreshold */ ring0_outb(ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) | (1<<2), pp_w9xring0_iobase + LPTREG_ECONTROL); ring0_outb(ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & ~(1<<2) , pp_w9xring0_iobase + LPTREG_ECONTROL); for (i = 1; i <= fifo_depth; i++) { ring0_inb(pp_w9xring0_iobase + LPTREG_TFIFO); usleep(50); if (ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & (1<<2)) break; } if (i <= fifo_depth) lprintf(3, "ECP: writeIntrThreshold is %d\n", i); else /* Number of bytes we know we can write if we get an interrupt. */ i = 0; writeIntrThreshold = i; /* Find out readIntrThreshold */ ring0_outb((ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & ~0xe0) | 0x20, pp_w9xring0_iobase + LPTREG_ECONTROL); /* Reset FIFO, PS2 */ ring0_outb(ring0_inb(pp_w9xring0_iobase + LPTREG_CONTROL) | PARPORT_CONTROL_DIRECTION, pp_w9xring0_iobase + LPTREG_CONTROL); ring0_outb((ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & ~0xe0) | 0xc0, pp_w9xring0_iobase + LPTREG_ECONTROL); /* Test FIFO */ ring0_outb(ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) | (1<<2), pp_w9xring0_iobase + LPTREG_ECONTROL); ring0_outb(ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & ~(1<<2) , pp_w9xring0_iobase + LPTREG_ECONTROL); for (i = 1; i <= fifo_depth; i++) { ring0_outb(0xaa, pp_w9xring0_iobase + LPTREG_TFIFO); if (ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & (1<<2)) break; } if (i <= fifo_depth) lprintf(3, "ECP: readIntrThreshold is %d\n", i); else /* Number of bytes we can read if we get an interrupt. */ i = 0; readIntrThreshold = i; ring0_outb(0x00, pp_w9xring0_iobase + LPTREG_ECONTROL); /* Reset FIFO */ ring0_outb(0xf4, pp_w9xring0_iobase + LPTREG_ECONTROL); /* Configuration mode */ config = ring0_inb(pp_w9xring0_iobase + LPTREG_CONFIGA); pword = (config >> 4) & 0x7; switch (pword) { case 0: pword = 2; lprintf(0, "ECP: Unsupported pword size! (2)\n"); break; case 2: pword = 4; lprintf(0, "ECP: Unsupported pword size! (4)\n"); break; default: lprintf(0, "ECP: Unknown implementation ID (%d)\n", pword); /* Assume 1 */ case 1: pword = 1; } lprintf(3, "ECP: PWord is %d bits\n", 8 * pword); config = ring0_inb(pp_w9xring0_iobase + LPTREG_CONFIGB); lprintf(3, "ECP: Interrupts are ISA-%s\n", config & 0x80 ? "Level" : "Pulses"); if (!(config & 0x40)) lprintf(3, "ECP: IRQ conflict!\n"); /* Go back to mode 000 */ ring0_outb(ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL) & ~0xe0, pp_w9xring0_iobase + LPTREG_ECONTROL); return PARPORT_MODE_PCECP;}/* EPP mode detection */static int parport_epp(void){ /* If EPP timeout bit clear then EPP available */ if (!pp_w9xring0_epp_clear_timeout()) return 0; /* No way to clear timeout */ /* * Theory: * Write two values to the EPP address register and * read them back. When the transfer times out, the state of * the EPP register is undefined in some cases (EPP 1.9?) but * in others (EPP 1.7, ECPEPP?) it is possible to read back * its value. */ pp_w9xring0_epp_clear_timeout(); usleep(30); /* Wait for possible EPP timeout */ ring0_outb(0x55, pp_w9xring0_iobase + LPTREG_EPPADDR); pp_w9xring0_epp_clear_timeout(); usleep(30); /* Wait for possible EPP timeout */ if (ring0_inb(pp_w9xring0_iobase + LPTREG_EPPADDR) == 0x55) { ring0_outb(0xaa, pp_w9xring0_iobase + LPTREG_EPPADDR); pp_w9xring0_epp_clear_timeout(); usleep(30); /* Wait for possible EPP timeout */ if (ring0_inb(pp_w9xring0_iobase + LPTREG_EPPADDR) == 0xaa) { pp_w9xring0_epp_clear_timeout(); return PARPORT_MODE_PCEPP; } } /* * Theory: * Bit 0 of STR is the EPP timeout bit, this bit is 0 * when EPP is possible and is set high when an EPP timeout * occurs (EPP uses the HALT line to stop the CPU while it does * the byte transfer, an EPP timeout occurs if the attached * device fails to respond after 10 micro seconds). * * This bit is cleared by either reading it (National Semi) * or writing a 1 to the bit (SMC, UMC, Wring0_inbond), others ??? * This bit is always high in non EPP modes. */ ring0_outb(ring0_inb(pp_w9xring0_iobase + LPTREG_CONTROL) | 0x20, pp_w9xring0_iobase + LPTREG_CONTROL); ring0_outb(ring0_inb(pp_w9xring0_iobase + LPTREG_CONTROL) | 0x10, pp_w9xring0_iobase + LPTREG_CONTROL); pp_w9xring0_epp_clear_timeout(); ring0_inb(pp_w9xring0_iobase + LPTREG_EPPDATA); usleep(30); /* Wait for possible EPP timeout */ if (ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & 0x01) { pp_w9xring0_epp_clear_timeout(); return PARPORT_MODE_PCEPP; } return 0;}static int parport_ecpepp(void){ int mode; unsigned char oecr; oecr = ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL); /* Search for SMC style EPP+ECP mode */ ring0_outb(0x80, pp_w9xring0_iobase + LPTREG_ECONTROL); mode = parport_epp(); ring0_outb(oecr, pp_w9xring0_iobase + LPTREG_ECONTROL); return mode ? PARPORT_MODE_PCECPEPP : 0;}/* Detect PS/2 support. * * Bit 5 (0x20) sets the PS/2 data w9xring0ion; setting this high * allows us to read data from the data lines. In theory we would get back * 0xff but any peripheral attached to the port may drag some or all of the * lines down to zero. So if we get back anything that isn't the contents * of the data register we deem PS/2 support to be present. * * Some SPP ports have "half PS/2" ability - you can't turn off the line * drivers, but an external peripheral with sufficiently beefy drivers of * its own can overpower them and assert its own levels onto the bus, from * where they can then be read back as normal. Ports with this property * and the right type of device attached are likely to fail the SPP test, * (as they will appear to have stuck bits) and so the fact that they might * be misdetected here is rather academic. */static int parport_ps2(void){ int ok = 0; unsigned char octr = ring0_inb(pp_w9xring0_iobase + LPTREG_CONTROL); pp_w9xring0_epp_clear_timeout(); ring0_outb(octr | 0x20, pp_w9xring0_iobase + LPTREG_CONTROL); /* try to tri-state the buffer */ ring0_outb(0x55, pp_w9xring0_iobase + LPTREG_DATA); if (ring0_inb(pp_w9xring0_iobase + LPTREG_DATA) != 0x55) ok++; ring0_outb(0xaa, pp_w9xring0_iobase + LPTREG_DATA); if (ring0_inb(pp_w9xring0_iobase + LPTREG_DATA) != 0xaa) ok++; ring0_outb(octr, pp_w9xring0_iobase); /* cancel input mode */ return ok ? PARPORT_MODE_PCPS2 : 0;}static int parport_ecpps2(void){ int mode; unsigned char oecr; oecr = ring0_inb(pp_w9xring0_iobase + LPTREG_ECONTROL); ring0_outb(0x20, pp_w9xring0_iobase + LPTREG_ECONTROL); mode = parport_ps2(); ring0_outb(oecr, pp_w9xring0_iobase + LPTREG_ECONTROL); return mode ? PARPORT_MODE_PCECPPS2 : 0;}/* ---------------------------------------------------------------------- */int parport_init_w9xring0_flags(unsigned io, unsigned int flags){ pp_w9xring0_flags = FLAGS_PCSPP; pp_w9xring0_iobase = io; if (iopl(3)) { lprintf(0, "Cannot get direct IO port access (iopl: %s)\n", strerror(errno)); return -1; } if (!parport_spp()) { lprintf(0, "No parport present at 0x%x\n", pp_w9xring0_iobase); return -1; } if (parport_ecr()) { pp_w9xring0_flags |= FLAGS_PCECR; pp_w9xring0_flags |= parport_ecp(); pp_w9xring0_flags |= parport_ecpps2(); pp_w9xring0_flags |= parport_ecpepp(); if ((flags & PPFLAG_FORCEHWEPP) && (pp_w9xring0_flags & (FLAGS_PCPS2|FLAGS_PCECPPS2)) && !(pp_w9xring0_flags & (FLAGS_PCEPP|FLAGS_PCECPEPP))) pp_w9xring0_flags |= FLAGS_PCECPEPP; else flags &= ~PPFLAG_FORCEHWEPP; } else { pp_w9xring0_flags |= parport_ps2(); pp_w9xring0_flags |= parport_epp(); if ((flags & PPFLAG_FORCEHWEPP) && (pp_w9xring0_flags & (FLAGS_PCPS2|FLAGS_PCECPPS2)) && !(pp_w9xring0_flags & (FLAGS_PCEPP|FLAGS_PCECPEPP))) pp_w9xring0_flags |= FLAGS_PCEPP; else flags &= ~PPFLAG_FORCEHWEPP; } lprintf(0, "Parport 0x%x capabilities: SPP%s%s%s%s%s%s\n", pp_w9xring0_iobase, (pp_w9xring0_flags & FLAGS_PCPS2) ? ", PS2" : "", (pp_w9xring0_flags & FLAGS_PCEPP) ? ((flags & PPFLAG_FORCEHWEPP) ? ", EPP (forced)" : ", EPP") : "", (pp_w9xring0_flags & FLAGS_PCECR) ? ", ECR" : "", (pp_w9xring0_flags & FLAGS_PCECP) ? ", ECP" : "", (pp_w9xring0_flags & FLAGS_PCECPEPP) ? ((flags & PPFLAG_FORCEHWEPP) ? ", ECPEPP (forced)" : ", ECPEPP") : "", (pp_w9xring0_flags & FLAGS_PCECPPS2) ? ", ECPPS2" : ""); if (!(pp_w9xring0_flags & (FLAGS_PCPS2 | FLAGS_PCECPPS2))) { lprintf(0, "Parport 0x%x does not even support PS/2 mode, cannot use it\n", pp_w9xring0_iobase); return -1; } lprintf(0, "Parport 0x%x using direct Win9x Ring0 hardware access\n", pp_w9xring0_iobase); if (pp_w9xring0_flags & FLAGS_PCECR) ring0_outb(0x30, pp_w9xring0_iobase + LPTREG_ECONTROL); /* PS/2 mode */ parport_ops = parport_w9xring0_ops; if ((flags & PPFLAG_SWEMULECP) || !(pp_w9xring0_flags & FLAGS_PCECP)) { parport_ops.parport_ecp_write_data = parport_w9xring0_emul_ops.parport_ecp_write_data; parport_ops.parport_ecp_read_data = parport_w9xring0_emul_ops.parport_ecp_read_data; parport_ops.parport_ecp_write_addr = parport_w9xring0_emul_ops.parport_ecp_write_addr; lprintf(0, "Parport 0x%x emulating ECP\n", pp_w9xring0_iobase); } if ((flags & PPFLAG_SWEMULEPP) || !(pp_w9xring0_flags & (FLAGS_PCEPP | FLAGS_PCECPEPP))) { parport_ops.parport_epp_write_data = parport_w9xring0_emul_ops.parport_epp_write_data; parport_ops.parport_epp_read_data = parport_w9xring0_emul_ops.parport_epp_read_data; parport_ops.parport_epp_write_addr = parport_w9xring0_emul_ops.parport_epp_write_addr; parport_ops.parport_epp_read_addr = parport_w9xring0_emul_ops.parport_epp_read_addr; lprintf(0, "Parport 0x%x emulating EPP\n", pp_w9xring0_iobase); } return 0;}int parport_init_w9xring0(unsigned io){ return parport_init_w9xring0_flags(io, 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -