iockbc.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278
  1. /* $OpenBSD: iockbc.c,v 1.11 2015/02/11 07:05:39 dlg Exp $ */
  2. /*
  3. * Copyright (c) 2013, Miodrag Vallat
  4. * Copyright (c) 2006, 2007, 2009 Joel Sing <jsing@openbsd.org>
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. /*
  19. * Derived from sys/dev/ic/pckbc.c under the following terms:
  20. * $NetBSD: pckbc.c,v 1.5 2000/06/09 04:58:35 soda Exp $ */
  21. /*
  22. * Copyright (c) 1998
  23. * Matthias Drochner. All rights reserved.
  24. *
  25. * Redistribution and use in source and binary forms, with or without
  26. * modification, are permitted provided that the following conditions
  27. * are met:
  28. * 1. Redistributions of source code must retain the above copyright
  29. * notice, this list of conditions and the following disclaimer.
  30. * 2. Redistributions in binary form must reproduce the above copyright
  31. * notice, this list of conditions and the following disclaimer in the
  32. * documentation and/or other materials provided with the distribution.
  33. *
  34. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  35. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  36. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  37. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  38. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  39. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  40. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  41. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  43. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. */
  45. /*
  46. * Driver for IOC3 and IOC4 PS/2 Controllers (iockbc)
  47. */
  48. #include <sys/param.h>
  49. #include <sys/systm.h>
  50. #include <sys/device.h>
  51. #include <sys/malloc.h>
  52. #include <sys/timeout.h>
  53. #include <sys/kernel.h>
  54. #include <sys/proc.h>
  55. #include <sys/signalvar.h>
  56. #include <sys/errno.h>
  57. #include <sys/queue.h>
  58. #include <machine/autoconf.h>
  59. #include <machine/bus.h>
  60. #include <mips64/archtype.h>
  61. #include <sgi/pci/iocreg.h>
  62. #include <sgi/pci/iocvar.h>
  63. #include <sgi/pci/iofreg.h>
  64. #include <sgi/pci/iofvar.h>
  65. #include <dev/ic/i8042reg.h>
  66. #include <dev/ic/pckbcvar.h>
  67. #include <dev/pckbc/pckbdreg.h>
  68. #define KBC_DEVCMD_ACK KBR_ACK
  69. #define KBC_DEVCMD_RESEND KBR_RESEND
  70. #include <dev/pckbc/pckbdvar.h>
  71. #include <dev/pci/pcireg.h>
  72. #include <dev/pci/pcidevs.h>
  73. #include <sgi/dev/iockbcreg.h>
  74. #include <sgi/dev/iockbcvar.h>
  75. #include "iockbc.h"
  76. const char *iockbc_slot_names[] = { "kbd", "mouse" };
  77. /* #define IOCKBC_DEBUG */
  78. #ifdef IOCKBC_DEBUG
  79. #define DPRINTF(x...) do { printf(x); } while(0)
  80. #else
  81. #define DPRINTF(x...)
  82. #endif
  83. struct iockbc_reginfo {
  84. bus_addr_t rx;
  85. bus_addr_t tx;
  86. bus_addr_t cs;
  87. uint32_t busy;
  88. };
  89. struct iockbc_softc {
  90. struct pckbc_softc sc_pckbc;
  91. bus_space_tag_t iot;
  92. bus_space_handle_t ioh;
  93. const struct iockbc_reginfo *reginfo;
  94. int console;
  95. };
  96. int iockbc_match(struct device *, void *, void *);
  97. void iockbc_ioc_attach(struct device *, struct device *, void *);
  98. void iockbc_iof_attach(struct device *, struct device *, void *);
  99. #if NIOCKBC_IOC > 0
  100. struct cfattach iockbc_ioc_ca = {
  101. sizeof(struct iockbc_softc), iockbc_match, iockbc_ioc_attach
  102. };
  103. #endif
  104. #if NIOCKBC_IOF > 0
  105. struct cfattach iockbc_iof_ca = {
  106. sizeof(struct iockbc_softc), iockbc_match, iockbc_iof_attach
  107. };
  108. #endif
  109. struct cfdriver iockbc_cd = {
  110. NULL, "iockbc", DV_DULL
  111. };
  112. /* Descriptor for one device command. */
  113. struct pckbc_devcmd {
  114. TAILQ_ENTRY(pckbc_devcmd) next;
  115. int flags;
  116. #define KBC_CMDFLAG_SYNC 1 /* Give descriptor back to caller. */
  117. #define KBC_CMDFLAG_SLOW 2
  118. u_char cmd[4];
  119. int cmdlen, cmdidx, retries;
  120. u_char response[4];
  121. int status, responselen, responseidx;
  122. };
  123. /* Data per slave device. */
  124. struct pckbc_slotdata {
  125. int polling; /* Don't read data port in interrupt handler. */
  126. TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* Active commands. */
  127. TAILQ_HEAD(, pckbc_devcmd) freequeue; /* Free commands. */
  128. #define NCMD 5
  129. struct pckbc_devcmd cmds[NCMD];
  130. int rx_queue[3];
  131. int rx_index;
  132. const struct iockbc_reginfo *reginfo;
  133. };
  134. #define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL)
  135. enum iockbc_slottype { EMPTY, KBD, MOUSE };
  136. static struct pckbc_internal iockbc_consdata;
  137. static struct pckbc_slotdata iockbc_cons_slotdata;
  138. int iockbc_is_ioc_console(struct ioc_attach_args *);
  139. int iockbc_is_iof_console(struct iof_attach_args *);
  140. void iockbc_attach_common(struct iockbc_softc *, bus_addr_t, int,
  141. const struct iockbc_reginfo *, const struct iockbc_reginfo *);
  142. void iockbc_start(struct pckbc_internal *, pckbc_slot_t);
  143. int iockbc_attach_slot(struct iockbc_softc *, pckbc_slot_t);
  144. void iockbc_init_slotdata(struct pckbc_slotdata *,
  145. const struct iockbc_reginfo *);
  146. int iockbc_submatch(struct device *, void *, void *);
  147. int iockbcprint(void *, const char *);
  148. int iockbcintr(void *);
  149. int iockbcintr_internal(struct pckbc_internal *, struct pckbc_softc *);
  150. void iockbc_cleanqueue(struct pckbc_slotdata *);
  151. void iockbc_cleanup(void *);
  152. void iockbc_poll(void *);
  153. int iockbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
  154. int iockbc_poll_read(struct pckbc_internal *, pckbc_slot_t);
  155. int iockbc_poll_write(struct pckbc_internal *, pckbc_slot_t, int);
  156. void iockbc_process_input(struct pckbc_softc *, struct pckbc_internal *,
  157. int, uint);
  158. enum iockbc_slottype
  159. iockbc_probe_slot(struct pckbc_internal *, pckbc_slot_t);
  160. int
  161. iockbc_match(struct device *parent, void *cf, void *aux)
  162. {
  163. /*
  164. * We expect ioc and iof NOT to attach us if there are no PS/2 ports.
  165. */
  166. return 1;
  167. }
  168. #if NIOCKBC_IOC > 0
  169. /*
  170. * Register assignments
  171. */
  172. const struct iockbc_reginfo iockbc_ioc[PCKBC_NSLOTS] = {
  173. [PCKBC_KBD_SLOT] = {
  174. .rx = IOC3_KBC_KBD_RX,
  175. .tx = IOC3_KBC_KBD_TX,
  176. .cs = IOC3_KBC_CTRL_STATUS,
  177. .busy = IOC3_KBC_STATUS_KBD_WRITE_PENDING
  178. },
  179. [PCKBC_AUX_SLOT] = {
  180. .rx = IOC3_KBC_AUX_RX,
  181. .tx = IOC3_KBC_AUX_TX,
  182. .cs = IOC3_KBC_CTRL_STATUS,
  183. .busy = IOC3_KBC_STATUS_AUX_WRITE_PENDING
  184. }
  185. };
  186. const struct iockbc_reginfo iockbc_ioc_inverted[PCKBC_NSLOTS] = {
  187. [PCKBC_KBD_SLOT] = {
  188. .rx = IOC3_KBC_AUX_RX,
  189. .tx = IOC3_KBC_AUX_TX,
  190. .cs = IOC3_KBC_CTRL_STATUS,
  191. .busy = IOC3_KBC_STATUS_AUX_WRITE_PENDING
  192. },
  193. [PCKBC_AUX_SLOT] = {
  194. .rx = IOC3_KBC_KBD_RX,
  195. .tx = IOC3_KBC_KBD_TX,
  196. .cs = IOC3_KBC_CTRL_STATUS,
  197. .busy = IOC3_KBC_STATUS_KBD_WRITE_PENDING
  198. }
  199. };
  200. void
  201. iockbc_ioc_attach(struct device *parent, struct device *self, void *aux)
  202. {
  203. struct iockbc_softc *isc = (void*)self;
  204. struct ioc_attach_args *iaa = aux;
  205. /* Setup bus space mapping. */
  206. isc->iot = iaa->iaa_memt;
  207. isc->ioh = iaa->iaa_memh;
  208. /* Establish interrupt handler. */
  209. if (ioc_intr_establish(parent, iaa->iaa_dev, IPL_TTY, iockbcintr,
  210. (void *)isc, self->dv_xname))
  211. printf("\n");
  212. else
  213. printf(": unable to establish interrupt\n");
  214. iockbc_attach_common(isc, iaa->iaa_base, iockbc_is_ioc_console(iaa),
  215. iockbc_ioc, iockbc_ioc_inverted);
  216. }
  217. #endif
  218. #if NIOCKBC_IOF > 0
  219. /*
  220. * Register assignments
  221. */
  222. const struct iockbc_reginfo iockbc_iof[PCKBC_NSLOTS] = {
  223. [PCKBC_KBD_SLOT] = {
  224. .rx = IOC4_KBC_KBD_RX,
  225. .tx = IOC4_KBC_KBD_TX,
  226. .cs = IOC4_KBC_CTRL_STATUS,
  227. .busy = IOC3_KBC_STATUS_KBD_WRITE_PENDING
  228. },
  229. [PCKBC_AUX_SLOT] = {
  230. .rx = IOC4_KBC_AUX_RX,
  231. .tx = IOC4_KBC_AUX_TX,
  232. .cs = IOC4_KBC_CTRL_STATUS,
  233. .busy = IOC3_KBC_STATUS_AUX_WRITE_PENDING
  234. }
  235. };
  236. const struct iockbc_reginfo iockbc_iof_inverted[PCKBC_NSLOTS] = {
  237. [PCKBC_KBD_SLOT] = {
  238. .rx = IOC4_KBC_AUX_RX,
  239. .tx = IOC4_KBC_AUX_TX,
  240. .cs = IOC4_KBC_CTRL_STATUS,
  241. .busy = IOC3_KBC_STATUS_AUX_WRITE_PENDING
  242. },
  243. [PCKBC_AUX_SLOT] = {
  244. .rx = IOC4_KBC_KBD_RX,
  245. .tx = IOC4_KBC_KBD_TX,
  246. .cs = IOC4_KBC_CTRL_STATUS,
  247. .busy = IOC3_KBC_STATUS_KBD_WRITE_PENDING
  248. }
  249. };
  250. void
  251. iockbc_iof_attach(struct device *parent, struct device *self, void *aux)
  252. {
  253. struct iockbc_softc *isc = (void*)self;
  254. struct iof_attach_args *iaa = aux;
  255. /* Setup bus space mapping. */
  256. isc->iot = iaa->iaa_memt;
  257. isc->ioh = iaa->iaa_memh;
  258. /* Establish interrupt handler. */
  259. if (iof_intr_establish(parent, iaa->iaa_dev, IPL_TTY, iockbcintr,
  260. (void *)isc, self->dv_xname))
  261. printf("\n");
  262. else
  263. printf(": unable to establish interrupt\n");
  264. iockbc_attach_common(isc, iaa->iaa_base, iockbc_is_iof_console(iaa),
  265. iockbc_iof, iockbc_iof_inverted);
  266. }
  267. #endif
  268. void
  269. iockbc_init_slotdata(struct pckbc_slotdata *q,
  270. const struct iockbc_reginfo *reginfo)
  271. {
  272. int i;
  273. TAILQ_INIT(&q->cmdqueue);
  274. TAILQ_INIT(&q->freequeue);
  275. for (i = 0; i < NCMD; i++)
  276. TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next);
  277. q->polling = 0;
  278. q->rx_index = -1;
  279. q->reginfo = reginfo;
  280. }
  281. int
  282. iockbcprint(void *aux, const char *pnp)
  283. {
  284. struct pckbc_attach_args *pa = aux;
  285. if (!pnp)
  286. printf(" (%s slot)", iockbc_slot_names[pa->pa_slot]);
  287. return (QUIET);
  288. }
  289. int
  290. iockbc_submatch(struct device *parent, void *match, void *aux)
  291. {
  292. struct cfdata *cf = match;
  293. struct pckbc_attach_args *pa = aux;
  294. if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT &&
  295. cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot)
  296. return (0);
  297. return ((*cf->cf_attach->ca_match)(parent, cf, pa));
  298. }
  299. /*
  300. * Figure out what kind of device is connected to the given slot, if any.
  301. */
  302. enum iockbc_slottype
  303. iockbc_probe_slot(struct pckbc_internal *t, pckbc_slot_t slot)
  304. {
  305. int rc, i, tries;
  306. /* reset device */
  307. pckbc_flush(t, slot);
  308. for (tries = 0; tries < 5; tries++) {
  309. rc = iockbc_poll_write(t, slot, KBC_RESET);
  310. if (rc < 0) {
  311. DPRINTF(("%s: slot %d write failed\n", __func__, slot));
  312. return EMPTY;
  313. }
  314. for (i = 10; i != 0; i--) {
  315. rc = iockbc_poll_read(t, slot);
  316. if (rc >= 0)
  317. break;
  318. }
  319. if (rc < 0) {
  320. DPRINTF(("%s: slot %d no answer to reset\n",
  321. __func__, slot));
  322. return EMPTY;
  323. }
  324. if (rc == KBC_DEVCMD_ACK)
  325. break;
  326. if (rc == KBC_DEVCMD_RESEND)
  327. continue;
  328. DPRINTF(("%s: slot %d bogus reset ack %02x\n",
  329. __func__, slot, rc));
  330. return EMPTY;
  331. }
  332. /* get answer byte */
  333. for (i = 10; i != 0; i--) {
  334. rc = iockbc_poll_read(t, slot);
  335. if (rc >= 0)
  336. break;
  337. }
  338. if (rc < 0) {
  339. DPRINTF(("%s: slot %d no answer to reset after ack\n",
  340. __func__, slot));
  341. return EMPTY;
  342. }
  343. if (rc != KBR_RSTDONE) {
  344. DPRINTF(("%s: slot %d bogus reset answer %02x\n",
  345. __func__, slot, rc));
  346. return EMPTY;
  347. }
  348. /* mice send an extra byte */
  349. (void)iockbc_poll_read(t, slot);
  350. /* ask for device id */
  351. for (tries = 0; tries < 5; tries++) {
  352. rc = iockbc_poll_write(t, slot, KBC_READID);
  353. if (rc == -1) {
  354. DPRINTF(("%s: slot %d write failed\n", __func__, slot));
  355. return EMPTY;
  356. }
  357. for (i = 10; i != 0; i--) {
  358. rc = iockbc_poll_read(t, slot);
  359. if (rc >= 0)
  360. break;
  361. }
  362. if (rc < 0) {
  363. DPRINTF(("%s: slot %d no answer to command\n",
  364. __func__, slot));
  365. return EMPTY;
  366. }
  367. if (rc == KBC_DEVCMD_ACK)
  368. break;
  369. if (rc == KBC_DEVCMD_RESEND)
  370. continue;
  371. DPRINTF(("%s: slot %d bogus command ack %02x\n",
  372. __func__, slot, rc));
  373. return EMPTY;
  374. }
  375. /* get first answer byte */
  376. for (i = 10; i != 0; i--) {
  377. rc = iockbc_poll_read(t, slot);
  378. if (rc >= 0)
  379. break;
  380. }
  381. if (rc < 0) {
  382. DPRINTF(("%s: slot %d no answer to command after ack\n",
  383. __func__, slot));
  384. return EMPTY;
  385. }
  386. switch (rc) {
  387. case KCID_KBD1: /* keyboard */
  388. /* get second answer byte */
  389. rc = iockbc_poll_read(t, slot);
  390. if (rc < 0) {
  391. DPRINTF(("%s: slot %d truncated keyboard answer\n",
  392. __func__, slot));
  393. return EMPTY;
  394. }
  395. if (rc != KCID_KBD2) {
  396. DPRINTF(("%s: slot %d unexpected keyboard answer"
  397. " 0x%02x 0x%02x\n", __func__, slot, KCID_KBD1, rc));
  398. /* return EMPTY; */
  399. }
  400. return KBD;
  401. case KCID_MOUSE: /* mouse */
  402. return MOUSE;
  403. default:
  404. DPRINTF(("%s: slot %d unknown device answer 0x%02x\n",
  405. __func__, slot, rc));
  406. return EMPTY;
  407. }
  408. }
  409. int
  410. iockbc_attach_slot(struct iockbc_softc *isc, pckbc_slot_t slot)
  411. {
  412. struct pckbc_softc *sc = &isc->sc_pckbc;
  413. struct pckbc_internal *t = sc->id;
  414. struct pckbc_attach_args pa;
  415. int found;
  416. iockbc_init_slotdata(t->t_slotdata[slot], &isc->reginfo[slot]);
  417. pa.pa_tag = t;
  418. pa.pa_slot = slot;
  419. found = (config_found_sm((struct device *)sc, &pa,
  420. iockbcprint, iockbc_submatch) != NULL);
  421. return (found);
  422. }
  423. void
  424. iockbc_attach_common(struct iockbc_softc *isc, bus_addr_t addr, int console,
  425. const struct iockbc_reginfo *reginfo,
  426. const struct iockbc_reginfo *reginfo_inverted)
  427. {
  428. struct pckbc_softc *sc = &isc->sc_pckbc;
  429. struct pckbc_internal *t;
  430. bus_addr_t cs;
  431. uint32_t csr;
  432. pckbc_slot_t slot;
  433. if (console) {
  434. iockbc_consdata.t_sc = sc;
  435. sc->id = t = &iockbc_consdata;
  436. isc->console = 1;
  437. if (&reginfo[PCKBC_KBD_SLOT] == iockbc_cons_slotdata.reginfo)
  438. isc->reginfo = reginfo;
  439. else
  440. isc->reginfo = reginfo_inverted;
  441. } else {
  442. /*
  443. * Setup up controller: do not force pull clock and data lines
  444. * low, clamp clocks after one byte received.
  445. */
  446. cs = reginfo[PCKBC_KBD_SLOT].cs;
  447. csr = bus_space_read_4(isc->iot, isc->ioh, cs);
  448. csr &= ~(IOC3_KBC_CTRL_KBD_PULL_DATA_LOW |
  449. IOC3_KBC_CTRL_KBD_PULL_CLOCK_LOW |
  450. IOC3_KBC_CTRL_AUX_PULL_DATA_LOW |
  451. IOC3_KBC_CTRL_AUX_PULL_CLOCK_LOW |
  452. IOC3_KBC_CTRL_KBD_CLAMP_3 | IOC3_KBC_CTRL_AUX_CLAMP_3);
  453. csr |= IOC3_KBC_CTRL_KBD_CLAMP_1 | IOC3_KBC_CTRL_AUX_CLAMP_1;
  454. bus_space_write_4(isc->iot, isc->ioh, cs, csr);
  455. /* Setup pckbc_internal structure. */
  456. t = malloc(sizeof(struct pckbc_internal), M_DEVBUF,
  457. M_WAITOK | M_ZERO);
  458. t->t_iot = isc->iot;
  459. t->t_ioh_d = isc->ioh;
  460. t->t_ioh_c = isc->ioh;
  461. t->t_addr = addr;
  462. t->t_sc = sc;
  463. sc->id = t;
  464. timeout_set(&t->t_cleanup, iockbc_cleanup, t);
  465. timeout_set(&t->t_poll, iockbc_poll, t);
  466. isc->reginfo = reginfo;
  467. }
  468. for (slot = 0; slot < PCKBC_NSLOTS; slot++) {
  469. if (t->t_slotdata[slot] == NULL) {
  470. t->t_slotdata[slot] =
  471. malloc(sizeof(struct pckbc_slotdata),
  472. M_DEVBUF, M_WAITOK);
  473. }
  474. }
  475. if (!console) {
  476. enum iockbc_slottype slottype;
  477. int mouse_on_main = 0;
  478. /*
  479. * Probe for a keyboard. If none is found at the regular
  480. * keyboard port, but one is found at the mouse port, then
  481. * it is likely that this particular system has both ports
  482. * inverted (or incorrect labels on the chassis), unless
  483. * this is a human error. In any case, try to get the
  484. * keyboard to attach to the `keyboard' port and the
  485. * pointing device to the `mouse' port.
  486. */
  487. for (slot = 0; slot < PCKBC_NSLOTS; slot++) {
  488. iockbc_init_slotdata(t->t_slotdata[slot],
  489. &isc->reginfo[slot]);
  490. slottype = iockbc_probe_slot(t, slot);
  491. if (slottype == KBD)
  492. break;
  493. if (slottype == MOUSE)
  494. mouse_on_main = slot == PCKBC_KBD_SLOT;
  495. }
  496. if (slot == PCKBC_NSLOTS) {
  497. /*
  498. * We could not identify a keyboard. Let's assume
  499. * none is connected; if a mouse has been found on
  500. * the keyboard port and none on the aux port, the
  501. * ports are likely to be inverted.
  502. */
  503. if (mouse_on_main)
  504. slot = PCKBC_AUX_SLOT;
  505. else
  506. slot = PCKBC_KBD_SLOT;
  507. }
  508. if (slot == PCKBC_AUX_SLOT) {
  509. /*
  510. * Either human error or inverted wiring; use
  511. * the inverted port settings.
  512. * iockbc_attach_slot() below will call
  513. * iockbc_init_slotdata() again.
  514. */
  515. isc->reginfo = reginfo_inverted;
  516. }
  517. }
  518. /*
  519. * Attach "slots".
  520. */
  521. iockbc_attach_slot(isc, PCKBC_KBD_SLOT);
  522. iockbc_attach_slot(isc, PCKBC_AUX_SLOT);
  523. }
  524. void
  525. iockbc_poll(void *self)
  526. {
  527. struct pckbc_internal *t = self;
  528. int s;
  529. s = spltty();
  530. (void)iockbcintr_internal(t, t->t_sc);
  531. timeout_add_sec(&t->t_poll, 1);
  532. splx(s);
  533. }
  534. int
  535. iockbcintr(void *vsc)
  536. {
  537. struct iockbc_softc *isc = (struct iockbc_softc *)vsc;
  538. struct pckbc_softc *sc = &isc->sc_pckbc;
  539. struct pckbc_internal *t = sc->id;
  540. return iockbcintr_internal(t, sc);
  541. }
  542. int
  543. iockbcintr_internal(struct pckbc_internal *t, struct pckbc_softc *sc)
  544. {
  545. pckbc_slot_t slot;
  546. struct pckbc_slotdata *q;
  547. int served = 0;
  548. uint32_t data;
  549. uint32_t val;
  550. /* Reschedule timeout further into the idle times. */
  551. if (timeout_pending(&t->t_poll))
  552. timeout_add_sec(&t->t_poll, 1);
  553. /*
  554. * Need to check both "slots" since interrupt could be from
  555. * either controller.
  556. */
  557. for (slot = 0; slot < PCKBC_NSLOTS; slot++) {
  558. q = t->t_slotdata[slot];
  559. for (;;) {
  560. if (!q) {
  561. DPRINTF("iockbcintr: no slot%d data!\n", slot);
  562. break;
  563. }
  564. if (q->polling) {
  565. served = 1;
  566. break; /* pckbc_poll_data() will get it */
  567. }
  568. val = bus_space_read_4(t->t_iot, t->t_ioh_d,
  569. q->reginfo->rx);
  570. if ((val & IOC3_KBC_DATA_VALID) == 0)
  571. break;
  572. served = 1;
  573. /* Process received data. */
  574. if (val & IOC3_KBC_DATA_0_VALID) {
  575. data = (val & IOC3_KBC_DATA_0_MASK) >>
  576. IOC3_KBC_DATA_0_SHIFT;
  577. iockbc_process_input(sc, t, slot, data);
  578. }
  579. if (val & IOC3_KBC_DATA_1_VALID) {
  580. data = (val & IOC3_KBC_DATA_1_MASK) >>
  581. IOC3_KBC_DATA_1_SHIFT;
  582. iockbc_process_input(sc, t, slot, data);
  583. }
  584. if (val & IOC3_KBC_DATA_2_VALID) {
  585. data = (val & IOC3_KBC_DATA_2_MASK) >>
  586. IOC3_KBC_DATA_2_SHIFT;
  587. iockbc_process_input(sc, t, slot, data);
  588. }
  589. }
  590. }
  591. return (served);
  592. }
  593. void
  594. iockbc_process_input(struct pckbc_softc *sc, struct pckbc_internal *t,
  595. int slot, uint data)
  596. {
  597. struct pckbc_slotdata *q;
  598. q = t->t_slotdata[slot];
  599. if (CMD_IN_QUEUE(q) && iockbc_cmdresponse(t, slot, data))
  600. return;
  601. if (sc->inputhandler[slot])
  602. (*sc->inputhandler[slot])(sc->inputarg[slot], data);
  603. else
  604. DPRINTF("iockbcintr: slot %d lost %d\n", slot, data);
  605. }
  606. int
  607. iockbc_poll_write(struct pckbc_internal *t, pckbc_slot_t slot, int val)
  608. {
  609. struct pckbc_slotdata *q = t->t_slotdata[slot];
  610. bus_space_tag_t iot = t->t_iot;
  611. bus_space_handle_t ioh = t->t_ioh_d;
  612. u_int64_t stat;
  613. int timeout = 10000;
  614. /* Attempt to write a value to the controller. */
  615. while (timeout--) {
  616. stat = bus_space_read_4(iot, ioh, q->reginfo->cs);
  617. if ((stat & q->reginfo->busy) == 0) {
  618. bus_space_write_4(iot, ioh, q->reginfo->tx, val & 0xff);
  619. return 0;
  620. }
  621. delay(50);
  622. }
  623. DPRINTF("iockbc_poll_write: timeout, sts %08x\n", stat);
  624. return -1;
  625. }
  626. int
  627. iockbc_poll_read(struct pckbc_internal *t, pckbc_slot_t slot)
  628. {
  629. struct pckbc_slotdata *q = t->t_slotdata[slot];
  630. int timeout = 10000;
  631. u_int32_t val;
  632. /* See if we already have bytes queued. */
  633. if (q->rx_index >= 0)
  634. return q->rx_queue[q->rx_index--];
  635. /* Poll input from controller. */
  636. while (timeout--) {
  637. val = bus_space_read_4(t->t_iot, t->t_ioh_d, q->reginfo->rx);
  638. if (val & IOC3_KBC_DATA_VALID)
  639. break;
  640. delay(50);
  641. }
  642. if ((val & IOC3_KBC_DATA_VALID) == 0) {
  643. DPRINTF("iockbc_poll_read: timeout, wx %08x\n", val);
  644. return -1;
  645. }
  646. /* Process received data. */
  647. if (val & IOC3_KBC_DATA_2_VALID)
  648. q->rx_queue[++q->rx_index] =
  649. (val & IOC3_KBC_DATA_2_MASK) >> IOC3_KBC_DATA_2_SHIFT;
  650. if (val & IOC3_KBC_DATA_1_VALID)
  651. q->rx_queue[++q->rx_index] =
  652. (val & IOC3_KBC_DATA_1_MASK) >> IOC3_KBC_DATA_1_SHIFT;
  653. if (val & IOC3_KBC_DATA_0_VALID)
  654. q->rx_queue[++q->rx_index] =
  655. (val & IOC3_KBC_DATA_0_MASK) >> IOC3_KBC_DATA_0_SHIFT;
  656. if (q->rx_index >= 0)
  657. return q->rx_queue[q->rx_index--];
  658. else
  659. return -1;
  660. }
  661. /*
  662. * Pass command to device, poll for ACK and data.
  663. * to be called at spltty()
  664. */
  665. static void
  666. iockbc_poll_cmd(struct pckbc_internal *t, pckbc_slot_t slot,
  667. struct pckbc_devcmd *cmd)
  668. {
  669. int i, c = 0;
  670. while (cmd->cmdidx < cmd->cmdlen) {
  671. if (iockbc_poll_write(t, slot, cmd->cmd[cmd->cmdidx]) == -1) {
  672. DPRINTF("iockbc_poll_cmd: send error\n");
  673. cmd->status = EIO;
  674. return;
  675. }
  676. for (i = 10; i; i--) { /* 1s ??? */
  677. c = iockbc_poll_read(t, slot);
  678. if (c != -1)
  679. break;
  680. }
  681. if (c == KBC_DEVCMD_ACK) {
  682. cmd->cmdidx++;
  683. continue;
  684. }
  685. if (c == KBC_DEVCMD_RESEND) {
  686. DPRINTF("iockbc_cmd: RESEND\n");
  687. if (cmd->retries++ < 5)
  688. continue;
  689. else {
  690. DPRINTF("iockbc: cmd failed\n");
  691. cmd->status = EIO;
  692. return;
  693. }
  694. }
  695. if (c == -1) {
  696. DPRINTF("iockbc_cmd: timeout\n");
  697. cmd->status = EIO;
  698. return;
  699. }
  700. DPRINTF("iockbc_cmd: lost 0x%x\n", c);
  701. }
  702. while (cmd->responseidx < cmd->responselen) {
  703. if (cmd->flags & KBC_CMDFLAG_SLOW)
  704. i = 100; /* 10s ??? */
  705. else
  706. i = 10; /* 1s ??? */
  707. while (i--) {
  708. c = iockbc_poll_read(t, slot);
  709. if (c != -1)
  710. break;
  711. }
  712. if (c == -1) {
  713. DPRINTF("iockbc_poll_cmd: no data\n");
  714. cmd->status = ETIMEDOUT;
  715. return;
  716. } else
  717. cmd->response[cmd->responseidx++] = c;
  718. }
  719. }
  720. /*
  721. * Clean up a command queue, throw away everything.
  722. */
  723. void
  724. iockbc_cleanqueue(struct pckbc_slotdata *q)
  725. {
  726. struct pckbc_devcmd *cmd;
  727. #ifdef IOCKBC_DEBUG
  728. int i;
  729. #endif
  730. while ((cmd = TAILQ_FIRST(&q->cmdqueue))) {
  731. TAILQ_REMOVE(&q->cmdqueue, cmd, next);
  732. #ifdef IOCKBC_DEBUG
  733. printf("iockbc_cleanqueue: removing");
  734. for (i = 0; i < cmd->cmdlen; i++)
  735. printf(" %02x", cmd->cmd[i]);
  736. printf("\n");
  737. #endif
  738. TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
  739. }
  740. }
  741. /*
  742. * Timeout error handler: clean queues and data port.
  743. * XXX could be less invasive.
  744. */
  745. void
  746. iockbc_cleanup(void *self)
  747. {
  748. struct pckbc_internal *t = self;
  749. int s;
  750. printf("iockbc: command timeout\n");
  751. s = spltty();
  752. if (t->t_slotdata[PCKBC_KBD_SLOT])
  753. iockbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
  754. if (t->t_slotdata[PCKBC_AUX_SLOT])
  755. iockbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
  756. while (iockbc_poll_read(t, PCKBC_KBD_SLOT)
  757. != -1) ;
  758. while (iockbc_poll_read(t, PCKBC_AUX_SLOT)
  759. != -1) ;
  760. /* Reset KBC? */
  761. splx(s);
  762. }
  763. /*
  764. * Pass command to device during normal operation.
  765. * to be called at spltty()
  766. */
  767. void
  768. iockbc_start(struct pckbc_internal *t, pckbc_slot_t slot)
  769. {
  770. struct pckbc_slotdata *q = t->t_slotdata[slot];
  771. struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
  772. if (q->polling) {
  773. do {
  774. iockbc_poll_cmd(t, slot, cmd);
  775. if (cmd->status)
  776. printf("iockbc_start: command error\n");
  777. TAILQ_REMOVE(&q->cmdqueue, cmd, next);
  778. if (cmd->flags & KBC_CMDFLAG_SYNC)
  779. wakeup(cmd);
  780. else {
  781. timeout_del(&t->t_cleanup);
  782. TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
  783. }
  784. cmd = TAILQ_FIRST(&q->cmdqueue);
  785. } while (cmd);
  786. return;
  787. }
  788. if (iockbc_poll_write(t, slot, cmd->cmd[cmd->cmdidx])) {
  789. printf("iockbc_start: send error\n");
  790. /* XXX what now? */
  791. return;
  792. }
  793. }
  794. /*
  795. * Handle command responses coming in asynchronously,
  796. * return nonzero if valid response.
  797. * to be called at spltty()
  798. */
  799. int
  800. iockbc_cmdresponse(struct pckbc_internal *t, pckbc_slot_t slot, u_char data)
  801. {
  802. struct pckbc_slotdata *q = t->t_slotdata[slot];
  803. struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
  804. #ifdef DIAGNOSTIC
  805. if (!cmd)
  806. panic("iockbc_cmdresponse: no active command");
  807. #endif
  808. if (cmd->cmdidx < cmd->cmdlen) {
  809. if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
  810. return (0);
  811. if (data == KBC_DEVCMD_RESEND) {
  812. if (cmd->retries++ < 5) {
  813. /* try again last command */
  814. goto restart;
  815. } else {
  816. DPRINTF("iockbc: cmd failed\n");
  817. cmd->status = EIO;
  818. /* dequeue */
  819. }
  820. } else {
  821. if (++cmd->cmdidx < cmd->cmdlen)
  822. goto restart;
  823. if (cmd->responselen)
  824. return (1);
  825. /* else dequeue */
  826. }
  827. } else if (cmd->responseidx < cmd->responselen) {
  828. cmd->response[cmd->responseidx++] = data;
  829. if (cmd->responseidx < cmd->responselen)
  830. return (1);
  831. /* else dequeue */
  832. } else
  833. return (0);
  834. /* dequeue: */
  835. TAILQ_REMOVE(&q->cmdqueue, cmd, next);
  836. if (cmd->flags & KBC_CMDFLAG_SYNC)
  837. wakeup(cmd);
  838. else {
  839. timeout_del(&t->t_cleanup);
  840. TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
  841. }
  842. if (!CMD_IN_QUEUE(q))
  843. return (1);
  844. restart:
  845. iockbc_start(t, slot);
  846. return (1);
  847. }
  848. /*
  849. * Interfaces to act like pckbc(4).
  850. */
  851. int
  852. pckbc_xt_translation(pckbc_tag_t self)
  853. {
  854. /* Translation isn't supported... */
  855. return (-1);
  856. }
  857. /* For use in autoconfiguration. */
  858. int
  859. pckbc_poll_cmd(pckbc_tag_t self, pckbc_slot_t slot, u_char *cmd, int len,
  860. int responselen, u_char *respbuf, int slow)
  861. {
  862. struct pckbc_devcmd nc;
  863. int s;
  864. if ((len > 4) || (responselen > 4))
  865. return (EINVAL);
  866. bzero(&nc, sizeof(nc));
  867. bcopy(cmd, nc.cmd, len);
  868. nc.cmdlen = len;
  869. nc.responselen = responselen;
  870. nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
  871. s = spltty();
  872. iockbc_poll_cmd(self, slot, &nc);
  873. splx(s);
  874. if (nc.status == 0 && respbuf)
  875. bcopy(nc.response, respbuf, responselen);
  876. return (nc.status);
  877. }
  878. void
  879. pckbc_flush(pckbc_tag_t self, pckbc_slot_t slot)
  880. {
  881. /* Read any data and discard. */
  882. struct pckbc_internal *t = self;
  883. (void) iockbc_poll_read(t, slot);
  884. }
  885. /*
  886. * Put command into the device's command queue, return zero or errno.
  887. */
  888. int
  889. pckbc_enqueue_cmd(pckbc_tag_t self, pckbc_slot_t slot, u_char *cmd, int len,
  890. int responselen, int sync, u_char *respbuf)
  891. {
  892. struct pckbc_internal *t = self;
  893. struct pckbc_slotdata *q = t->t_slotdata[slot];
  894. struct pckbc_devcmd *nc;
  895. int s, isactive, res = 0;
  896. if ((len > 4) || (responselen > 4))
  897. return (EINVAL);
  898. s = spltty();
  899. nc = TAILQ_FIRST(&q->freequeue);
  900. if (nc)
  901. TAILQ_REMOVE(&q->freequeue, nc, next);
  902. splx(s);
  903. if (!nc)
  904. return (ENOMEM);
  905. bzero(nc, sizeof(*nc));
  906. bcopy(cmd, nc->cmd, len);
  907. nc->cmdlen = len;
  908. nc->responselen = responselen;
  909. nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0);
  910. s = spltty();
  911. if (q->polling && sync) {
  912. /*
  913. * XXX We should poll until the queue is empty.
  914. * But we don't come here normally, so make
  915. * it simple and throw away everything.
  916. */
  917. iockbc_cleanqueue(q);
  918. }
  919. isactive = CMD_IN_QUEUE(q);
  920. TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next);
  921. if (!isactive)
  922. iockbc_start(t, slot);
  923. if (q->polling)
  924. res = (sync ? nc->status : 0);
  925. else if (sync) {
  926. if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) {
  927. TAILQ_REMOVE(&q->cmdqueue, nc, next);
  928. iockbc_cleanup(t);
  929. } else
  930. res = nc->status;
  931. } else
  932. timeout_add_sec(&t->t_cleanup, 1);
  933. if (sync) {
  934. if (respbuf)
  935. bcopy(nc->response, respbuf, responselen);
  936. TAILQ_INSERT_TAIL(&q->freequeue, nc, next);
  937. }
  938. splx(s);
  939. return (res);
  940. }
  941. int
  942. pckbc_poll_data(pckbc_tag_t self, pckbc_slot_t slot)
  943. {
  944. struct pckbc_internal *t = self;
  945. struct pckbc_slotdata *q = t->t_slotdata[slot];
  946. int c;
  947. c = iockbc_poll_read(t, slot);
  948. if (c != -1 && q && CMD_IN_QUEUE(q)) {
  949. /* We jumped into a running command - try to deliver the
  950. response. */
  951. if (iockbc_cmdresponse(t, slot, c))
  952. return (-1);
  953. }
  954. return (c);
  955. }
  956. void
  957. pckbc_set_inputhandler(pckbc_tag_t self, pckbc_slot_t slot, pckbc_inputfcn func,
  958. void *arg, char *name)
  959. {
  960. struct pckbc_internal *t = (struct pckbc_internal *)self;
  961. struct pckbc_softc *sc = t->t_sc;
  962. struct iockbc_softc *isc = (struct iockbc_softc *)sc;
  963. if (slot >= PCKBC_NSLOTS)
  964. panic("iockbc_set_inputhandler: bad slot %d", slot);
  965. sc->inputhandler[slot] = func;
  966. sc->inputarg[slot] = arg;
  967. sc->subname[slot] = name;
  968. if ((isc == NULL || isc->console) && slot == PCKBC_KBD_SLOT)
  969. timeout_add_sec(&t->t_poll, 1);
  970. }
  971. void
  972. pckbc_slot_enable(pckbc_tag_t self, pckbc_slot_t slot, int on)
  973. {
  974. struct pckbc_internal *t = (struct pckbc_internal *)self;
  975. if (slot == PCKBC_KBD_SLOT) {
  976. if (on)
  977. timeout_add_sec(&t->t_poll, 1);
  978. else
  979. timeout_del(&t->t_poll);
  980. }
  981. }
  982. void
  983. pckbc_set_poll(pckbc_tag_t self, pckbc_slot_t slot, int on)
  984. {
  985. struct pckbc_internal *t = (struct pckbc_internal *)self;
  986. t->t_slotdata[slot]->polling = on;
  987. if (!on) {
  988. int s;
  989. /*
  990. * If disabling polling on a device that's been configured,
  991. * make sure there are no bytes left in the FIFO, holding up
  992. * the interrupt line. Otherwise we won't get any further
  993. * interrupts.
  994. */
  995. if (t->t_sc) {
  996. s = spltty();
  997. iockbcintr(t->t_sc);
  998. splx(s);
  999. }
  1000. }
  1001. }
  1002. /*
  1003. * Console support.
  1004. */
  1005. static int iockbc_console;
  1006. int
  1007. iockbc_cnattach()
  1008. {
  1009. bus_space_tag_t iot = &sys_config.console_io;
  1010. bus_space_handle_t ioh = (bus_space_handle_t)iot->bus_base;
  1011. struct pckbc_internal *t = &iockbc_consdata;
  1012. const struct iockbc_reginfo *reginfo = NULL, *reginfo_inverted;
  1013. enum iockbc_slottype slottype;
  1014. pckbc_slot_t slot;
  1015. uint32_t csr;
  1016. int is_ioc;
  1017. int rc;
  1018. is_ioc = console_input.specific ==
  1019. PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3);
  1020. if (is_ioc) {
  1021. #if NIOCKBC_IOC > 0
  1022. reginfo = iockbc_ioc;
  1023. reginfo_inverted = iockbc_ioc_inverted;
  1024. #endif
  1025. } else {
  1026. #if NIOCKBC_IOF > 0
  1027. reginfo = iockbc_iof;
  1028. reginfo_inverted = iockbc_iof_inverted;
  1029. #endif
  1030. }
  1031. if (reginfo == NULL)
  1032. return ENXIO;
  1033. /*
  1034. * Setup up controller: do not force pull clock and data lines
  1035. * low, clamp clocks after one byte received.
  1036. */
  1037. csr = bus_space_read_4(iot, ioh, reginfo->cs);
  1038. csr &= ~(IOC3_KBC_CTRL_KBD_PULL_DATA_LOW |
  1039. IOC3_KBC_CTRL_KBD_PULL_CLOCK_LOW |
  1040. IOC3_KBC_CTRL_AUX_PULL_DATA_LOW |
  1041. IOC3_KBC_CTRL_AUX_PULL_CLOCK_LOW |
  1042. IOC3_KBC_CTRL_KBD_CLAMP_3 | IOC3_KBC_CTRL_AUX_CLAMP_3);
  1043. csr |= IOC3_KBC_CTRL_KBD_CLAMP_1 | IOC3_KBC_CTRL_AUX_CLAMP_1;
  1044. bus_space_write_4(iot, ioh, reginfo->cs, csr);
  1045. /* Setup pckbc_internal structure. */
  1046. t->t_iot = iot;
  1047. t->t_ioh_d = (bus_space_handle_t)iot->bus_base;
  1048. t->t_addr = 0; /* unused */
  1049. timeout_set(&t->t_cleanup, iockbc_cleanup, t);
  1050. timeout_set(&t->t_poll, iockbc_poll, t);
  1051. /*
  1052. * Probe for a keyboard. There must be one connected, for the PROM
  1053. * would not have advertized glass console if none had been
  1054. * detected.
  1055. */
  1056. for (slot = 0; slot < PCKBC_NSLOTS; slot++) {
  1057. iockbc_init_slotdata(&iockbc_cons_slotdata, &reginfo[slot]);
  1058. t->t_slotdata[slot] = &iockbc_cons_slotdata;
  1059. slottype = iockbc_probe_slot(t, slot);
  1060. t->t_slotdata[slot] = NULL;
  1061. if (slottype == KBD)
  1062. break;
  1063. }
  1064. if (slot == PCKBC_NSLOTS) {
  1065. /*
  1066. * We could not identify a keyboard, but the PROM did;
  1067. * let's assume it's a fluke and assume it exists and
  1068. * is connected to the first connector.
  1069. */
  1070. slot = PCKBC_KBD_SLOT;
  1071. /*
  1072. * For some reason keyboard and mouse ports are inverted on
  1073. * Fuel. They also are inverted on some IO9 boards, but
  1074. * we can't tell both IO9 flavour apart, yet.
  1075. */
  1076. if (is_ioc && sys_config.system_type == SGI_IP35)
  1077. slot = PCKBC_AUX_SLOT;
  1078. }
  1079. if (slot == PCKBC_AUX_SLOT) {
  1080. /*
  1081. * Either human error when plugging the keyboard, or the
  1082. * physical connectors on the chassis are inverted.
  1083. * Compensate by switching in software (pckbd relies upon
  1084. * being at PCKBC_KBD_SLOT).
  1085. */
  1086. reginfo = reginfo_inverted;
  1087. }
  1088. iockbc_init_slotdata(&iockbc_cons_slotdata, &reginfo[PCKBC_KBD_SLOT]);
  1089. t->t_slotdata[PCKBC_KBD_SLOT] = &iockbc_cons_slotdata;
  1090. rc = pckbd_cnattach(t);
  1091. if (rc == 0)
  1092. iockbc_console = 1;
  1093. return rc;
  1094. }
  1095. #if NIOCKBC_IOC > 0
  1096. int
  1097. iockbc_is_ioc_console(struct ioc_attach_args *iaa)
  1098. {
  1099. if (iockbc_console == 0)
  1100. return 0;
  1101. return location_match(&iaa->iaa_location, &console_input);
  1102. }
  1103. #endif
  1104. #if NIOCKBC_IOF > 0
  1105. int
  1106. iockbc_is_iof_console(struct iof_attach_args *iaa)
  1107. {
  1108. if (iockbc_console == 0)
  1109. return 0;
  1110. return location_match(&iaa->iaa_location, &console_input);
  1111. }
  1112. #endif