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