1 1.9 chs /* $NetBSD: macekbc.c,v 1.9 2019/10/01 18:00:07 chs Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2007 Jared D. McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 14 1.1 jmcneill * documentation and/or other materials provided with the distribution. 15 1.1 jmcneill * 16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE. 27 1.1 jmcneill */ 28 1.1 jmcneill 29 1.1 jmcneill /* 30 1.1 jmcneill * SGI MACE PS2 keyboard/mouse controller driver 31 1.1 jmcneill */ 32 1.1 jmcneill 33 1.1 jmcneill #include <sys/cdefs.h> 34 1.9 chs __KERNEL_RCSID(0, "$NetBSD: macekbc.c,v 1.9 2019/10/01 18:00:07 chs Exp $"); 35 1.1 jmcneill 36 1.1 jmcneill #include <sys/param.h> 37 1.1 jmcneill #include <sys/device.h> 38 1.1 jmcneill #include <sys/syslog.h> 39 1.8 macallan #include <sys/kmem.h> 40 1.1 jmcneill 41 1.6 dyoung #include <sys/bus.h> 42 1.1 jmcneill #include <machine/intr.h> 43 1.1 jmcneill 44 1.1 jmcneill #include <sgimips/mace/macevar.h> 45 1.1 jmcneill 46 1.2 jmcneill #include <dev/arcbios/arcbios.h> 47 1.2 jmcneill #include <dev/arcbios/arcbiosvar.h> 48 1.1 jmcneill #include <dev/pckbport/pckbportvar.h> 49 1.1 jmcneill 50 1.1 jmcneill #define MACEKBC_TX 0x00 51 1.1 jmcneill #define MACEKBC_RX 0x08 52 1.1 jmcneill #define MACEKBC_CTRL 0x10 53 1.1 jmcneill #define MACEKBC_CTRL_TXCLKOFF (1 << 0) 54 1.1 jmcneill #define MACEKBC_CTRL_TXON (1 << 1) 55 1.1 jmcneill #define MACEKBC_CTRL_TXINTEN (1 << 2) 56 1.1 jmcneill #define MACEKBC_CTRL_RXINTEN (1 << 3) 57 1.1 jmcneill #define MACEKBC_CTRL_RXCLKON (1 << 4) 58 1.1 jmcneill #define MACEKBC_CTRL_RESET (1 << 5) 59 1.1 jmcneill #define MACEKBC_STAT 0x18 60 1.1 jmcneill #define MACEKBC_STAT_TXEMPTY (1 << 3) 61 1.1 jmcneill #define MACEKBC_STAT_RXFULL (1 << 4) 62 1.1 jmcneill 63 1.1 jmcneill struct macekbc_softc { 64 1.1 jmcneill struct macekbc_internal *sc_id; 65 1.1 jmcneill 66 1.1 jmcneill bus_space_tag_t sc_iot; 67 1.1 jmcneill bus_space_handle_t sc_ioh; 68 1.1 jmcneill }; 69 1.1 jmcneill 70 1.1 jmcneill struct macekbc_internal { 71 1.1 jmcneill struct macekbc_softc *t_sc; 72 1.1 jmcneill pckbport_tag_t t_pt; 73 1.1 jmcneill 74 1.1 jmcneill bus_space_tag_t t_iot; 75 1.1 jmcneill bus_space_handle_t t_ioh[PCKBPORT_NSLOTS]; 76 1.2 jmcneill int t_present[PCKBPORT_NSLOTS]; 77 1.1 jmcneill 78 1.1 jmcneill void *t_rxih; 79 1.1 jmcneill }; 80 1.1 jmcneill 81 1.1 jmcneill static int macekbc_intr(void *); 82 1.1 jmcneill static void macekbc_reset(struct macekbc_internal *, pckbport_slot_t); 83 1.1 jmcneill 84 1.1 jmcneill static int macekbc_xt_translation(void *, pckbport_slot_t, int); 85 1.1 jmcneill static int macekbc_send_devcmd(void *, pckbport_slot_t, u_char); 86 1.1 jmcneill static int macekbc_poll_data1(void *, pckbport_slot_t); 87 1.1 jmcneill static void macekbc_slot_enable(void *, pckbport_slot_t, int); 88 1.1 jmcneill static void macekbc_intr_establish(void *, pckbport_slot_t); 89 1.1 jmcneill static void macekbc_set_poll(void *, pckbport_slot_t, int); 90 1.1 jmcneill 91 1.7 chs static int macekbc_match(device_t, cfdata_t, void *); 92 1.7 chs static void macekbc_attach(device_t, device_t, void *); 93 1.1 jmcneill 94 1.7 chs CFATTACH_DECL_NEW(macekbc, sizeof(struct macekbc_softc), 95 1.1 jmcneill macekbc_match, macekbc_attach, NULL, NULL); 96 1.1 jmcneill 97 1.1 jmcneill static struct pckbport_accessops macekbc_ops = { 98 1.1 jmcneill .t_xt_translation = macekbc_xt_translation, 99 1.1 jmcneill .t_send_devcmd = macekbc_send_devcmd, 100 1.1 jmcneill .t_poll_data1 = macekbc_poll_data1, 101 1.1 jmcneill .t_slot_enable = macekbc_slot_enable, 102 1.1 jmcneill .t_intr_establish = macekbc_intr_establish, 103 1.1 jmcneill .t_set_poll = macekbc_set_poll, 104 1.1 jmcneill }; 105 1.1 jmcneill 106 1.1 jmcneill static int 107 1.7 chs macekbc_match(device_t parent, cfdata_t match, void *aux) 108 1.1 jmcneill { 109 1.2 jmcneill 110 1.1 jmcneill return 1; 111 1.1 jmcneill } 112 1.1 jmcneill 113 1.1 jmcneill static void 114 1.7 chs macekbc_attach(device_t parent, device_t self, void *aux) 115 1.1 jmcneill { 116 1.1 jmcneill struct mace_attach_args *maa; 117 1.1 jmcneill struct macekbc_softc *sc; 118 1.1 jmcneill struct macekbc_internal *t; 119 1.2 jmcneill int slot; 120 1.3 tnn const char *consdev; 121 1.1 jmcneill 122 1.1 jmcneill maa = aux; 123 1.1 jmcneill sc = device_private(self); 124 1.1 jmcneill 125 1.1 jmcneill aprint_normal(": PS2 controller\n"); 126 1.1 jmcneill aprint_naive("\n"); 127 1.1 jmcneill 128 1.9 chs t = kmem_alloc(sizeof(struct macekbc_internal), KM_SLEEP); 129 1.1 jmcneill t->t_iot = maa->maa_st; 130 1.2 jmcneill for (slot = 0; slot < PCKBPORT_NSLOTS; slot++) 131 1.2 jmcneill t->t_present[slot] = 0; 132 1.1 jmcneill if (bus_space_subregion(t->t_iot, maa->maa_sh, maa->maa_offset, 133 1.1 jmcneill 0, &t->t_ioh[PCKBPORT_KBD_SLOT]) != 0) { 134 1.1 jmcneill aprint_error("%s: couldn't map kbd registers\n", 135 1.1 jmcneill device_xname(self)); 136 1.8 macallan goto bork; 137 1.1 jmcneill } 138 1.1 jmcneill if (bus_space_subregion(t->t_iot, maa->maa_sh, maa->maa_offset + 32, 139 1.1 jmcneill 0, &t->t_ioh[PCKBPORT_AUX_SLOT]) != 0) { 140 1.1 jmcneill aprint_error("%s: couldn't map aux registers\n", 141 1.1 jmcneill device_xname(self)); 142 1.8 macallan goto bork; 143 1.1 jmcneill } 144 1.1 jmcneill 145 1.1 jmcneill if ((t->t_rxih = cpu_intr_establish(maa->maa_intr, maa->maa_intrmask, 146 1.1 jmcneill macekbc_intr, t)) == NULL) { 147 1.1 jmcneill printf("%s: couldn't establish interrupt\n", 148 1.1 jmcneill device_xname(self)); 149 1.8 macallan goto bork; 150 1.1 jmcneill } 151 1.1 jmcneill sc->sc_id = t; 152 1.1 jmcneill t->t_sc = sc; 153 1.1 jmcneill 154 1.1 jmcneill macekbc_reset(t, PCKBPORT_KBD_SLOT); 155 1.1 jmcneill macekbc_reset(t, PCKBPORT_AUX_SLOT); 156 1.1 jmcneill 157 1.5 matt consdev = arcbios_GetEnvironmentVariable("ConsoleIn"); 158 1.3 tnn if (consdev != NULL && strcmp(consdev, "keyboard()") == 0) 159 1.3 tnn pckbport_cnattach(t, &macekbc_ops, PCKBPORT_KBD_SLOT); 160 1.3 tnn 161 1.1 jmcneill t->t_pt = pckbport_attach(t, &macekbc_ops); 162 1.7 chs if (pckbport_attach_slot(self, t->t_pt, PCKBPORT_KBD_SLOT)) 163 1.2 jmcneill t->t_present[PCKBPORT_KBD_SLOT] = 1; 164 1.7 chs if (pckbport_attach_slot(self, t->t_pt, PCKBPORT_AUX_SLOT)) 165 1.2 jmcneill t->t_present[PCKBPORT_AUX_SLOT] = 1; 166 1.1 jmcneill 167 1.1 jmcneill return; 168 1.8 macallan bork: 169 1.8 macallan kmem_free(t, sizeof(struct macekbc_internal)); 170 1.8 macallan return; 171 1.1 jmcneill } 172 1.1 jmcneill 173 1.1 jmcneill static int 174 1.1 jmcneill macekbc_intr(void *opaque) 175 1.1 jmcneill { 176 1.1 jmcneill struct macekbc_internal *t; 177 1.1 jmcneill bus_space_tag_t iot; 178 1.1 jmcneill bus_space_handle_t ioh; 179 1.1 jmcneill uint64_t stat, val; 180 1.1 jmcneill pckbport_slot_t slot; 181 1.1 jmcneill int rv; 182 1.1 jmcneill 183 1.1 jmcneill t = opaque; 184 1.1 jmcneill iot = t->t_iot; 185 1.1 jmcneill rv = 0; 186 1.1 jmcneill 187 1.1 jmcneill for (slot = 0; slot < PCKBPORT_NSLOTS; slot++) { 188 1.2 jmcneill if (t->t_present[slot] == 0) 189 1.2 jmcneill continue; 190 1.2 jmcneill 191 1.1 jmcneill ioh = t->t_ioh[slot]; 192 1.1 jmcneill stat = bus_space_read_8(iot, ioh, MACEKBC_STAT); 193 1.1 jmcneill if (stat & MACEKBC_STAT_RXFULL) { 194 1.1 jmcneill val = bus_space_read_8(iot, ioh, MACEKBC_RX); 195 1.1 jmcneill pckbportintr(t->t_pt, slot, val & 0xff); 196 1.1 jmcneill rv = 1; 197 1.1 jmcneill } 198 1.1 jmcneill } 199 1.1 jmcneill 200 1.3 tnn return rv; 201 1.1 jmcneill } 202 1.1 jmcneill 203 1.1 jmcneill static void 204 1.1 jmcneill macekbc_reset(struct macekbc_internal *t, pckbport_slot_t slot) 205 1.1 jmcneill { 206 1.1 jmcneill bus_space_tag_t iot; 207 1.1 jmcneill bus_space_handle_t ioh; 208 1.1 jmcneill uint64_t val; 209 1.1 jmcneill 210 1.1 jmcneill iot = t->t_iot; 211 1.1 jmcneill ioh = t->t_ioh[slot]; 212 1.1 jmcneill 213 1.1 jmcneill val = bus_space_read_8(iot, ioh, MACEKBC_CTRL); 214 1.1 jmcneill val |= MACEKBC_CTRL_TXCLKOFF | MACEKBC_CTRL_RESET; 215 1.1 jmcneill bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 216 1.1 jmcneill 217 1.1 jmcneill delay(10000); 218 1.1 jmcneill 219 1.1 jmcneill val &= ~(MACEKBC_CTRL_TXCLKOFF | MACEKBC_CTRL_RESET); 220 1.1 jmcneill val |= MACEKBC_CTRL_TXON | MACEKBC_CTRL_RXCLKON | MACEKBC_CTRL_RXINTEN; 221 1.1 jmcneill bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 222 1.1 jmcneill 223 1.1 jmcneill return; 224 1.1 jmcneill } 225 1.1 jmcneill 226 1.1 jmcneill static int 227 1.1 jmcneill macekbc_wait(struct macekbc_internal *t, pckbport_slot_t slot, 228 1.1 jmcneill uint64_t mask, bool set) 229 1.1 jmcneill { 230 1.1 jmcneill bus_space_tag_t iot; 231 1.1 jmcneill bus_space_handle_t ioh; 232 1.1 jmcneill uint64_t val, tmp; 233 1.1 jmcneill int timeout; 234 1.1 jmcneill 235 1.1 jmcneill iot = t->t_iot; 236 1.1 jmcneill ioh = t->t_ioh[slot]; 237 1.1 jmcneill val = (set ? mask : 0); 238 1.2 jmcneill timeout = 1000; 239 1.1 jmcneill 240 1.1 jmcneill while (timeout-- > 0) { 241 1.1 jmcneill tmp = bus_space_read_8(iot, ioh, MACEKBC_STAT); 242 1.1 jmcneill if ((tmp & mask) == val) 243 1.1 jmcneill return 0; 244 1.1 jmcneill delay(10); 245 1.1 jmcneill } 246 1.1 jmcneill 247 1.1 jmcneill return 1; 248 1.1 jmcneill } 249 1.1 jmcneill 250 1.1 jmcneill static int 251 1.1 jmcneill macekbc_xt_translation(void *opaque, pckbport_slot_t port, int on) 252 1.1 jmcneill { 253 1.1 jmcneill 254 1.1 jmcneill if (on) 255 1.1 jmcneill return 0; 256 1.1 jmcneill 257 1.1 jmcneill return 1; 258 1.1 jmcneill } 259 1.1 jmcneill 260 1.1 jmcneill static int 261 1.1 jmcneill macekbc_send_devcmd(void *opaque, pckbport_slot_t slot, u_char byte) 262 1.1 jmcneill { 263 1.1 jmcneill struct macekbc_internal *t; 264 1.1 jmcneill bus_space_tag_t iot; 265 1.1 jmcneill bus_space_handle_t ioh; 266 1.1 jmcneill 267 1.1 jmcneill t = opaque; 268 1.1 jmcneill iot = t->t_iot; 269 1.1 jmcneill ioh = t->t_ioh[slot]; 270 1.1 jmcneill 271 1.1 jmcneill if (macekbc_wait(t, slot, MACEKBC_STAT_TXEMPTY, 1)) 272 1.1 jmcneill return 0; 273 1.1 jmcneill 274 1.1 jmcneill bus_space_write_8(iot, ioh, MACEKBC_TX, byte & 0xff); 275 1.1 jmcneill 276 1.1 jmcneill return 1; 277 1.1 jmcneill } 278 1.1 jmcneill 279 1.1 jmcneill static int 280 1.1 jmcneill macekbc_poll_data1(void *opaque, pckbport_slot_t slot) 281 1.1 jmcneill { 282 1.1 jmcneill struct macekbc_internal *t; 283 1.1 jmcneill bus_space_tag_t iot; 284 1.1 jmcneill bus_space_handle_t ioh; 285 1.1 jmcneill 286 1.1 jmcneill t = opaque; 287 1.1 jmcneill iot = t->t_iot; 288 1.1 jmcneill ioh = t->t_ioh[slot]; 289 1.1 jmcneill 290 1.1 jmcneill if (macekbc_wait(t, slot, MACEKBC_STAT_RXFULL, 1)) /* rx full */ 291 1.1 jmcneill return -1; 292 1.1 jmcneill 293 1.1 jmcneill return bus_space_read_8(iot, ioh, MACEKBC_RX) & 0xff; 294 1.1 jmcneill } 295 1.1 jmcneill 296 1.1 jmcneill static void 297 1.1 jmcneill macekbc_slot_enable(void *opaque, pckbport_slot_t slot, int on) 298 1.1 jmcneill { 299 1.1 jmcneill struct macekbc_internal *t; 300 1.1 jmcneill bus_space_tag_t iot; 301 1.1 jmcneill bus_space_handle_t ioh; 302 1.1 jmcneill uint64_t val; 303 1.1 jmcneill 304 1.1 jmcneill t = opaque; 305 1.1 jmcneill iot = t->t_iot; 306 1.1 jmcneill ioh = t->t_ioh[slot]; 307 1.1 jmcneill 308 1.1 jmcneill val = bus_space_read_8(iot, ioh, MACEKBC_CTRL); 309 1.1 jmcneill if (on) 310 1.1 jmcneill val |= MACEKBC_CTRL_TXON | MACEKBC_CTRL_RXCLKON; 311 1.1 jmcneill else 312 1.1 jmcneill val &= ~(MACEKBC_CTRL_TXON | MACEKBC_CTRL_RXCLKON); 313 1.1 jmcneill bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 314 1.1 jmcneill 315 1.1 jmcneill return; 316 1.1 jmcneill } 317 1.1 jmcneill 318 1.1 jmcneill static void 319 1.1 jmcneill macekbc_intr_establish(void *opaque, pckbport_slot_t slot) 320 1.1 jmcneill { 321 1.1 jmcneill 322 1.1 jmcneill /* XXX */ 323 1.1 jmcneill macekbc_set_poll(opaque, slot, 0); 324 1.1 jmcneill 325 1.1 jmcneill return; 326 1.1 jmcneill } 327 1.1 jmcneill 328 1.1 jmcneill static void 329 1.1 jmcneill macekbc_set_poll(void *opaque, pckbport_slot_t slot, int on) 330 1.1 jmcneill { 331 1.1 jmcneill struct macekbc_internal *t; 332 1.1 jmcneill bus_space_tag_t iot; 333 1.1 jmcneill bus_space_handle_t ioh; 334 1.1 jmcneill uint64_t val; 335 1.1 jmcneill 336 1.1 jmcneill t = opaque; 337 1.1 jmcneill iot = t->t_iot; 338 1.1 jmcneill ioh = t->t_ioh[slot]; 339 1.1 jmcneill 340 1.1 jmcneill val = bus_space_read_8(iot, ioh, MACEKBC_CTRL); 341 1.1 jmcneill if (on) 342 1.1 jmcneill val &= ~MACEKBC_CTRL_RXINTEN; 343 1.1 jmcneill else 344 1.1 jmcneill val |= MACEKBC_CTRL_RXINTEN; 345 1.1 jmcneill bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 346 1.1 jmcneill 347 1.1 jmcneill return; 348 1.1 jmcneill } 349