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 | |