| 1 | /* $NetBSD: lpt_isa.c,v 1.68 2009/11/23 02:13:47 rmind Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 1993, 1994 Charles M. Hannum. |
| 5 | * Copyright (c) 1990 William F. Jolitz, TeleMuse |
| 6 | * All rights reserved. |
| 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without |
| 9 | * modification, are permitted provided that the following conditions |
| 10 | * are met: |
| 11 | * 1. Redistributions of source code must retain the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer. |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer in the |
| 15 | * documentation and/or other materials provided with the distribution. |
| 16 | * 3. All advertising materials mentioning features or use of this software |
| 17 | * must display the following acknowledgement: |
| 18 | * This software is a component of "386BSD" developed by |
| 19 | * William F. Jolitz, TeleMuse. |
| 20 | * 4. Neither the name of the developer nor the name "386BSD" |
| 21 | * may be used to endorse or promote products derived from this software |
| 22 | * without specific prior written permission. |
| 23 | * |
| 24 | * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ |
| 25 | * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS |
| 26 | * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. |
| 27 | * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT |
| 28 | * NOT MAKE USE OF THIS WORK. |
| 29 | * |
| 30 | * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED |
| 31 | * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN |
| 32 | * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES |
| 33 | * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING |
| 34 | * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND |
| 35 | * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE |
| 36 | * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS |
| 37 | * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. |
| 38 | * |
| 39 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND |
| 40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 42 | * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE |
| 43 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 44 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 45 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 47 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 48 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 49 | * SUCH DAMAGE. |
| 50 | */ |
| 51 | |
| 52 | /* |
| 53 | * Device Driver for AT parallel printer port |
| 54 | */ |
| 55 | |
| 56 | #include <sys/cdefs.h> |
| 57 | __KERNEL_RCSID(0, "$NetBSD: lpt_isa.c,v 1.68 2009/11/23 02:13:47 rmind Exp $" ); |
| 58 | |
| 59 | #include <sys/param.h> |
| 60 | #include <sys/systm.h> |
| 61 | #include <sys/proc.h> |
| 62 | #include <sys/buf.h> |
| 63 | #include <sys/kernel.h> |
| 64 | #include <sys/ioctl.h> |
| 65 | #include <sys/uio.h> |
| 66 | #include <sys/device.h> |
| 67 | #include <sys/syslog.h> |
| 68 | |
| 69 | #include <sys/bus.h> |
| 70 | #include <sys/intr.h> |
| 71 | |
| 72 | #include <dev/isa/isavar.h> |
| 73 | #include <dev/ic/lptreg.h> |
| 74 | #include <dev/ic/lptvar.h> |
| 75 | |
| 76 | #define LPTPRI (PZERO+8) |
| 77 | #define LPT_BSIZE 1024 |
| 78 | |
| 79 | #ifndef LPTDEBUG |
| 80 | #define LPRINTF(a) |
| 81 | #else |
| 82 | #define LPRINTF(a) if (lpt_isa_debug) printf a |
| 83 | int lpt_isa_debug = 0; |
| 84 | #endif |
| 85 | |
| 86 | struct lpt_isa_softc { |
| 87 | struct lpt_softc sc_lpt; |
| 88 | int sc_irq; |
| 89 | isa_chipset_tag_t sc_ic; |
| 90 | |
| 91 | }; |
| 92 | |
| 93 | int lpt_isa_probe(device_t, cfdata_t, void *); |
| 94 | static void lpt_isa_attach(device_t, device_t, void *); |
| 95 | static int lpt_isa_detach(device_t, int); |
| 96 | |
| 97 | CFATTACH_DECL_NEW(lpt_isa, sizeof(struct lpt_isa_softc), |
| 98 | lpt_isa_probe, lpt_isa_attach, lpt_isa_detach, NULL); |
| 99 | |
| 100 | int lpt_port_test(bus_space_tag_t, bus_space_handle_t, bus_addr_t, |
| 101 | bus_size_t, u_char, u_char); |
| 102 | |
| 103 | /* |
| 104 | * Internal routine to lptprobe to do port tests of one byte value. |
| 105 | */ |
| 106 | int |
| 107 | lpt_port_test(bus_space_tag_t iot, bus_space_handle_t ioh, |
| 108 | bus_addr_t base, bus_size_t off, u_char data, u_char mask) |
| 109 | { |
| 110 | int timeout; |
| 111 | u_char temp; |
| 112 | |
| 113 | data &= mask; |
| 114 | bus_space_write_1(iot, ioh, off, data); |
| 115 | timeout = 1000; |
| 116 | do { |
| 117 | delay(10); |
| 118 | temp = bus_space_read_1(iot, ioh, off) & mask; |
| 119 | } while (temp != data && --timeout); |
| 120 | LPRINTF(("lpt: port=0x%x out=0x%x in=0x%x timeout=%d\n" , |
| 121 | (unsigned)(base + off), (unsigned)data, (unsigned)temp, timeout)); |
| 122 | return (temp == data); |
| 123 | } |
| 124 | |
| 125 | /* |
| 126 | * Logic: |
| 127 | * 1) You should be able to write to and read back the same value |
| 128 | * to the data port. Do an alternating zeros, alternating ones, |
| 129 | * walking zero, and walking one test to check for stuck bits. |
| 130 | * |
| 131 | * 2) You should be able to write to and read back the same value |
| 132 | * to the control port lower 5 bits, the upper 3 bits are reserved |
| 133 | * per the IBM PC technical reference manauls and different boards |
| 134 | * do different things with them. Do an alternating zeros, alternating |
| 135 | * ones, walking zero, and walking one test to check for stuck bits. |
| 136 | * |
| 137 | * Some printers drag the strobe line down when the are powered off |
| 138 | * so this bit has been masked out of the control port test. |
| 139 | * |
| 140 | * XXX Some printers may not like a fast pulse on init or strobe, I |
| 141 | * don't know at this point, if that becomes a problem these bits |
| 142 | * should be turned off in the mask byte for the control port test. |
| 143 | * |
| 144 | * 3) Set the data and control ports to a value of 0 |
| 145 | */ |
| 146 | int |
| 147 | lpt_isa_probe(device_t parent, cfdata_t match, void *aux) |
| 148 | { |
| 149 | struct isa_attach_args *ia = aux; |
| 150 | bus_space_tag_t iot; |
| 151 | bus_space_handle_t ioh; |
| 152 | u_long base; |
| 153 | u_char mask, data; |
| 154 | int i, rv; |
| 155 | |
| 156 | #ifdef LPT_DEBUG |
| 157 | #define ABORT do {printf("lptprobe: mask %x data %x failed\n", mask, data); \ |
| 158 | goto out;} while (0) |
| 159 | #else |
| 160 | #define ABORT goto out |
| 161 | #endif |
| 162 | |
| 163 | if (ia->ia_nio < 1) |
| 164 | return (0); |
| 165 | |
| 166 | if (ISA_DIRECT_CONFIG(ia)) |
| 167 | return (0); |
| 168 | |
| 169 | /* Disallow wildcarded i/o address. */ |
| 170 | if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) |
| 171 | return (0); |
| 172 | |
| 173 | iot = ia->ia_iot; |
| 174 | base = ia->ia_io[0].ir_addr; |
| 175 | if (bus_space_map(iot, base, LPT_NPORTS, 0, &ioh)) |
| 176 | return 0; |
| 177 | |
| 178 | rv = 0; |
| 179 | mask = 0xff; |
| 180 | |
| 181 | data = 0x55; /* Alternating zeros */ |
| 182 | if (!lpt_port_test(iot, ioh, base, lpt_data, data, mask)) |
| 183 | ABORT; |
| 184 | |
| 185 | data = 0xaa; /* Alternating ones */ |
| 186 | if (!lpt_port_test(iot, ioh, base, lpt_data, data, mask)) |
| 187 | ABORT; |
| 188 | |
| 189 | for (i = 0; i < CHAR_BIT; i++) { /* Walking zero */ |
| 190 | data = ~(1 << i); |
| 191 | if (!lpt_port_test(iot, ioh, base, lpt_data, data, mask)) |
| 192 | ABORT; |
| 193 | } |
| 194 | |
| 195 | for (i = 0; i < CHAR_BIT; i++) { /* Walking one */ |
| 196 | data = (1 << i); |
| 197 | if (!lpt_port_test(iot, ioh, base, lpt_data, data, mask)) |
| 198 | ABORT; |
| 199 | } |
| 200 | |
| 201 | bus_space_write_1(iot, ioh, lpt_data, 0); |
| 202 | bus_space_write_1(iot, ioh, lpt_control, 0); |
| 203 | |
| 204 | ia->ia_io[0].ir_size = LPT_NPORTS; |
| 205 | |
| 206 | ia->ia_niomem = 0; |
| 207 | ia->ia_ndrq = 0; |
| 208 | |
| 209 | rv = 1; |
| 210 | |
| 211 | out: |
| 212 | bus_space_unmap(iot, ioh, LPT_NPORTS); |
| 213 | return rv; |
| 214 | } |
| 215 | |
| 216 | void |
| 217 | lpt_isa_attach(device_t parent, device_t self, void *aux) |
| 218 | { |
| 219 | struct lpt_isa_softc *sc = device_private(self); |
| 220 | struct lpt_softc *lsc = &sc->sc_lpt; |
| 221 | struct isa_attach_args *ia = aux; |
| 222 | bus_space_tag_t iot; |
| 223 | bus_space_handle_t ioh; |
| 224 | |
| 225 | lsc->sc_dev = self; |
| 226 | |
| 227 | if (ia->ia_nirq < 1 || |
| 228 | ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ) { |
| 229 | sc->sc_irq = -1; |
| 230 | aprint_normal(": polled\n" ); |
| 231 | } else { |
| 232 | sc->sc_irq = ia->ia_irq[0].ir_irq; |
| 233 | aprint_normal("\n" ); |
| 234 | } |
| 235 | |
| 236 | if (!pmf_device_register(self, NULL, NULL)) |
| 237 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
| 238 | |
| 239 | iot = lsc->sc_iot = ia->ia_iot; |
| 240 | if (bus_space_map(iot, ia->ia_io[0].ir_addr, LPT_NPORTS, 0, &ioh)) { |
| 241 | aprint_normal_dev(self, "can't map i/o space\n" ); |
| 242 | return; |
| 243 | } |
| 244 | lsc->sc_ioh = ioh; |
| 245 | |
| 246 | lpt_attach_subr(lsc); |
| 247 | |
| 248 | sc->sc_ic = ia->ia_ic; |
| 249 | if (sc->sc_irq != -1) |
| 250 | lsc->sc_ih = isa_intr_establish(sc->sc_ic, sc->sc_irq, |
| 251 | IST_EDGE, IPL_TTY, lptintr, lsc); |
| 252 | } |
| 253 | |
| 254 | static int |
| 255 | lpt_isa_detach(device_t self, int flags) |
| 256 | { |
| 257 | int rc; |
| 258 | struct lpt_isa_softc *sc = device_private(self); |
| 259 | struct lpt_softc *lsc = &sc->sc_lpt; |
| 260 | |
| 261 | if ((rc = lpt_detach_subr(self, flags)) != 0) |
| 262 | return rc; |
| 263 | |
| 264 | if (sc->sc_irq != -1) |
| 265 | isa_intr_disestablish(sc->sc_ic, lsc->sc_ih); |
| 266 | |
| 267 | bus_space_unmap(lsc->sc_iot, lsc->sc_ioh, LPT_NPORTS); |
| 268 | return 0; |
| 269 | } |
| 270 | |