Annotation of src/sys/dev/ic/pckbc.c, Revision 1.59.18.2
1.59.18.2! martin 1: /* $NetBSD$ */
1.1 thorpej 2:
3: /*
1.31 bjh21 4: * Copyright (c) 2004 Ben Harris.
1.1 thorpej 5: * Copyright (c) 1998
6: * Matthias Drochner. 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: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27: */
1.16 lukem 28:
29: #include <sys/cdefs.h>
1.59.18.2! martin 30: __KERNEL_RCSID(0, "$NetBSD$");
1.1 thorpej 31:
32: #include <sys/param.h>
33: #include <sys/systm.h>
1.2 thorpej 34: #include <sys/callout.h>
1.1 thorpej 35: #include <sys/kernel.h>
36: #include <sys/proc.h>
37: #include <sys/device.h>
38: #include <sys/malloc.h>
39: #include <sys/errno.h>
40: #include <sys/queue.h>
41:
1.38 ad 42: #include <sys/bus.h>
1.1 thorpej 43:
44: #include <dev/ic/i8042reg.h>
45: #include <dev/ic/pckbcvar.h>
46:
1.31 bjh21 47: #include <dev/pckbport/pckbportvar.h>
48:
1.1 thorpej 49: #include "locators.h"
50:
1.58 riastrad 51: #include <sys/rndsource.h>
1.1 thorpej 52:
53: /* data per slave device */
54: struct pckbc_slotdata {
1.15 jdolecek 55: int polling; /* don't process data in interrupt handler */
56: int poll_data; /* data read from inr handler if polling */
57: int poll_stat; /* status read from inr handler if polling */
1.52 tls 58: krndsource_t rnd_source;
1.1 thorpej 59: };
60:
1.33 perry 61: static void pckbc_init_slotdata(struct pckbc_slotdata *);
62: static int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t);
1.1 thorpej 63:
64: struct pckbc_internal pckbc_consdata;
65: int pckbc_console_attached;
66:
67: static int pckbc_console;
68: static struct pckbc_slotdata pckbc_cons_slotdata;
69:
1.33 perry 70: static int pckbc_xt_translation(void *, pckbport_slot_t, int);
71: static int pckbc_send_devcmd(void *, pckbport_slot_t, u_char);
72: static void pckbc_slot_enable(void *, pckbport_slot_t, int);
73: static void pckbc_intr_establish(void *, pckbport_slot_t);
74: static void pckbc_set_poll(void *, pckbc_slot_t, int on);
75:
76: static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t);
77:
78: static int pckbc_get8042cmd(struct pckbc_internal *);
79: static int pckbc_put8042cmd(struct pckbc_internal *);
80:
81: void pckbc_cleanqueue(struct pckbc_slotdata *);
82: void pckbc_cleanup(void *);
83: int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
84: void pckbc_start(struct pckbc_internal *, pckbc_slot_t);
1.1 thorpej 85:
1.11 jdolecek 86: const char * const pckbc_slot_names[] = { "kbd", "aux" };
1.1 thorpej 87:
1.31 bjh21 88: static struct pckbport_accessops const pckbc_ops = {
89: pckbc_xt_translation,
90: pckbc_send_devcmd,
91: pckbc_poll_data1,
92: pckbc_slot_enable,
93: pckbc_intr_establish,
94: pckbc_set_poll
95: };
1.1 thorpej 96:
97: #define KBD_DELAY DELAY(8)
98:
99: static inline int
1.44 cegger 100: pckbc_wait_output(bus_space_tag_t iot, bus_space_handle_t ioh_c)
1.1 thorpej 101: {
102: u_int i;
103:
104: for (i = 100000; i; i--)
105: if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
106: KBD_DELAY;
107: return (1);
108: }
109: return (0);
110: }
111:
112: int
1.44 cegger 113: pckbc_send_cmd(bus_space_tag_t iot, bus_space_handle_t ioh_c, u_char val)
1.1 thorpej 114: {
115: if (!pckbc_wait_output(iot, ioh_c))
116: return (0);
117: bus_space_write_1(iot, ioh_c, 0, val);
118: return (1);
119: }
120:
1.15 jdolecek 121: /*
122: * Note: the spl games here are to deal with some strange PC kbd controllers
123: * in some system configurations.
124: * This is not canonical way to handle polling input.
125: */
1.1 thorpej 126: int
1.44 cegger 127: pckbc_poll_data1(void *pt, pckbc_slot_t slot)
1.1 thorpej 128: {
1.14 jdolecek 129: struct pckbc_internal *t = pt;
1.15 jdolecek 130: struct pckbc_slotdata *q = t->t_slotdata[slot];
1.23 jdolecek 131: int s;
1.14 jdolecek 132: u_char stat, c;
1.45 drochner 133: int i = 100; /* polls for ~100ms */
1.31 bjh21 134: int checkaux = t->t_haveaux;
1.1 thorpej 135:
1.15 jdolecek 136: s = splhigh();
137:
138: if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
139: stat = q->poll_stat;
140: c = q->poll_data;
141: q->poll_data = -1;
142: q->poll_stat = -1;
143: goto process;
144: }
145:
1.45 drochner 146: for (; i; i--, delay(1000)) {
1.14 jdolecek 147: stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
1.1 thorpej 148: if (stat & KBS_DIB) {
149: KBD_DELAY;
1.14 jdolecek 150: c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
1.34 perry 151:
1.15 jdolecek 152: process:
1.1 thorpej 153: if (checkaux && (stat & 0x20)) { /* aux data */
154: if (slot != PCKBC_AUX_SLOT) {
155: #ifdef PCKBCDEBUG
1.36 christos 156: printf("pckbc: lost aux 0x%x\n", c);
1.1 thorpej 157: #endif
158: continue;
159: }
160: } else {
161: if (slot == PCKBC_AUX_SLOT) {
162: #ifdef PCKBCDEBUG
1.36 christos 163: printf("pckbc: lost kbd 0x%x\n", c);
1.1 thorpej 164: #endif
165: continue;
166: }
167: }
1.15 jdolecek 168: splx(s);
1.1 thorpej 169: return (c);
170: }
171: }
1.15 jdolecek 172:
173: splx(s);
1.1 thorpej 174: return (-1);
175: }
176:
177: /*
178: * Get the current command byte.
179: */
180: static int
1.44 cegger 181: pckbc_get8042cmd(struct pckbc_internal *t)
1.1 thorpej 182: {
183: bus_space_tag_t iot = t->t_iot;
184: bus_space_handle_t ioh_c = t->t_ioh_c;
185: int data;
186:
187: if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
188: return (0);
1.31 bjh21 189: data = pckbc_poll_data1(t, PCKBC_KBD_SLOT);
1.1 thorpej 190: if (data == -1)
191: return (0);
192: t->t_cmdbyte = data;
193: return (1);
194: }
195:
196: /*
197: * Pass command byte to keyboard controller (8042).
198: */
199: static int
1.44 cegger 200: pckbc_put8042cmd(struct pckbc_internal *t)
1.1 thorpej 201: {
202: bus_space_tag_t iot = t->t_iot;
203: bus_space_handle_t ioh_d = t->t_ioh_d;
204: bus_space_handle_t ioh_c = t->t_ioh_c;
205:
206: if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
207: return (0);
208: if (!pckbc_wait_output(iot, ioh_c))
209: return (0);
210: bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
211: return (1);
212: }
213:
214: static int
1.44 cegger 215: pckbc_send_devcmd(void *pt, pckbc_slot_t slot, u_char val)
1.1 thorpej 216: {
1.31 bjh21 217: struct pckbc_internal *t = pt;
1.1 thorpej 218: bus_space_tag_t iot = t->t_iot;
219: bus_space_handle_t ioh_d = t->t_ioh_d;
220: bus_space_handle_t ioh_c = t->t_ioh_c;
221:
222: if (slot == PCKBC_AUX_SLOT) {
223: if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
224: return (0);
225: }
226: if (!pckbc_wait_output(iot, ioh_c))
227: return (0);
228: bus_space_write_1(iot, ioh_d, 0, val);
229: return (1);
230: }
231:
232: int
1.44 cegger 233: pckbc_is_console(bus_space_tag_t iot, bus_addr_t addr)
1.1 thorpej 234: {
235: if (pckbc_console && !pckbc_console_attached &&
1.50 dyoung 236: bus_space_is_equal(pckbc_consdata.t_iot, iot) &&
1.1 thorpej 237: pckbc_consdata.t_addr == addr)
238: return (1);
239: return (0);
240: }
241:
1.31 bjh21 242: static int
1.44 cegger 243: pckbc_attach_slot(struct pckbc_softc *sc, pckbc_slot_t slot)
1.1 thorpej 244: {
245: struct pckbc_internal *t = sc->id;
1.19 augustss 246: void *sdata;
1.46 cegger 247: device_t child;
1.17 christos 248: int alloced = 0;
1.1 thorpej 249:
1.17 christos 250: if (t->t_slotdata[slot] == NULL) {
1.19 augustss 251: sdata = malloc(sizeof(struct pckbc_slotdata),
1.59.18.2! martin 252: M_DEVBUF, M_WAITOK);
1.19 augustss 253: t->t_slotdata[slot] = sdata;
1.1 thorpej 254: pckbc_init_slotdata(t->t_slotdata[slot]);
1.17 christos 255: alloced++;
256: }
257:
1.42 cube 258: child = pckbport_attach_slot(sc->sc_dv, t->t_pt, slot);
1.17 christos 259:
1.31 bjh21 260: if (child == NULL && alloced) {
1.17 christos 261: free(t->t_slotdata[slot], M_DEVBUF);
262: t->t_slotdata[slot] = NULL;
1.1 thorpej 263: }
1.17 christos 264:
1.31 bjh21 265: if (child != NULL && t->t_slotdata[slot] != NULL)
1.17 christos 266: rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
1.57 tls 267: device_xname(child), RND_TYPE_TTY, RND_FLAG_DEFAULT);
1.53 tls 268:
1.31 bjh21 269: return child != NULL;
1.1 thorpej 270: }
271:
272: void
1.44 cegger 273: pckbc_attach(struct pckbc_softc *sc)
1.1 thorpej 274: {
275: struct pckbc_internal *t;
276: bus_space_tag_t iot;
277: bus_space_handle_t ioh_d, ioh_c;
278: int res;
279: u_char cmdbits = 0;
280:
281: t = sc->id;
282: iot = t->t_iot;
283: ioh_d = t->t_ioh_d;
284: ioh_c = t->t_ioh_c;
285:
1.31 bjh21 286: t->t_pt = pckbport_attach(t, &pckbc_ops);
287: if (t->t_pt == NULL) {
288: aprint_error(": attach failed\n");
289: return;
290: }
291:
1.1 thorpej 292: /* flush */
1.31 bjh21 293: (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT);
1.1 thorpej 294:
295: /* set initial cmd byte */
296: if (!pckbc_put8042cmd(t)) {
1.59 msaitoh 297: aprint_error("pckbc: cmd word write error\n");
1.1 thorpej 298: return;
299: }
300:
301: /*
302: * XXX Don't check the keyboard port. There are broken keyboard controllers
303: * which don't pass the test but work normally otherwise.
304: */
305: #if 0
306: /*
307: * check kbd port ok
308: */
309: if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
310: return;
1.14 jdolecek 311: res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
1.1 thorpej 312:
313: /*
314: * Normally, we should get a "0" here.
315: * But there are keyboard controllers behaving differently.
316: */
317: if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
318: #ifdef PCKBCDEBUG
319: if (res != 0)
1.36 christos 320: printf("pckbc: returned %x on kbd slot test\n", res);
1.1 thorpej 321: #endif
322: if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
323: cmdbits |= KC8_KENABLE;
324: } else {
1.36 christos 325: printf("pckbc: kbd port test: %x\n", res);
1.1 thorpej 326: return;
327: }
328: #else
329: if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
330: cmdbits |= KC8_KENABLE;
331: #endif /* 0 */
332:
333: /*
1.6 drochner 334: * Check aux port ok.
335: * Avoid KBC_AUXTEST because it hangs some older controllers
336: * (eg UMC880?).
1.1 thorpej 337: */
1.6 drochner 338: if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
1.59 msaitoh 339: aprint_error("pckbc: aux echo error 1\n");
1.6 drochner 340: goto nomouse;
341: }
342: if (!pckbc_wait_output(iot, ioh_c)) {
1.59 msaitoh 343: aprint_error("pckbc: aux echo error 2\n");
1.6 drochner 344: goto nomouse;
345: }
1.31 bjh21 346: t->t_haveaux = 1;
1.6 drochner 347: bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
1.31 bjh21 348: res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
1.54 jdc 349:
350: /*
351: * The following is needed to find the aux port on the Tadpole
352: * SPARCle.
353: */
354: if (res == -1 && ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) {
355: /* Read of aux echo timed out, try again */
356: if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
357: goto nomouse;
358: if (!pckbc_wait_output(iot, ioh_c))
359: goto nomouse;
360: bus_space_write_1(iot, ioh_d, 0, 0x5a);
361: res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
362: }
1.8 drochner 363: if (res != -1) {
1.7 christos 364: /*
1.8 drochner 365: * In most cases, the 0x5a gets echoed.
366: * Some older controllers (Gateway 2000 circa 1993)
367: * return 0xfe here.
368: * We are satisfied if there is anything in the
369: * aux output buffer.
1.7 christos 370: */
1.1 thorpej 371: if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
372: cmdbits |= KC8_MENABLE;
1.31 bjh21 373: } else {
1.54 jdc 374:
1.8 drochner 375: #ifdef PCKBCDEBUG
1.36 christos 376: printf("pckbc: aux echo test failed\n");
1.8 drochner 377: #endif
1.31 bjh21 378: t->t_haveaux = 0;
379: }
1.1 thorpej 380:
1.6 drochner 381: nomouse:
1.1 thorpej 382: /* enable needed interrupts */
383: t->t_cmdbyte |= cmdbits;
384: if (!pckbc_put8042cmd(t))
1.59 msaitoh 385: aprint_error("pckbc: cmd word write error\n");
1.1 thorpej 386: }
387:
1.31 bjh21 388: static void
1.44 cegger 389: pckbc_init_slotdata(struct pckbc_slotdata *q)
1.1 thorpej 390: {
391:
392: q->polling = 0;
393: }
394:
395: /*
396: * switch scancode translation on / off
397: * return nonzero on success
398: */
1.31 bjh21 399: static int
1.44 cegger 400: pckbc_xt_translation(void *self, pckbc_slot_t slot, int on)
1.1 thorpej 401: {
402: struct pckbc_internal *t = self;
403: int ison;
404:
1.54 jdc 405: if (ISSET(t->t_flags, PCKBC_CANT_TRANSLATE))
406: return (-1);
407:
1.1 thorpej 408: if (slot != PCKBC_KBD_SLOT) {
409: /* translation only for kbd slot */
410: if (on)
411: return (0);
412: else
413: return (1);
414: }
415:
416: ison = t->t_cmdbyte & KC8_TRANS;
417: if ((on && ison) || (!on && !ison))
418: return (1);
419:
420: t->t_cmdbyte ^= KC8_TRANS;
421: if (!pckbc_put8042cmd(t))
422: return (0);
423:
424: /* read back to be sure */
425: if (!pckbc_get8042cmd(t))
426: return (0);
427:
428: ison = t->t_cmdbyte & KC8_TRANS;
429: if ((on && ison) || (!on && !ison))
430: return (1);
431: return (0);
432: }
433:
1.11 jdolecek 434: static const struct pckbc_portcmd {
1.1 thorpej 435: u_char cmd_en, cmd_dis;
436: } pckbc_portcmd[2] = {
437: {
438: KBC_KBDENABLE, KBC_KBDDISABLE,
439: }, {
440: KBC_AUXENABLE, KBC_AUXDISABLE,
441: }
442: };
443:
444: void
1.44 cegger 445: pckbc_slot_enable(void *self, pckbc_slot_t slot, int on)
1.1 thorpej 446: {
447: struct pckbc_internal *t = (struct pckbc_internal *)self;
1.11 jdolecek 448: const struct pckbc_portcmd *cmd;
1.1 thorpej 449:
450: cmd = &pckbc_portcmd[slot];
451:
452: if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
453: on ? cmd->cmd_en : cmd->cmd_dis))
1.36 christos 454: printf("pckbc: pckbc_slot_enable(%d) failed\n", on);
1.1 thorpej 455: }
456:
1.31 bjh21 457: static void
1.44 cegger 458: pckbc_set_poll(void *self, pckbc_slot_t slot, int on)
1.1 thorpej 459: {
460: struct pckbc_internal *t = (struct pckbc_internal *)self;
461:
462: t->t_slotdata[slot]->polling = on;
463:
1.15 jdolecek 464: if (on) {
465: t->t_slotdata[slot]->poll_data = -1;
466: t->t_slotdata[slot]->poll_stat = -1;
467: } else {
1.51 isaki 468: int s;
1.1 thorpej 469:
1.51 isaki 470: /*
471: * If disabling polling on a device that's been configured,
472: * make sure there are no bytes left in the FIFO, holding up
473: * the interrupt line. Otherwise we won't get any further
474: * interrupts.
475: */
1.1 thorpej 476: if (t->t_sc) {
477: s = spltty();
478: pckbcintr(t->t_sc);
479: splx(s);
480: }
481: }
482: }
483:
484: static void
1.44 cegger 485: pckbc_intr_establish(void *pt, pckbport_slot_t slot)
1.1 thorpej 486: {
1.31 bjh21 487: struct pckbc_internal *t = pt;
1.1 thorpej 488:
1.31 bjh21 489: (*t->t_sc->intr_establish)(t->t_sc, slot);
1.28 martin 490: }
491:
492: int
1.44 cegger 493: pckbcintr_hard(void *vsc)
1.28 martin 494: {
495: struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
496: struct pckbc_internal *t = sc->id;
497: u_char stat;
498: pckbc_slot_t slot;
499: struct pckbc_slotdata *q;
500: int served = 0, data, next, s;
501:
502: for(;;) {
503: stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
504: if (!(stat & KBS_DIB))
505: break;
506:
507: served = 1;
508:
509: slot = (t->t_haveaux && (stat & 0x20)) ?
510: PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
511: q = t->t_slotdata[slot];
512:
513: if (!q) {
514: /* XXX do something for live insertion? */
1.36 christos 515: printf("pckbc: no dev for slot %d\n", slot);
1.28 martin 516: KBD_DELAY;
517: (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
518: continue;
519: }
520:
521: KBD_DELAY;
522: data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
523:
524: rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
525:
526: if (q->polling) {
527: q->poll_data = data;
528: q->poll_stat = stat;
529: break; /* pckbc_poll_data() will get it */
530: }
531:
1.31 bjh21 532: #if 0 /* XXXBJH */
1.28 martin 533: if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
534: continue;
1.31 bjh21 535: #endif
1.28 martin 536:
537: s = splhigh();
538: next = (t->rbuf_write+1) % PCKBC_RBUF_SIZE;
539: if (next == t->rbuf_read) {
540: splx(s);
541: break;
542: }
543: t->rbuf[t->rbuf_write].data = data;
544: t->rbuf[t->rbuf_write].slot = slot;
545: t->rbuf_write = next;
546: splx(s);
547: }
548:
549: return (served);
550: }
551:
552: void
1.44 cegger 553: pckbcintr_soft(void *vsc)
1.28 martin 554: {
555: struct pckbc_softc *sc = vsc;
556: struct pckbc_internal *t = sc->id;
557: int data, slot, s;
558: #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
1.29 martin 559: int st;
1.28 martin 560:
1.29 martin 561: st = spltty();
1.28 martin 562: #endif
563:
564: s = splhigh();
565: while (t->rbuf_read != t->rbuf_write) {
566: slot = t->rbuf[t->rbuf_read].slot;
567: data = t->rbuf[t->rbuf_read].data;
568: t->rbuf_read = (t->rbuf_read+1) % PCKBC_RBUF_SIZE;
569: splx(s);
1.31 bjh21 570: pckbportintr(t->t_pt, slot, data);
1.28 martin 571: s = splhigh();
572: }
573: splx(s);
574:
575:
576: #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
1.29 martin 577: splx(st);
1.28 martin 578: #endif
1.1 thorpej 579: }
580:
581: int
1.44 cegger 582: pckbcintr(void *vsc)
1.1 thorpej 583: {
584: struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
585: struct pckbc_internal *t = sc->id;
586: u_char stat;
587: pckbc_slot_t slot;
588: struct pckbc_slotdata *q;
589: int served = 0, data;
590:
591: for(;;) {
592: stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
593: if (!(stat & KBS_DIB))
594: break;
595:
596: slot = (t->t_haveaux && (stat & 0x20)) ?
597: PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
598: q = t->t_slotdata[slot];
599:
1.56 jakllsch 600: if (q != NULL && q->polling)
601: return 0;
602:
603: served = 1;
1.1 thorpej 604: KBD_DELAY;
605: data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
606:
1.59.18.1 christos 607: if (q != NULL)
608: rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
1.15 jdolecek 609:
1.31 bjh21 610: pckbportintr(t->t_pt, slot, data);
1.1 thorpej 611: }
612:
613: return (served);
614: }
615:
616: int
1.44 cegger 617: pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr,
1.54 jdc 618: bus_size_t cmd_offset, pckbc_slot_t slot, int flags)
1.1 thorpej 619: {
620: bus_space_handle_t ioh_d, ioh_c;
1.26 uwe 621: #ifdef PCKBC_CNATTACH_SELFTEST
622: int reply;
623: #endif
1.1 thorpej 624: int res = 0;
625:
626: if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
1.51 isaki 627: return (ENXIO);
1.5 soda 628: if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
1.1 thorpej 629: bus_space_unmap(iot, ioh_d, 1);
1.51 isaki 630: return (ENXIO);
1.1 thorpej 631: }
632:
1.14 jdolecek 633: memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
1.1 thorpej 634: pckbc_consdata.t_iot = iot;
635: pckbc_consdata.t_ioh_d = ioh_d;
636: pckbc_consdata.t_ioh_c = ioh_c;
637: pckbc_consdata.t_addr = addr;
1.54 jdc 638: pckbc_consdata.t_flags = flags;
1.37 ad 639: callout_init(&pckbc_consdata.t_cleanup, 0);
1.1 thorpej 640:
641: /* flush */
1.31 bjh21 642: (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
1.1 thorpej 643:
1.26 uwe 644: #ifdef PCKBC_CNATTACH_SELFTEST
645: /*
646: * In some machines (e.g. netwinder) pckbc refuses to talk at
647: * all until we request a self-test.
648: */
649: if (!pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST)) {
1.36 christos 650: printf("pckbc: unable to request selftest\n");
1.26 uwe 651: res = EIO;
652: goto out;
653: }
654:
1.31 bjh21 655: reply = pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
1.26 uwe 656: if (reply != 0x55) {
1.36 christos 657: printf("pckbc: selftest returned 0x%02x\n", reply);
1.26 uwe 658: res = EIO;
659: goto out;
660: }
661: #endif /* PCKBC_CNATTACH_SELFTEST */
1.1 thorpej 662:
663: /* init cmd byte, enable ports */
664: pckbc_consdata.t_cmdbyte = KC8_CPU;
665: if (!pckbc_put8042cmd(&pckbc_consdata)) {
1.36 christos 666: printf("pckbc: cmd word write error\n");
1.1 thorpej 667: res = EIO;
1.26 uwe 668: goto out;
1.1 thorpej 669: }
670:
1.31 bjh21 671: res = pckbport_cnattach(&pckbc_consdata, &pckbc_ops, slot);
1.1 thorpej 672:
1.26 uwe 673: out:
1.1 thorpej 674: if (res) {
675: bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
676: bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
677: } else {
678: pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
679: pckbc_init_slotdata(&pckbc_cons_slotdata);
680: pckbc_console = 1;
681: }
682:
683: return (res);
684: }
1.39 jmcneill 685:
686: bool
1.48 dyoung 687: pckbc_resume(device_t dv, const pmf_qual_t *qual)
1.39 jmcneill 688: {
689: struct pckbc_softc *sc = device_private(dv);
690: struct pckbc_internal *t;
691:
692: t = sc->id;
693: (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT);
694: if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c, KBC_SELFTEST))
695: return false;
696: (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT);
697: (void)pckbc_put8042cmd(t);
698: pckbcintr(t->t_sc);
699:
700: return true;
701: }
CVSweb <webmaster@jp.NetBSD.org>