pckbc.c revision 1.5.4.3 1 1.5.4.3 bouyer /* $NetBSD: pckbc.c,v 1.5.4.3 2001/04/21 17:48:42 bouyer Exp $ */
2 1.5.4.2 bouyer
3 1.5.4.2 bouyer /*
4 1.5.4.2 bouyer * Copyright (c) 1998
5 1.5.4.2 bouyer * Matthias Drochner. All rights reserved.
6 1.5.4.2 bouyer *
7 1.5.4.2 bouyer * Redistribution and use in source and binary forms, with or without
8 1.5.4.2 bouyer * modification, are permitted provided that the following conditions
9 1.5.4.2 bouyer * are met:
10 1.5.4.2 bouyer * 1. Redistributions of source code must retain the above copyright
11 1.5.4.2 bouyer * notice, this list of conditions and the following disclaimer.
12 1.5.4.2 bouyer * 2. Redistributions in binary form must reproduce the above copyright
13 1.5.4.2 bouyer * notice, this list of conditions and the following disclaimer in the
14 1.5.4.2 bouyer * documentation and/or other materials provided with the distribution.
15 1.5.4.2 bouyer * 3. All advertising materials mentioning features or use of this software
16 1.5.4.2 bouyer * must display the following acknowledgement:
17 1.5.4.2 bouyer * This product includes software developed for the NetBSD Project
18 1.5.4.2 bouyer * by Matthias Drochner.
19 1.5.4.2 bouyer * 4. The name of the author may not be used to endorse or promote products
20 1.5.4.2 bouyer * derived from this software without specific prior written permission.
21 1.5.4.2 bouyer *
22 1.5.4.2 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 1.5.4.2 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 1.5.4.2 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 1.5.4.2 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 1.5.4.2 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 1.5.4.2 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 1.5.4.2 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 1.5.4.2 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 1.5.4.2 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 1.5.4.2 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 1.5.4.2 bouyer */
33 1.5.4.2 bouyer
34 1.5.4.2 bouyer #include <sys/param.h>
35 1.5.4.2 bouyer #include <sys/systm.h>
36 1.5.4.2 bouyer #include <sys/callout.h>
37 1.5.4.2 bouyer #include <sys/kernel.h>
38 1.5.4.2 bouyer #include <sys/proc.h>
39 1.5.4.2 bouyer #include <sys/device.h>
40 1.5.4.2 bouyer #include <sys/malloc.h>
41 1.5.4.2 bouyer #include <sys/errno.h>
42 1.5.4.2 bouyer #include <sys/queue.h>
43 1.5.4.2 bouyer #include <sys/lock.h>
44 1.5.4.2 bouyer
45 1.5.4.2 bouyer #include <machine/bus.h>
46 1.5.4.2 bouyer
47 1.5.4.2 bouyer #include <dev/ic/i8042reg.h>
48 1.5.4.2 bouyer #include <dev/ic/pckbcvar.h>
49 1.5.4.2 bouyer
50 1.5.4.2 bouyer #include "rnd.h"
51 1.5.4.2 bouyer #include "locators.h"
52 1.5.4.2 bouyer
53 1.5.4.2 bouyer #ifdef __HAVE_NWSCONS /* XXX: this port uses sys/dev/pckbc */
54 1.5.4.2 bouyer #include "pckbd.h"
55 1.5.4.2 bouyer #else /* ie: only md drivers attach to pckbc */
56 1.5.4.2 bouyer #define NPCKBD 0
57 1.5.4.2 bouyer #endif
58 1.5.4.2 bouyer #if (NPCKBD > 0)
59 1.5.4.2 bouyer #include <dev/pckbc/pckbdvar.h>
60 1.5.4.2 bouyer #endif
61 1.5.4.2 bouyer #if NRND > 0
62 1.5.4.2 bouyer #include <sys/rnd.h>
63 1.5.4.2 bouyer #endif
64 1.5.4.2 bouyer
65 1.5.4.2 bouyer /* descriptor for one device command */
66 1.5.4.2 bouyer struct pckbc_devcmd {
67 1.5.4.2 bouyer TAILQ_ENTRY(pckbc_devcmd) next;
68 1.5.4.2 bouyer int flags;
69 1.5.4.2 bouyer #define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */
70 1.5.4.2 bouyer #define KBC_CMDFLAG_SLOW 2
71 1.5.4.2 bouyer u_char cmd[4];
72 1.5.4.2 bouyer int cmdlen, cmdidx, retries;
73 1.5.4.2 bouyer u_char response[4];
74 1.5.4.2 bouyer int status, responselen, responseidx;
75 1.5.4.2 bouyer };
76 1.5.4.2 bouyer
77 1.5.4.2 bouyer /* data per slave device */
78 1.5.4.2 bouyer struct pckbc_slotdata {
79 1.5.4.2 bouyer int polling; /* don't read data port in interrupt handler */
80 1.5.4.2 bouyer TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */
81 1.5.4.2 bouyer TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */
82 1.5.4.2 bouyer #define NCMD 5
83 1.5.4.2 bouyer struct pckbc_devcmd cmds[NCMD];
84 1.5.4.2 bouyer #if NRND > 0
85 1.5.4.2 bouyer rndsource_element_t rnd_source;
86 1.5.4.2 bouyer #endif
87 1.5.4.2 bouyer };
88 1.5.4.2 bouyer
89 1.5.4.2 bouyer #define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL)
90 1.5.4.2 bouyer
91 1.5.4.2 bouyer void pckbc_init_slotdata __P((struct pckbc_slotdata *));
92 1.5.4.2 bouyer int pckbc_attach_slot __P((struct pckbc_softc *, pckbc_slot_t));
93 1.5.4.2 bouyer int pckbc_submatch __P((struct device *, struct cfdata *, void *));
94 1.5.4.2 bouyer int pckbcprint __P((void *, const char *));
95 1.5.4.2 bouyer
96 1.5.4.2 bouyer struct pckbc_internal pckbc_consdata;
97 1.5.4.2 bouyer int pckbc_console_attached;
98 1.5.4.2 bouyer
99 1.5.4.2 bouyer static int pckbc_console;
100 1.5.4.2 bouyer static struct pckbc_slotdata pckbc_cons_slotdata;
101 1.5.4.2 bouyer
102 1.5.4.2 bouyer static int pckbc_wait_output __P((bus_space_tag_t, bus_space_handle_t));
103 1.5.4.2 bouyer
104 1.5.4.2 bouyer static int pckbc_get8042cmd __P((struct pckbc_internal *));
105 1.5.4.2 bouyer static int pckbc_put8042cmd __P((struct pckbc_internal *));
106 1.5.4.2 bouyer static int pckbc_send_devcmd __P((struct pckbc_internal *, pckbc_slot_t,
107 1.5.4.2 bouyer u_char));
108 1.5.4.2 bouyer static void pckbc_poll_cmd1 __P((struct pckbc_internal *, pckbc_slot_t,
109 1.5.4.2 bouyer struct pckbc_devcmd *));
110 1.5.4.2 bouyer
111 1.5.4.2 bouyer void pckbc_cleanqueue __P((struct pckbc_slotdata *));
112 1.5.4.2 bouyer void pckbc_cleanup __P((void *));
113 1.5.4.2 bouyer int pckbc_cmdresponse __P((struct pckbc_internal *, pckbc_slot_t, u_char));
114 1.5.4.2 bouyer void pckbc_start __P((struct pckbc_internal *, pckbc_slot_t));
115 1.5.4.2 bouyer
116 1.5.4.2 bouyer const char *pckbc_slot_names[] = { "kbd", "aux" };
117 1.5.4.2 bouyer
118 1.5.4.2 bouyer #define KBC_DEVCMD_ACK 0xfa
119 1.5.4.2 bouyer #define KBC_DEVCMD_RESEND 0xfe
120 1.5.4.2 bouyer
121 1.5.4.2 bouyer #define KBD_DELAY DELAY(8)
122 1.5.4.2 bouyer
123 1.5.4.2 bouyer static inline int
124 1.5.4.2 bouyer pckbc_wait_output(iot, ioh_c)
125 1.5.4.2 bouyer bus_space_tag_t iot;
126 1.5.4.2 bouyer bus_space_handle_t ioh_c;
127 1.5.4.2 bouyer {
128 1.5.4.2 bouyer u_int i;
129 1.5.4.2 bouyer
130 1.5.4.2 bouyer for (i = 100000; i; i--)
131 1.5.4.2 bouyer if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
132 1.5.4.2 bouyer KBD_DELAY;
133 1.5.4.2 bouyer return (1);
134 1.5.4.2 bouyer }
135 1.5.4.2 bouyer return (0);
136 1.5.4.2 bouyer }
137 1.5.4.2 bouyer
138 1.5.4.2 bouyer int
139 1.5.4.2 bouyer pckbc_send_cmd(iot, ioh_c, val)
140 1.5.4.2 bouyer bus_space_tag_t iot;
141 1.5.4.2 bouyer bus_space_handle_t ioh_c;
142 1.5.4.2 bouyer u_char val;
143 1.5.4.2 bouyer {
144 1.5.4.2 bouyer if (!pckbc_wait_output(iot, ioh_c))
145 1.5.4.2 bouyer return (0);
146 1.5.4.2 bouyer bus_space_write_1(iot, ioh_c, 0, val);
147 1.5.4.2 bouyer return (1);
148 1.5.4.2 bouyer }
149 1.5.4.2 bouyer
150 1.5.4.2 bouyer int
151 1.5.4.2 bouyer pckbc_poll_data1(iot, ioh_d, ioh_c, slot, checkaux)
152 1.5.4.2 bouyer bus_space_tag_t iot;
153 1.5.4.2 bouyer bus_space_handle_t ioh_d, ioh_c;
154 1.5.4.2 bouyer pckbc_slot_t slot;
155 1.5.4.2 bouyer int checkaux;
156 1.5.4.2 bouyer {
157 1.5.4.2 bouyer int i;
158 1.5.4.2 bouyer u_char stat;
159 1.5.4.2 bouyer
160 1.5.4.2 bouyer /* if 1 port read takes 1us (?), this polls for 100ms */
161 1.5.4.2 bouyer for (i = 100000; i; i--) {
162 1.5.4.2 bouyer stat = bus_space_read_1(iot, ioh_c, 0);
163 1.5.4.2 bouyer if (stat & KBS_DIB) {
164 1.5.4.2 bouyer register u_char c;
165 1.5.4.2 bouyer
166 1.5.4.2 bouyer KBD_DELAY;
167 1.5.4.2 bouyer c = bus_space_read_1(iot, ioh_d, 0);
168 1.5.4.2 bouyer if (checkaux && (stat & 0x20)) { /* aux data */
169 1.5.4.2 bouyer if (slot != PCKBC_AUX_SLOT) {
170 1.5.4.2 bouyer #ifdef PCKBCDEBUG
171 1.5.4.2 bouyer printf("lost aux 0x%x\n", c);
172 1.5.4.2 bouyer #endif
173 1.5.4.2 bouyer continue;
174 1.5.4.2 bouyer }
175 1.5.4.2 bouyer } else {
176 1.5.4.2 bouyer if (slot == PCKBC_AUX_SLOT) {
177 1.5.4.2 bouyer #ifdef PCKBCDEBUG
178 1.5.4.2 bouyer printf("lost kbd 0x%x\n", c);
179 1.5.4.2 bouyer #endif
180 1.5.4.2 bouyer continue;
181 1.5.4.2 bouyer }
182 1.5.4.2 bouyer }
183 1.5.4.2 bouyer return (c);
184 1.5.4.2 bouyer }
185 1.5.4.2 bouyer }
186 1.5.4.2 bouyer return (-1);
187 1.5.4.2 bouyer }
188 1.5.4.2 bouyer
189 1.5.4.2 bouyer /*
190 1.5.4.2 bouyer * Get the current command byte.
191 1.5.4.2 bouyer */
192 1.5.4.2 bouyer static int
193 1.5.4.2 bouyer pckbc_get8042cmd(t)
194 1.5.4.2 bouyer struct pckbc_internal *t;
195 1.5.4.2 bouyer {
196 1.5.4.2 bouyer bus_space_tag_t iot = t->t_iot;
197 1.5.4.2 bouyer bus_space_handle_t ioh_d = t->t_ioh_d;
198 1.5.4.2 bouyer bus_space_handle_t ioh_c = t->t_ioh_c;
199 1.5.4.2 bouyer int data;
200 1.5.4.2 bouyer
201 1.5.4.2 bouyer if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
202 1.5.4.2 bouyer return (0);
203 1.5.4.2 bouyer data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT,
204 1.5.4.2 bouyer t->t_haveaux);
205 1.5.4.2 bouyer if (data == -1)
206 1.5.4.2 bouyer return (0);
207 1.5.4.2 bouyer t->t_cmdbyte = data;
208 1.5.4.2 bouyer return (1);
209 1.5.4.2 bouyer }
210 1.5.4.2 bouyer
211 1.5.4.2 bouyer /*
212 1.5.4.2 bouyer * Pass command byte to keyboard controller (8042).
213 1.5.4.2 bouyer */
214 1.5.4.2 bouyer static int
215 1.5.4.2 bouyer pckbc_put8042cmd(t)
216 1.5.4.2 bouyer struct pckbc_internal *t;
217 1.5.4.2 bouyer {
218 1.5.4.2 bouyer bus_space_tag_t iot = t->t_iot;
219 1.5.4.2 bouyer bus_space_handle_t ioh_d = t->t_ioh_d;
220 1.5.4.2 bouyer bus_space_handle_t ioh_c = t->t_ioh_c;
221 1.5.4.2 bouyer
222 1.5.4.2 bouyer if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
223 1.5.4.2 bouyer return (0);
224 1.5.4.2 bouyer if (!pckbc_wait_output(iot, ioh_c))
225 1.5.4.2 bouyer return (0);
226 1.5.4.2 bouyer bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
227 1.5.4.2 bouyer return (1);
228 1.5.4.2 bouyer }
229 1.5.4.2 bouyer
230 1.5.4.2 bouyer static int
231 1.5.4.2 bouyer pckbc_send_devcmd(t, slot, val)
232 1.5.4.2 bouyer struct pckbc_internal *t;
233 1.5.4.2 bouyer pckbc_slot_t slot;
234 1.5.4.2 bouyer u_char val;
235 1.5.4.2 bouyer {
236 1.5.4.2 bouyer bus_space_tag_t iot = t->t_iot;
237 1.5.4.2 bouyer bus_space_handle_t ioh_d = t->t_ioh_d;
238 1.5.4.2 bouyer bus_space_handle_t ioh_c = t->t_ioh_c;
239 1.5.4.2 bouyer
240 1.5.4.2 bouyer if (slot == PCKBC_AUX_SLOT) {
241 1.5.4.2 bouyer if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
242 1.5.4.2 bouyer return (0);
243 1.5.4.2 bouyer }
244 1.5.4.2 bouyer if (!pckbc_wait_output(iot, ioh_c))
245 1.5.4.2 bouyer return (0);
246 1.5.4.2 bouyer bus_space_write_1(iot, ioh_d, 0, val);
247 1.5.4.2 bouyer return (1);
248 1.5.4.2 bouyer }
249 1.5.4.2 bouyer
250 1.5.4.2 bouyer int
251 1.5.4.2 bouyer pckbc_is_console(iot, addr)
252 1.5.4.2 bouyer bus_space_tag_t iot;
253 1.5.4.2 bouyer bus_addr_t addr;
254 1.5.4.2 bouyer {
255 1.5.4.2 bouyer if (pckbc_console && !pckbc_console_attached &&
256 1.5.4.2 bouyer pckbc_consdata.t_iot == iot &&
257 1.5.4.2 bouyer pckbc_consdata.t_addr == addr)
258 1.5.4.2 bouyer return (1);
259 1.5.4.2 bouyer return (0);
260 1.5.4.2 bouyer }
261 1.5.4.2 bouyer
262 1.5.4.2 bouyer int
263 1.5.4.2 bouyer pckbc_submatch(parent, cf, aux)
264 1.5.4.2 bouyer struct device *parent;
265 1.5.4.2 bouyer struct cfdata *cf;
266 1.5.4.2 bouyer void *aux;
267 1.5.4.2 bouyer {
268 1.5.4.2 bouyer struct pckbc_attach_args *pa = aux;
269 1.5.4.2 bouyer
270 1.5.4.2 bouyer if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT &&
271 1.5.4.2 bouyer cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot)
272 1.5.4.2 bouyer return (0);
273 1.5.4.2 bouyer return ((*cf->cf_attach->ca_match)(parent, cf, aux));
274 1.5.4.2 bouyer }
275 1.5.4.2 bouyer
276 1.5.4.2 bouyer int
277 1.5.4.2 bouyer pckbc_attach_slot(sc, slot)
278 1.5.4.2 bouyer struct pckbc_softc *sc;
279 1.5.4.2 bouyer pckbc_slot_t slot;
280 1.5.4.2 bouyer {
281 1.5.4.2 bouyer struct pckbc_internal *t = sc->id;
282 1.5.4.2 bouyer struct pckbc_attach_args pa;
283 1.5.4.2 bouyer int found;
284 1.5.4.2 bouyer
285 1.5.4.2 bouyer pa.pa_tag = t;
286 1.5.4.2 bouyer pa.pa_slot = slot;
287 1.5.4.2 bouyer found = (config_found_sm((struct device *)sc, &pa,
288 1.5.4.2 bouyer pckbcprint, pckbc_submatch) != NULL);
289 1.5.4.2 bouyer
290 1.5.4.2 bouyer if (found && !t->t_slotdata[slot]) {
291 1.5.4.2 bouyer t->t_slotdata[slot] = malloc(sizeof(struct pckbc_slotdata),
292 1.5.4.2 bouyer M_DEVBUF, M_NOWAIT);
293 1.5.4.2 bouyer pckbc_init_slotdata(t->t_slotdata[slot]);
294 1.5.4.2 bouyer }
295 1.5.4.2 bouyer #if NRND > 0
296 1.5.4.2 bouyer if (found && (t->t_slotdata[slot] != NULL))
297 1.5.4.2 bouyer rnd_attach_source(&t->t_slotdata[slot]->rnd_source, sc->subname[slot],
298 1.5.4.2 bouyer RND_TYPE_TTY, 0);
299 1.5.4.2 bouyer #endif
300 1.5.4.2 bouyer return (found);
301 1.5.4.2 bouyer }
302 1.5.4.2 bouyer
303 1.5.4.2 bouyer void
304 1.5.4.2 bouyer pckbc_attach(sc)
305 1.5.4.2 bouyer struct pckbc_softc *sc;
306 1.5.4.2 bouyer {
307 1.5.4.2 bouyer struct pckbc_internal *t;
308 1.5.4.2 bouyer bus_space_tag_t iot;
309 1.5.4.2 bouyer bus_space_handle_t ioh_d, ioh_c;
310 1.5.4.2 bouyer int res;
311 1.5.4.2 bouyer u_char cmdbits = 0;
312 1.5.4.2 bouyer
313 1.5.4.2 bouyer t = sc->id;
314 1.5.4.2 bouyer iot = t->t_iot;
315 1.5.4.2 bouyer ioh_d = t->t_ioh_d;
316 1.5.4.2 bouyer ioh_c = t->t_ioh_c;
317 1.5.4.2 bouyer
318 1.5.4.2 bouyer /* flush */
319 1.5.4.2 bouyer (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
320 1.5.4.2 bouyer
321 1.5.4.2 bouyer /* set initial cmd byte */
322 1.5.4.2 bouyer if (!pckbc_put8042cmd(t)) {
323 1.5.4.2 bouyer printf("kbc: cmd word write error\n");
324 1.5.4.2 bouyer return;
325 1.5.4.2 bouyer }
326 1.5.4.2 bouyer
327 1.5.4.2 bouyer /*
328 1.5.4.2 bouyer * XXX Don't check the keyboard port. There are broken keyboard controllers
329 1.5.4.2 bouyer * which don't pass the test but work normally otherwise.
330 1.5.4.2 bouyer */
331 1.5.4.2 bouyer #if 0
332 1.5.4.2 bouyer /*
333 1.5.4.2 bouyer * check kbd port ok
334 1.5.4.2 bouyer */
335 1.5.4.2 bouyer if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
336 1.5.4.2 bouyer return;
337 1.5.4.2 bouyer res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
338 1.5.4.2 bouyer
339 1.5.4.2 bouyer /*
340 1.5.4.2 bouyer * Normally, we should get a "0" here.
341 1.5.4.2 bouyer * But there are keyboard controllers behaving differently.
342 1.5.4.2 bouyer */
343 1.5.4.2 bouyer if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
344 1.5.4.2 bouyer #ifdef PCKBCDEBUG
345 1.5.4.2 bouyer if (res != 0)
346 1.5.4.2 bouyer printf("kbc: returned %x on kbd slot test\n", res);
347 1.5.4.2 bouyer #endif
348 1.5.4.2 bouyer if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
349 1.5.4.2 bouyer cmdbits |= KC8_KENABLE;
350 1.5.4.2 bouyer } else {
351 1.5.4.2 bouyer printf("kbc: kbd port test: %x\n", res);
352 1.5.4.2 bouyer return;
353 1.5.4.2 bouyer }
354 1.5.4.2 bouyer #else
355 1.5.4.2 bouyer if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
356 1.5.4.2 bouyer cmdbits |= KC8_KENABLE;
357 1.5.4.2 bouyer #endif /* 0 */
358 1.5.4.2 bouyer
359 1.5.4.2 bouyer /*
360 1.5.4.3 bouyer * Check aux port ok.
361 1.5.4.3 bouyer * Avoid KBC_AUXTEST because it hangs some older controllers
362 1.5.4.3 bouyer * (eg UMC880?).
363 1.5.4.2 bouyer */
364 1.5.4.3 bouyer if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
365 1.5.4.3 bouyer printf("kbc: aux echo error 1\n");
366 1.5.4.3 bouyer goto nomouse;
367 1.5.4.3 bouyer }
368 1.5.4.3 bouyer if (!pckbc_wait_output(iot, ioh_c)) {
369 1.5.4.3 bouyer printf("kbc: aux echo error 2\n");
370 1.5.4.3 bouyer goto nomouse;
371 1.5.4.3 bouyer }
372 1.5.4.3 bouyer bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
373 1.5.4.3 bouyer res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, 1);
374 1.5.4.3 bouyer if (res == 0x5a) {
375 1.5.4.2 bouyer t->t_haveaux = 1;
376 1.5.4.2 bouyer if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
377 1.5.4.2 bouyer cmdbits |= KC8_MENABLE;
378 1.5.4.2 bouyer }
379 1.5.4.2 bouyer #ifdef PCKBCDEBUG
380 1.5.4.2 bouyer else
381 1.5.4.3 bouyer printf("kbc: aux echo: %x\n", res);
382 1.5.4.2 bouyer #endif
383 1.5.4.2 bouyer
384 1.5.4.3 bouyer nomouse:
385 1.5.4.2 bouyer /* enable needed interrupts */
386 1.5.4.2 bouyer t->t_cmdbyte |= cmdbits;
387 1.5.4.2 bouyer if (!pckbc_put8042cmd(t))
388 1.5.4.2 bouyer printf("kbc: cmd word write error\n");
389 1.5.4.2 bouyer }
390 1.5.4.2 bouyer
391 1.5.4.2 bouyer int
392 1.5.4.2 bouyer pckbcprint(aux, pnp)
393 1.5.4.2 bouyer void *aux;
394 1.5.4.2 bouyer const char *pnp;
395 1.5.4.2 bouyer {
396 1.5.4.2 bouyer struct pckbc_attach_args *pa = aux;
397 1.5.4.2 bouyer
398 1.5.4.2 bouyer if (!pnp)
399 1.5.4.2 bouyer printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
400 1.5.4.2 bouyer return (QUIET);
401 1.5.4.2 bouyer }
402 1.5.4.2 bouyer
403 1.5.4.2 bouyer void
404 1.5.4.2 bouyer pckbc_init_slotdata(q)
405 1.5.4.2 bouyer struct pckbc_slotdata *q;
406 1.5.4.2 bouyer {
407 1.5.4.2 bouyer int i;
408 1.5.4.2 bouyer TAILQ_INIT(&q->cmdqueue);
409 1.5.4.2 bouyer TAILQ_INIT(&q->freequeue);
410 1.5.4.2 bouyer
411 1.5.4.3 bouyer for (i = 0; i < NCMD; i++) {
412 1.5.4.2 bouyer TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next);
413 1.5.4.2 bouyer }
414 1.5.4.2 bouyer q->polling = 0;
415 1.5.4.2 bouyer }
416 1.5.4.2 bouyer
417 1.5.4.2 bouyer void
418 1.5.4.2 bouyer pckbc_flush(self, slot)
419 1.5.4.2 bouyer pckbc_tag_t self;
420 1.5.4.2 bouyer pckbc_slot_t slot;
421 1.5.4.2 bouyer {
422 1.5.4.2 bouyer struct pckbc_internal *t = self;
423 1.5.4.2 bouyer
424 1.5.4.2 bouyer (void) pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
425 1.5.4.2 bouyer slot, t->t_haveaux);
426 1.5.4.2 bouyer }
427 1.5.4.2 bouyer
428 1.5.4.2 bouyer int
429 1.5.4.2 bouyer pckbc_poll_data(self, slot)
430 1.5.4.2 bouyer pckbc_tag_t self;
431 1.5.4.2 bouyer pckbc_slot_t slot;
432 1.5.4.2 bouyer {
433 1.5.4.2 bouyer struct pckbc_internal *t = self;
434 1.5.4.2 bouyer struct pckbc_slotdata *q = t->t_slotdata[slot];
435 1.5.4.2 bouyer int c;
436 1.5.4.2 bouyer
437 1.5.4.2 bouyer c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
438 1.5.4.2 bouyer slot, t->t_haveaux);
439 1.5.4.2 bouyer if (c != -1 && q && CMD_IN_QUEUE(q)) {
440 1.5.4.2 bouyer /* we jumped into a running command - try to
441 1.5.4.2 bouyer deliver the response */
442 1.5.4.2 bouyer if (pckbc_cmdresponse(t, slot, c))
443 1.5.4.2 bouyer return (-1);
444 1.5.4.2 bouyer }
445 1.5.4.2 bouyer return (c);
446 1.5.4.2 bouyer }
447 1.5.4.2 bouyer
448 1.5.4.2 bouyer /*
449 1.5.4.2 bouyer * switch scancode translation on / off
450 1.5.4.2 bouyer * return nonzero on success
451 1.5.4.2 bouyer */
452 1.5.4.2 bouyer int
453 1.5.4.2 bouyer pckbc_xt_translation(self, slot, on)
454 1.5.4.2 bouyer pckbc_tag_t self;
455 1.5.4.2 bouyer pckbc_slot_t slot;
456 1.5.4.2 bouyer int on;
457 1.5.4.2 bouyer {
458 1.5.4.2 bouyer struct pckbc_internal *t = self;
459 1.5.4.2 bouyer int ison;
460 1.5.4.2 bouyer
461 1.5.4.2 bouyer if (slot != PCKBC_KBD_SLOT) {
462 1.5.4.2 bouyer /* translation only for kbd slot */
463 1.5.4.2 bouyer if (on)
464 1.5.4.2 bouyer return (0);
465 1.5.4.2 bouyer else
466 1.5.4.2 bouyer return (1);
467 1.5.4.2 bouyer }
468 1.5.4.2 bouyer
469 1.5.4.2 bouyer ison = t->t_cmdbyte & KC8_TRANS;
470 1.5.4.2 bouyer if ((on && ison) || (!on && !ison))
471 1.5.4.2 bouyer return (1);
472 1.5.4.2 bouyer
473 1.5.4.2 bouyer t->t_cmdbyte ^= KC8_TRANS;
474 1.5.4.2 bouyer if (!pckbc_put8042cmd(t))
475 1.5.4.2 bouyer return (0);
476 1.5.4.2 bouyer
477 1.5.4.2 bouyer /* read back to be sure */
478 1.5.4.2 bouyer if (!pckbc_get8042cmd(t))
479 1.5.4.2 bouyer return (0);
480 1.5.4.2 bouyer
481 1.5.4.2 bouyer ison = t->t_cmdbyte & KC8_TRANS;
482 1.5.4.2 bouyer if ((on && ison) || (!on && !ison))
483 1.5.4.2 bouyer return (1);
484 1.5.4.2 bouyer return (0);
485 1.5.4.2 bouyer }
486 1.5.4.2 bouyer
487 1.5.4.2 bouyer static struct pckbc_portcmd {
488 1.5.4.2 bouyer u_char cmd_en, cmd_dis;
489 1.5.4.2 bouyer } pckbc_portcmd[2] = {
490 1.5.4.2 bouyer {
491 1.5.4.2 bouyer KBC_KBDENABLE, KBC_KBDDISABLE,
492 1.5.4.2 bouyer }, {
493 1.5.4.2 bouyer KBC_AUXENABLE, KBC_AUXDISABLE,
494 1.5.4.2 bouyer }
495 1.5.4.2 bouyer };
496 1.5.4.2 bouyer
497 1.5.4.2 bouyer void
498 1.5.4.2 bouyer pckbc_slot_enable(self, slot, on)
499 1.5.4.2 bouyer pckbc_tag_t self;
500 1.5.4.2 bouyer pckbc_slot_t slot;
501 1.5.4.2 bouyer int on;
502 1.5.4.2 bouyer {
503 1.5.4.2 bouyer struct pckbc_internal *t = (struct pckbc_internal *)self;
504 1.5.4.2 bouyer struct pckbc_portcmd *cmd;
505 1.5.4.2 bouyer
506 1.5.4.2 bouyer cmd = &pckbc_portcmd[slot];
507 1.5.4.2 bouyer
508 1.5.4.2 bouyer if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
509 1.5.4.2 bouyer on ? cmd->cmd_en : cmd->cmd_dis))
510 1.5.4.2 bouyer printf("pckbc_slot_enable(%d) failed\n", on);
511 1.5.4.2 bouyer }
512 1.5.4.2 bouyer
513 1.5.4.2 bouyer void
514 1.5.4.2 bouyer pckbc_set_poll(self, slot, on)
515 1.5.4.2 bouyer pckbc_tag_t self;
516 1.5.4.2 bouyer pckbc_slot_t slot;
517 1.5.4.2 bouyer int on;
518 1.5.4.2 bouyer {
519 1.5.4.2 bouyer struct pckbc_internal *t = (struct pckbc_internal *)self;
520 1.5.4.2 bouyer
521 1.5.4.2 bouyer t->t_slotdata[slot]->polling = on;
522 1.5.4.2 bouyer
523 1.5.4.2 bouyer if (!on) {
524 1.5.4.2 bouyer int s;
525 1.5.4.2 bouyer
526 1.5.4.2 bouyer /*
527 1.5.4.2 bouyer * If disabling polling on a device that's been configured,
528 1.5.4.2 bouyer * make sure there are no bytes left in the FIFO, holding up
529 1.5.4.2 bouyer * the interrupt line. Otherwise we won't get any further
530 1.5.4.2 bouyer * interrupts.
531 1.5.4.2 bouyer */
532 1.5.4.2 bouyer if (t->t_sc) {
533 1.5.4.2 bouyer s = spltty();
534 1.5.4.2 bouyer pckbcintr(t->t_sc);
535 1.5.4.2 bouyer splx(s);
536 1.5.4.2 bouyer }
537 1.5.4.2 bouyer }
538 1.5.4.2 bouyer }
539 1.5.4.2 bouyer
540 1.5.4.2 bouyer /*
541 1.5.4.2 bouyer * Pass command to device, poll for ACK and data.
542 1.5.4.2 bouyer * to be called at spltty()
543 1.5.4.2 bouyer */
544 1.5.4.2 bouyer static void
545 1.5.4.2 bouyer pckbc_poll_cmd1(t, slot, cmd)
546 1.5.4.2 bouyer struct pckbc_internal *t;
547 1.5.4.2 bouyer pckbc_slot_t slot;
548 1.5.4.2 bouyer struct pckbc_devcmd *cmd;
549 1.5.4.2 bouyer {
550 1.5.4.2 bouyer bus_space_tag_t iot = t->t_iot;
551 1.5.4.2 bouyer bus_space_handle_t ioh_d = t->t_ioh_d;
552 1.5.4.2 bouyer bus_space_handle_t ioh_c = t->t_ioh_c;
553 1.5.4.2 bouyer int i, c = 0;
554 1.5.4.2 bouyer
555 1.5.4.2 bouyer while (cmd->cmdidx < cmd->cmdlen) {
556 1.5.4.2 bouyer if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
557 1.5.4.2 bouyer printf("pckbc_cmd: send error\n");
558 1.5.4.2 bouyer cmd->status = EIO;
559 1.5.4.2 bouyer return;
560 1.5.4.2 bouyer }
561 1.5.4.2 bouyer for (i = 10; i; i--) { /* 1s ??? */
562 1.5.4.2 bouyer c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
563 1.5.4.2 bouyer t->t_haveaux);
564 1.5.4.2 bouyer if (c != -1)
565 1.5.4.2 bouyer break;
566 1.5.4.2 bouyer }
567 1.5.4.2 bouyer
568 1.5.4.2 bouyer if (c == KBC_DEVCMD_ACK) {
569 1.5.4.2 bouyer cmd->cmdidx++;
570 1.5.4.2 bouyer continue;
571 1.5.4.2 bouyer }
572 1.5.4.2 bouyer if (c == KBC_DEVCMD_RESEND) {
573 1.5.4.2 bouyer #ifdef PCKBCDEBUG
574 1.5.4.2 bouyer printf("pckbc_cmd: RESEND\n");
575 1.5.4.2 bouyer #endif
576 1.5.4.2 bouyer if (cmd->retries++ < 5)
577 1.5.4.2 bouyer continue;
578 1.5.4.2 bouyer else {
579 1.5.4.2 bouyer #ifdef PCKBCDEBUG
580 1.5.4.2 bouyer printf("pckbc: cmd failed\n");
581 1.5.4.2 bouyer #endif
582 1.5.4.2 bouyer cmd->status = EIO;
583 1.5.4.2 bouyer return;
584 1.5.4.2 bouyer }
585 1.5.4.2 bouyer }
586 1.5.4.2 bouyer if (c == -1) {
587 1.5.4.2 bouyer #ifdef PCKBCDEBUG
588 1.5.4.2 bouyer printf("pckbc_cmd: timeout\n");
589 1.5.4.2 bouyer #endif
590 1.5.4.2 bouyer cmd->status = EIO;
591 1.5.4.2 bouyer return;
592 1.5.4.2 bouyer }
593 1.5.4.2 bouyer #ifdef PCKBCDEBUG
594 1.5.4.2 bouyer printf("pckbc_cmd: lost 0x%x\n", c);
595 1.5.4.2 bouyer #endif
596 1.5.4.2 bouyer }
597 1.5.4.2 bouyer
598 1.5.4.2 bouyer while (cmd->responseidx < cmd->responselen) {
599 1.5.4.2 bouyer if (cmd->flags & KBC_CMDFLAG_SLOW)
600 1.5.4.2 bouyer i = 100; /* 10s ??? */
601 1.5.4.2 bouyer else
602 1.5.4.2 bouyer i = 10; /* 1s ??? */
603 1.5.4.2 bouyer while (i--) {
604 1.5.4.2 bouyer c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
605 1.5.4.2 bouyer t->t_haveaux);
606 1.5.4.2 bouyer if (c != -1)
607 1.5.4.2 bouyer break;
608 1.5.4.2 bouyer }
609 1.5.4.2 bouyer if (c == -1) {
610 1.5.4.2 bouyer #ifdef PCKBCDEBUG
611 1.5.4.2 bouyer printf("pckbc_cmd: no data\n");
612 1.5.4.2 bouyer #endif
613 1.5.4.2 bouyer cmd->status = ETIMEDOUT;
614 1.5.4.2 bouyer return;
615 1.5.4.2 bouyer } else
616 1.5.4.2 bouyer cmd->response[cmd->responseidx++] = c;
617 1.5.4.2 bouyer }
618 1.5.4.2 bouyer }
619 1.5.4.2 bouyer
620 1.5.4.2 bouyer /* for use in autoconfiguration */
621 1.5.4.2 bouyer int
622 1.5.4.2 bouyer pckbc_poll_cmd(self, slot, cmd, len, responselen, respbuf, slow)
623 1.5.4.2 bouyer pckbc_tag_t self;
624 1.5.4.2 bouyer pckbc_slot_t slot;
625 1.5.4.2 bouyer u_char *cmd;
626 1.5.4.2 bouyer int len, responselen;
627 1.5.4.2 bouyer u_char *respbuf;
628 1.5.4.2 bouyer int slow;
629 1.5.4.2 bouyer {
630 1.5.4.2 bouyer struct pckbc_internal *t = self;
631 1.5.4.2 bouyer struct pckbc_devcmd nc;
632 1.5.4.2 bouyer
633 1.5.4.2 bouyer if ((len > 4) || (responselen > 4))
634 1.5.4.2 bouyer return (EINVAL);
635 1.5.4.2 bouyer
636 1.5.4.2 bouyer bzero(&nc, sizeof(nc));
637 1.5.4.2 bouyer bcopy(cmd, nc.cmd, len);
638 1.5.4.2 bouyer nc.cmdlen = len;
639 1.5.4.2 bouyer nc.responselen = responselen;
640 1.5.4.2 bouyer nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
641 1.5.4.2 bouyer
642 1.5.4.2 bouyer pckbc_poll_cmd1(t, slot, &nc);
643 1.5.4.2 bouyer
644 1.5.4.2 bouyer if (nc.status == 0 && respbuf)
645 1.5.4.2 bouyer bcopy(nc.response, respbuf, responselen);
646 1.5.4.2 bouyer
647 1.5.4.2 bouyer return (nc.status);
648 1.5.4.2 bouyer }
649 1.5.4.2 bouyer
650 1.5.4.2 bouyer /*
651 1.5.4.2 bouyer * Clean up a command queue, throw away everything.
652 1.5.4.2 bouyer */
653 1.5.4.2 bouyer void
654 1.5.4.2 bouyer pckbc_cleanqueue(q)
655 1.5.4.2 bouyer struct pckbc_slotdata *q;
656 1.5.4.2 bouyer {
657 1.5.4.2 bouyer struct pckbc_devcmd *cmd;
658 1.5.4.2 bouyer #ifdef PCKBCDEBUG
659 1.5.4.2 bouyer int i;
660 1.5.4.2 bouyer #endif
661 1.5.4.2 bouyer
662 1.5.4.2 bouyer while ((cmd = TAILQ_FIRST(&q->cmdqueue))) {
663 1.5.4.2 bouyer TAILQ_REMOVE(&q->cmdqueue, cmd, next);
664 1.5.4.2 bouyer #ifdef PCKBCDEBUG
665 1.5.4.2 bouyer printf("pckbc_cleanqueue: removing");
666 1.5.4.2 bouyer for (i = 0; i < cmd->cmdlen; i++)
667 1.5.4.2 bouyer printf(" %02x", cmd->cmd[i]);
668 1.5.4.2 bouyer printf("\n");
669 1.5.4.2 bouyer #endif
670 1.5.4.2 bouyer TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
671 1.5.4.2 bouyer }
672 1.5.4.2 bouyer }
673 1.5.4.2 bouyer
674 1.5.4.2 bouyer /*
675 1.5.4.2 bouyer * Timeout error handler: clean queues and data port.
676 1.5.4.2 bouyer * XXX could be less invasive.
677 1.5.4.2 bouyer */
678 1.5.4.2 bouyer void
679 1.5.4.2 bouyer pckbc_cleanup(self)
680 1.5.4.2 bouyer void *self;
681 1.5.4.2 bouyer {
682 1.5.4.2 bouyer struct pckbc_internal *t = self;
683 1.5.4.2 bouyer int s;
684 1.5.4.2 bouyer
685 1.5.4.2 bouyer printf("pckbc: command timeout\n");
686 1.5.4.2 bouyer
687 1.5.4.2 bouyer s = spltty();
688 1.5.4.2 bouyer
689 1.5.4.2 bouyer if (t->t_slotdata[PCKBC_KBD_SLOT])
690 1.5.4.2 bouyer pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
691 1.5.4.2 bouyer if (t->t_slotdata[PCKBC_AUX_SLOT])
692 1.5.4.2 bouyer pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
693 1.5.4.2 bouyer
694 1.5.4.2 bouyer while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) {
695 1.5.4.2 bouyer KBD_DELAY;
696 1.5.4.2 bouyer (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
697 1.5.4.2 bouyer }
698 1.5.4.2 bouyer
699 1.5.4.2 bouyer /* reset KBC? */
700 1.5.4.2 bouyer
701 1.5.4.2 bouyer splx(s);
702 1.5.4.2 bouyer }
703 1.5.4.2 bouyer
704 1.5.4.2 bouyer /*
705 1.5.4.2 bouyer * Pass command to device during normal operation.
706 1.5.4.2 bouyer * to be called at spltty()
707 1.5.4.2 bouyer */
708 1.5.4.2 bouyer void
709 1.5.4.2 bouyer pckbc_start(t, slot)
710 1.5.4.2 bouyer struct pckbc_internal *t;
711 1.5.4.2 bouyer pckbc_slot_t slot;
712 1.5.4.2 bouyer {
713 1.5.4.2 bouyer struct pckbc_slotdata *q = t->t_slotdata[slot];
714 1.5.4.2 bouyer struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
715 1.5.4.2 bouyer
716 1.5.4.2 bouyer if (q->polling) {
717 1.5.4.2 bouyer do {
718 1.5.4.2 bouyer pckbc_poll_cmd1(t, slot, cmd);
719 1.5.4.2 bouyer if (cmd->status)
720 1.5.4.2 bouyer printf("pckbc_start: command error\n");
721 1.5.4.2 bouyer
722 1.5.4.2 bouyer TAILQ_REMOVE(&q->cmdqueue, cmd, next);
723 1.5.4.2 bouyer if (cmd->flags & KBC_CMDFLAG_SYNC)
724 1.5.4.2 bouyer wakeup(cmd);
725 1.5.4.2 bouyer else {
726 1.5.4.2 bouyer callout_stop(&t->t_cleanup);
727 1.5.4.2 bouyer TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
728 1.5.4.2 bouyer }
729 1.5.4.2 bouyer cmd = TAILQ_FIRST(&q->cmdqueue);
730 1.5.4.2 bouyer } while (cmd);
731 1.5.4.2 bouyer return;
732 1.5.4.2 bouyer }
733 1.5.4.2 bouyer
734 1.5.4.2 bouyer if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
735 1.5.4.2 bouyer printf("pckbc_start: send error\n");
736 1.5.4.2 bouyer /* XXX what now? */
737 1.5.4.2 bouyer return;
738 1.5.4.2 bouyer }
739 1.5.4.2 bouyer }
740 1.5.4.2 bouyer
741 1.5.4.2 bouyer /*
742 1.5.4.2 bouyer * Handle command responses coming in asynchonously,
743 1.5.4.2 bouyer * return nonzero if valid response.
744 1.5.4.2 bouyer * to be called at spltty()
745 1.5.4.2 bouyer */
746 1.5.4.2 bouyer int
747 1.5.4.2 bouyer pckbc_cmdresponse(t, slot, data)
748 1.5.4.2 bouyer struct pckbc_internal *t;
749 1.5.4.2 bouyer pckbc_slot_t slot;
750 1.5.4.2 bouyer u_char data;
751 1.5.4.2 bouyer {
752 1.5.4.2 bouyer struct pckbc_slotdata *q = t->t_slotdata[slot];
753 1.5.4.2 bouyer struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
754 1.5.4.2 bouyer #ifdef DIAGNOSTIC
755 1.5.4.2 bouyer if (!cmd)
756 1.5.4.2 bouyer panic("pckbc_cmdresponse: no active command");
757 1.5.4.2 bouyer #endif
758 1.5.4.2 bouyer if (cmd->cmdidx < cmd->cmdlen) {
759 1.5.4.2 bouyer if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
760 1.5.4.2 bouyer return (0);
761 1.5.4.2 bouyer
762 1.5.4.2 bouyer if (data == KBC_DEVCMD_RESEND) {
763 1.5.4.2 bouyer if (cmd->retries++ < 5) {
764 1.5.4.2 bouyer /* try again last command */
765 1.5.4.2 bouyer goto restart;
766 1.5.4.2 bouyer } else {
767 1.5.4.2 bouyer printf("pckbc: cmd failed\n");
768 1.5.4.2 bouyer cmd->status = EIO;
769 1.5.4.2 bouyer /* dequeue */
770 1.5.4.2 bouyer }
771 1.5.4.2 bouyer } else {
772 1.5.4.2 bouyer if (++cmd->cmdidx < cmd->cmdlen)
773 1.5.4.2 bouyer goto restart;
774 1.5.4.2 bouyer if (cmd->responselen)
775 1.5.4.2 bouyer return (1);
776 1.5.4.2 bouyer /* else dequeue */
777 1.5.4.2 bouyer }
778 1.5.4.2 bouyer } else if (cmd->responseidx < cmd->responselen) {
779 1.5.4.2 bouyer cmd->response[cmd->responseidx++] = data;
780 1.5.4.2 bouyer if (cmd->responseidx < cmd->responselen)
781 1.5.4.2 bouyer return (1);
782 1.5.4.2 bouyer /* else dequeue */
783 1.5.4.2 bouyer } else
784 1.5.4.2 bouyer return (0);
785 1.5.4.2 bouyer
786 1.5.4.2 bouyer /* dequeue: */
787 1.5.4.2 bouyer TAILQ_REMOVE(&q->cmdqueue, cmd, next);
788 1.5.4.2 bouyer if (cmd->flags & KBC_CMDFLAG_SYNC)
789 1.5.4.2 bouyer wakeup(cmd);
790 1.5.4.2 bouyer else {
791 1.5.4.2 bouyer callout_stop(&t->t_cleanup);
792 1.5.4.2 bouyer TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
793 1.5.4.2 bouyer }
794 1.5.4.2 bouyer if (!CMD_IN_QUEUE(q))
795 1.5.4.2 bouyer return (1);
796 1.5.4.2 bouyer restart:
797 1.5.4.2 bouyer pckbc_start(t, slot);
798 1.5.4.2 bouyer return (1);
799 1.5.4.2 bouyer }
800 1.5.4.2 bouyer
801 1.5.4.2 bouyer /*
802 1.5.4.2 bouyer * Put command into the device's command queue, return zero or errno.
803 1.5.4.2 bouyer */
804 1.5.4.2 bouyer int
805 1.5.4.2 bouyer pckbc_enqueue_cmd(self, slot, cmd, len, responselen, sync, respbuf)
806 1.5.4.2 bouyer pckbc_tag_t self;
807 1.5.4.2 bouyer pckbc_slot_t slot;
808 1.5.4.2 bouyer u_char *cmd;
809 1.5.4.2 bouyer int len, responselen, sync;
810 1.5.4.2 bouyer u_char *respbuf;
811 1.5.4.2 bouyer {
812 1.5.4.2 bouyer struct pckbc_internal *t = self;
813 1.5.4.2 bouyer struct pckbc_slotdata *q = t->t_slotdata[slot];
814 1.5.4.2 bouyer struct pckbc_devcmd *nc;
815 1.5.4.2 bouyer int s, isactive, res = 0;
816 1.5.4.2 bouyer
817 1.5.4.2 bouyer if ((len > 4) || (responselen > 4))
818 1.5.4.2 bouyer return (EINVAL);
819 1.5.4.2 bouyer s = spltty();
820 1.5.4.2 bouyer nc = TAILQ_FIRST(&q->freequeue);
821 1.5.4.2 bouyer if (nc) {
822 1.5.4.2 bouyer TAILQ_REMOVE(&q->freequeue, nc, next);
823 1.5.4.2 bouyer }
824 1.5.4.2 bouyer splx(s);
825 1.5.4.2 bouyer if (!nc)
826 1.5.4.2 bouyer return (ENOMEM);
827 1.5.4.2 bouyer
828 1.5.4.2 bouyer bzero(nc, sizeof(*nc));
829 1.5.4.2 bouyer bcopy(cmd, nc->cmd, len);
830 1.5.4.2 bouyer nc->cmdlen = len;
831 1.5.4.2 bouyer nc->responselen = responselen;
832 1.5.4.2 bouyer nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0);
833 1.5.4.2 bouyer
834 1.5.4.2 bouyer s = spltty();
835 1.5.4.2 bouyer
836 1.5.4.2 bouyer if (q->polling && sync) {
837 1.5.4.2 bouyer /*
838 1.5.4.2 bouyer * XXX We should poll until the queue is empty.
839 1.5.4.2 bouyer * But we don't come here normally, so make
840 1.5.4.2 bouyer * it simple and throw away everything.
841 1.5.4.2 bouyer */
842 1.5.4.2 bouyer pckbc_cleanqueue(q);
843 1.5.4.2 bouyer }
844 1.5.4.2 bouyer
845 1.5.4.2 bouyer isactive = CMD_IN_QUEUE(q);
846 1.5.4.2 bouyer TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next);
847 1.5.4.2 bouyer if (!isactive)
848 1.5.4.2 bouyer pckbc_start(t, slot);
849 1.5.4.2 bouyer
850 1.5.4.2 bouyer if (q->polling)
851 1.5.4.2 bouyer res = (sync ? nc->status : 0);
852 1.5.4.2 bouyer else if (sync) {
853 1.5.4.2 bouyer if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) {
854 1.5.4.2 bouyer TAILQ_REMOVE(&q->cmdqueue, nc, next);
855 1.5.4.2 bouyer pckbc_cleanup(t);
856 1.5.4.2 bouyer } else
857 1.5.4.2 bouyer res = nc->status;
858 1.5.4.2 bouyer } else
859 1.5.4.2 bouyer callout_reset(&t->t_cleanup, hz, pckbc_cleanup, t);
860 1.5.4.2 bouyer
861 1.5.4.2 bouyer if (sync) {
862 1.5.4.2 bouyer if (respbuf)
863 1.5.4.2 bouyer bcopy(nc->response, respbuf, responselen);
864 1.5.4.2 bouyer TAILQ_INSERT_TAIL(&q->freequeue, nc, next);
865 1.5.4.2 bouyer }
866 1.5.4.2 bouyer
867 1.5.4.2 bouyer splx(s);
868 1.5.4.2 bouyer
869 1.5.4.2 bouyer return (res);
870 1.5.4.2 bouyer }
871 1.5.4.2 bouyer
872 1.5.4.2 bouyer void
873 1.5.4.2 bouyer pckbc_set_inputhandler(self, slot, func, arg, name)
874 1.5.4.2 bouyer pckbc_tag_t self;
875 1.5.4.2 bouyer pckbc_slot_t slot;
876 1.5.4.2 bouyer pckbc_inputfcn func;
877 1.5.4.2 bouyer void *arg;
878 1.5.4.2 bouyer char *name;
879 1.5.4.2 bouyer {
880 1.5.4.2 bouyer struct pckbc_internal *t = (struct pckbc_internal *)self;
881 1.5.4.2 bouyer struct pckbc_softc *sc = t->t_sc;
882 1.5.4.2 bouyer
883 1.5.4.2 bouyer if (slot >= PCKBC_NSLOTS)
884 1.5.4.2 bouyer panic("pckbc_set_inputhandler: bad slot %d", slot);
885 1.5.4.2 bouyer
886 1.5.4.2 bouyer (*sc->intr_establish)(sc, slot);
887 1.5.4.2 bouyer
888 1.5.4.2 bouyer sc->inputhandler[slot] = func;
889 1.5.4.2 bouyer sc->inputarg[slot] = arg;
890 1.5.4.2 bouyer sc->subname[slot] = name;
891 1.5.4.2 bouyer }
892 1.5.4.2 bouyer
893 1.5.4.2 bouyer int
894 1.5.4.2 bouyer pckbcintr(vsc)
895 1.5.4.2 bouyer void *vsc;
896 1.5.4.2 bouyer {
897 1.5.4.2 bouyer struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
898 1.5.4.2 bouyer struct pckbc_internal *t = sc->id;
899 1.5.4.2 bouyer u_char stat;
900 1.5.4.2 bouyer pckbc_slot_t slot;
901 1.5.4.2 bouyer struct pckbc_slotdata *q;
902 1.5.4.2 bouyer int served = 0, data;
903 1.5.4.2 bouyer
904 1.5.4.2 bouyer for(;;) {
905 1.5.4.2 bouyer stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
906 1.5.4.2 bouyer if (!(stat & KBS_DIB))
907 1.5.4.2 bouyer break;
908 1.5.4.2 bouyer
909 1.5.4.2 bouyer served = 1;
910 1.5.4.2 bouyer
911 1.5.4.2 bouyer slot = (t->t_haveaux && (stat & 0x20)) ?
912 1.5.4.2 bouyer PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
913 1.5.4.2 bouyer q = t->t_slotdata[slot];
914 1.5.4.2 bouyer
915 1.5.4.2 bouyer if (!q) {
916 1.5.4.2 bouyer /* XXX do something for live insertion? */
917 1.5.4.2 bouyer printf("pckbcintr: no dev for slot %d\n", slot);
918 1.5.4.2 bouyer KBD_DELAY;
919 1.5.4.2 bouyer (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
920 1.5.4.2 bouyer continue;
921 1.5.4.2 bouyer }
922 1.5.4.2 bouyer
923 1.5.4.2 bouyer if (q->polling)
924 1.5.4.2 bouyer break; /* pckbc_poll_data() will get it */
925 1.5.4.2 bouyer
926 1.5.4.2 bouyer KBD_DELAY;
927 1.5.4.2 bouyer data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
928 1.5.4.2 bouyer
929 1.5.4.2 bouyer #if NRND > 0
930 1.5.4.2 bouyer rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
931 1.5.4.2 bouyer #endif
932 1.5.4.2 bouyer if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
933 1.5.4.2 bouyer continue;
934 1.5.4.2 bouyer
935 1.5.4.2 bouyer if (sc->inputhandler[slot])
936 1.5.4.2 bouyer (*sc->inputhandler[slot])(sc->inputarg[slot], data);
937 1.5.4.2 bouyer #ifdef PCKBCDEBUG
938 1.5.4.2 bouyer else
939 1.5.4.2 bouyer printf("pckbcintr: slot %d lost %d\n", slot, data);
940 1.5.4.2 bouyer #endif
941 1.5.4.2 bouyer }
942 1.5.4.2 bouyer
943 1.5.4.2 bouyer return (served);
944 1.5.4.2 bouyer }
945 1.5.4.2 bouyer
946 1.5.4.2 bouyer int
947 1.5.4.2 bouyer pckbc_cnattach(iot, addr, cmd_offset, slot)
948 1.5.4.2 bouyer bus_space_tag_t iot;
949 1.5.4.2 bouyer bus_addr_t addr;
950 1.5.4.2 bouyer bus_size_t cmd_offset;
951 1.5.4.2 bouyer pckbc_slot_t slot;
952 1.5.4.2 bouyer {
953 1.5.4.2 bouyer bus_space_handle_t ioh_d, ioh_c;
954 1.5.4.2 bouyer int res = 0;
955 1.5.4.2 bouyer
956 1.5.4.2 bouyer if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
957 1.5.4.2 bouyer return (ENXIO);
958 1.5.4.2 bouyer if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
959 1.5.4.2 bouyer bus_space_unmap(iot, ioh_d, 1);
960 1.5.4.2 bouyer return (ENXIO);
961 1.5.4.2 bouyer }
962 1.5.4.2 bouyer
963 1.5.4.2 bouyer pckbc_consdata.t_iot = iot;
964 1.5.4.2 bouyer pckbc_consdata.t_ioh_d = ioh_d;
965 1.5.4.2 bouyer pckbc_consdata.t_ioh_c = ioh_c;
966 1.5.4.2 bouyer pckbc_consdata.t_addr = addr;
967 1.5.4.2 bouyer callout_init(&pckbc_consdata.t_cleanup);
968 1.5.4.2 bouyer
969 1.5.4.2 bouyer /* flush */
970 1.5.4.2 bouyer (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
971 1.5.4.2 bouyer
972 1.5.4.2 bouyer /* selftest? */
973 1.5.4.2 bouyer
974 1.5.4.2 bouyer /* init cmd byte, enable ports */
975 1.5.4.2 bouyer pckbc_consdata.t_cmdbyte = KC8_CPU;
976 1.5.4.2 bouyer if (!pckbc_put8042cmd(&pckbc_consdata)) {
977 1.5.4.2 bouyer printf("kbc: cmd word write error\n");
978 1.5.4.2 bouyer res = EIO;
979 1.5.4.2 bouyer }
980 1.5.4.2 bouyer
981 1.5.4.2 bouyer if (!res) {
982 1.5.4.2 bouyer #if (NPCKBD > 0)
983 1.5.4.2 bouyer res = pckbd_cnattach(&pckbc_consdata, slot);
984 1.5.4.2 bouyer #else
985 1.5.4.2 bouyer /*
986 1.5.4.2 bouyer * XXX This should be replaced with the `notyet' case
987 1.5.4.2 bouyer * XXX when all of the old PC-style console drivers
988 1.5.4.2 bouyer * XXX have gone away. When that happens, all of
989 1.5.4.2 bouyer * XXX the pckbc_machdep_cnattach() should be purged,
990 1.5.4.2 bouyer * XXX as well.
991 1.5.4.2 bouyer */
992 1.5.4.2 bouyer #ifdef notyet
993 1.5.4.2 bouyer res = ENXIO;
994 1.5.4.2 bouyer #else
995 1.5.4.2 bouyer res = pckbc_machdep_cnattach(&pckbc_consdata, slot);
996 1.5.4.2 bouyer #endif
997 1.5.4.2 bouyer #endif /* NPCKBD > 0 */
998 1.5.4.2 bouyer }
999 1.5.4.2 bouyer
1000 1.5.4.2 bouyer if (res) {
1001 1.5.4.2 bouyer bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
1002 1.5.4.2 bouyer bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
1003 1.5.4.2 bouyer } else {
1004 1.5.4.2 bouyer pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
1005 1.5.4.2 bouyer pckbc_init_slotdata(&pckbc_cons_slotdata);
1006 1.5.4.2 bouyer pckbc_console = 1;
1007 1.5.4.2 bouyer }
1008 1.5.4.2 bouyer
1009 1.5.4.2 bouyer return (res);
1010 1.5.4.2 bouyer }
1011