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