lpt_pioc.c revision 1.3 1 /* $NetBSD: lpt_pioc.c,v 1.3 2002/02/17 23:45:29 bjh21 Exp $ */
2
3 /*
4 * Copyright (c) 1997 Mark Brinicombe
5 * Copyright (c) 1997 Causality Limited
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. The name of the company nor the name of the author may be used to
17 * endorse or promote products derived from this software without specific
18 * prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
21 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTERS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * Device Driver for AT parallel printer port
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <machine/bus.h>
42 #include <machine/intr.h>
43 #include <acorn32/mainbus/piocvar.h>
44 #include <dev/ic/lptreg.h>
45 #include <dev/ic/lptvar.h>
46
47 #include "locators.h"
48
49 /* Prototypes for functions */
50
51 static int lpt_port_test __P((bus_space_tag_t, bus_space_handle_t, bus_addr_t,
52 bus_size_t, u_char, u_char));
53 static int lptprobe __P((bus_space_tag_t, u_int));
54 static int lpt_pioc_probe __P((struct device *, struct cfdata *, void *));
55 static void lpt_pioc_attach __P((struct device *, struct device *, void *));
56
57 /* device attach structure */
58
59 struct cfattach lpt_pioc_ca = {
60 sizeof(struct lpt_softc), lpt_pioc_probe, lpt_pioc_attach
61 };
62
63 /*
64 * Internal routine to lptprobe to do port tests of one byte value.
65 */
66 static int
67 lpt_port_test(iot, ioh, base, off, data, mask)
68 bus_space_tag_t iot;
69 bus_space_handle_t ioh;
70 bus_addr_t base;
71 bus_size_t off;
72 u_char data, mask;
73 {
74 int timeout;
75 u_char temp;
76
77 data &= mask;
78 bus_space_write_1(iot, ioh, off, data);
79 timeout = 1000;
80 do {
81 delay(10);
82 temp = bus_space_read_1(iot, ioh, off) & mask;
83 } while (temp != data && --timeout);
84 return (temp == data);
85 }
86
87 /*
88 * Logic:
89 * 1) You should be able to write to and read back the same value
90 * to the data port. Do an alternating zeros, alternating ones,
91 * walking zero, and walking one test to check for stuck bits.
92 *
93 * 2) You should be able to write to and read back the same value
94 * to the control port lower 5 bits, the upper 3 bits are reserved
95 * per the IBM PC technical reference manauls and different boards
96 * do different things with them. Do an alternating zeros, alternating
97 * ones, walking zero, and walking one test to check for stuck bits.
98 *
99 * Some printers drag the strobe line down when the are powered off
100 * so this bit has been masked out of the control port test.
101 *
102 * XXX Some printers may not like a fast pulse on init or strobe, I
103 * don't know at this point, if that becomes a problem these bits
104 * should be turned off in the mask byte for the control port test.
105 *
106 * 3) Set the data and control ports to a value of 0
107 */
108 static int
109 lptprobe(iot, iobase)
110 bus_space_tag_t iot;
111 u_int iobase;
112 {
113 bus_space_handle_t ioh;
114 u_char mask, data;
115 int i, rv;
116 #ifdef DEBUG
117 #define ABORT do {printf("lptprobe: mask %x data %x failed\n", mask, data); \
118 goto out;} while (0)
119 #else
120 #define ABORT goto out
121 #endif
122
123 if (bus_space_map(iot, iobase, LPT_NPORTS, 0, &ioh))
124 return 0;
125 rv = 0;
126 mask = 0xff;
127
128 data = 0x55; /* Alternating zeros */
129 if (!lpt_port_test(iot, ioh, iobase, lpt_data, data, mask))
130 ABORT;
131
132 data = 0xaa; /* Alternating ones */
133 if (!lpt_port_test(iot, ioh, iobase, lpt_data, data, mask))
134 ABORT;
135
136 for (i = 0; i < CHAR_BIT; i++) { /* Walking zero */
137 data = ~(1 << i);
138 if (!lpt_port_test(iot, ioh, iobase, lpt_data, data, mask))
139 ABORT;
140 }
141
142 for (i = 0; i < CHAR_BIT; i++) { /* Walking one */
143 data = (1 << i);
144 if (!lpt_port_test(iot, ioh, iobase, lpt_data, data, mask))
145 ABORT;
146 }
147
148 bus_space_write_1(iot, ioh, lpt_data, 0);
149 bus_space_write_1(iot, ioh, lpt_control, 0);
150
151 rv = LPT_NPORTS;
152
153 out:
154 bus_space_unmap(iot, ioh, LPT_NPORTS);
155 return rv;
156 }
157
158 /*
159 * int lpt_pioc_probe(struct device *parent, struct cfdata *cf, void *aux)
160 *
161 * Make sure we are trying to attach a lpt device and then
162 * probe for one.
163 */
164
165 static int
166 lpt_pioc_probe(parent, match, aux)
167 struct device *parent;
168 struct cfdata *match;
169 void *aux;
170 {
171 struct pioc_attach_args *pa = aux;
172 int rv;
173
174 if (pa->pa_name && strcmp(pa->pa_name, "lpt") != 0)
175 return(0);
176
177 /* We need an offset */
178 if (pa->pa_offset == PIOCCF_OFFSET_DEFAULT)
179 return(0);
180
181 rv = lptprobe(pa->pa_iot, pa->pa_iobase + pa->pa_offset);
182
183 if (rv) {
184 pa->pa_iosize = rv;
185 return(1);
186 }
187 return(0);
188 }
189
190 /*
191 * void lpt_pioc_attach(struct device *parent, struct device *self, void *aux)
192 *
193 * attach the lpt device
194 */
195
196 static void
197 lpt_pioc_attach(parent, self, aux)
198 struct device *parent, *self;
199 void *aux;
200 {
201 struct lpt_softc *sc = (void *)self;
202 struct pioc_attach_args *pa = aux;
203 bus_space_tag_t iot;
204 bus_space_handle_t ioh;
205 u_int iobase;
206
207 if (pa->pa_irq != MAINBUSCF_IRQ_DEFAULT)
208 printf("\n");
209 else
210 printf(": polled\n");
211
212 iobase = pa->pa_iobase + pa->pa_offset;
213
214 iot = sc->sc_iot = pa->pa_iot;
215 if (bus_space_map(iot, iobase, LPT_NPORTS, 0, &ioh))
216 panic("lptattach: couldn't map I/O ports");
217 sc->sc_ioh = ioh;
218
219 lpt_attach_subr(sc);
220
221 if (pa->pa_irq != MAINBUSCF_IRQ_DEFAULT)
222 sc->sc_ih = intr_claim(pa->pa_irq, IPL_TTY, "lpt",
223 lptintr, sc);
224 }
225
226 /* End of lpt_pioc.c */
227