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