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