1 /* $NetBSD: macekbc.c,v 1.8 2015/04/04 14:19:00 macallan Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@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.8 2015/04/04 14:19:00 macallan 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_NOSLEEP); 129 if (t == NULL) { 130 aprint_error("%s: not enough memory\n", device_xname(self)); 131 return; 132 } 133 t->t_iot = maa->maa_st; 134 for (slot = 0; slot < PCKBPORT_NSLOTS; slot++) 135 t->t_present[slot] = 0; 136 if (bus_space_subregion(t->t_iot, maa->maa_sh, maa->maa_offset, 137 0, &t->t_ioh[PCKBPORT_KBD_SLOT]) != 0) { 138 aprint_error("%s: couldn't map kbd registers\n", 139 device_xname(self)); 140 goto bork; 141 } 142 if (bus_space_subregion(t->t_iot, maa->maa_sh, maa->maa_offset + 32, 143 0, &t->t_ioh[PCKBPORT_AUX_SLOT]) != 0) { 144 aprint_error("%s: couldn't map aux registers\n", 145 device_xname(self)); 146 goto bork; 147 } 148 149 if ((t->t_rxih = cpu_intr_establish(maa->maa_intr, maa->maa_intrmask, 150 macekbc_intr, t)) == NULL) { 151 printf("%s: couldn't establish interrupt\n", 152 device_xname(self)); 153 goto bork; 154 } 155 sc->sc_id = t; 156 t->t_sc = sc; 157 158 macekbc_reset(t, PCKBPORT_KBD_SLOT); 159 macekbc_reset(t, PCKBPORT_AUX_SLOT); 160 161 consdev = arcbios_GetEnvironmentVariable("ConsoleIn"); 162 if (consdev != NULL && strcmp(consdev, "keyboard()") == 0) 163 pckbport_cnattach(t, &macekbc_ops, PCKBPORT_KBD_SLOT); 164 165 t->t_pt = pckbport_attach(t, &macekbc_ops); 166 if (pckbport_attach_slot(self, t->t_pt, PCKBPORT_KBD_SLOT)) 167 t->t_present[PCKBPORT_KBD_SLOT] = 1; 168 if (pckbport_attach_slot(self, t->t_pt, PCKBPORT_AUX_SLOT)) 169 t->t_present[PCKBPORT_AUX_SLOT] = 1; 170 171 return; 172 bork: 173 kmem_free(t, sizeof(struct macekbc_internal)); 174 return; 175 } 176 177 static int 178 macekbc_intr(void *opaque) 179 { 180 struct macekbc_internal *t; 181 bus_space_tag_t iot; 182 bus_space_handle_t ioh; 183 uint64_t stat, val; 184 pckbport_slot_t slot; 185 int rv; 186 187 t = opaque; 188 iot = t->t_iot; 189 rv = 0; 190 191 for (slot = 0; slot < PCKBPORT_NSLOTS; slot++) { 192 if (t->t_present[slot] == 0) 193 continue; 194 195 ioh = t->t_ioh[slot]; 196 stat = bus_space_read_8(iot, ioh, MACEKBC_STAT); 197 if (stat & MACEKBC_STAT_RXFULL) { 198 val = bus_space_read_8(iot, ioh, MACEKBC_RX); 199 pckbportintr(t->t_pt, slot, val & 0xff); 200 rv = 1; 201 } 202 } 203 204 return rv; 205 } 206 207 static void 208 macekbc_reset(struct macekbc_internal *t, pckbport_slot_t slot) 209 { 210 bus_space_tag_t iot; 211 bus_space_handle_t ioh; 212 uint64_t val; 213 214 iot = t->t_iot; 215 ioh = t->t_ioh[slot]; 216 217 val = bus_space_read_8(iot, ioh, MACEKBC_CTRL); 218 val |= MACEKBC_CTRL_TXCLKOFF | MACEKBC_CTRL_RESET; 219 bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 220 221 delay(10000); 222 223 val &= ~(MACEKBC_CTRL_TXCLKOFF | MACEKBC_CTRL_RESET); 224 val |= MACEKBC_CTRL_TXON | MACEKBC_CTRL_RXCLKON | MACEKBC_CTRL_RXINTEN; 225 bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 226 227 return; 228 } 229 230 static int 231 macekbc_wait(struct macekbc_internal *t, pckbport_slot_t slot, 232 uint64_t mask, bool set) 233 { 234 bus_space_tag_t iot; 235 bus_space_handle_t ioh; 236 uint64_t val, tmp; 237 int timeout; 238 239 iot = t->t_iot; 240 ioh = t->t_ioh[slot]; 241 val = (set ? mask : 0); 242 timeout = 1000; 243 244 while (timeout-- > 0) { 245 tmp = bus_space_read_8(iot, ioh, MACEKBC_STAT); 246 if ((tmp & mask) == val) 247 return 0; 248 delay(10); 249 } 250 251 return 1; 252 } 253 254 static int 255 macekbc_xt_translation(void *opaque, pckbport_slot_t port, int on) 256 { 257 258 if (on) 259 return 0; 260 261 return 1; 262 } 263 264 static int 265 macekbc_send_devcmd(void *opaque, pckbport_slot_t slot, u_char byte) 266 { 267 struct macekbc_internal *t; 268 bus_space_tag_t iot; 269 bus_space_handle_t ioh; 270 271 t = opaque; 272 iot = t->t_iot; 273 ioh = t->t_ioh[slot]; 274 275 if (macekbc_wait(t, slot, MACEKBC_STAT_TXEMPTY, 1)) 276 return 0; 277 278 bus_space_write_8(iot, ioh, MACEKBC_TX, byte & 0xff); 279 280 return 1; 281 } 282 283 static int 284 macekbc_poll_data1(void *opaque, pckbport_slot_t slot) 285 { 286 struct macekbc_internal *t; 287 bus_space_tag_t iot; 288 bus_space_handle_t ioh; 289 290 t = opaque; 291 iot = t->t_iot; 292 ioh = t->t_ioh[slot]; 293 294 if (macekbc_wait(t, slot, MACEKBC_STAT_RXFULL, 1)) /* rx full */ 295 return -1; 296 297 return bus_space_read_8(iot, ioh, MACEKBC_RX) & 0xff; 298 } 299 300 static void 301 macekbc_slot_enable(void *opaque, pckbport_slot_t slot, int on) 302 { 303 struct macekbc_internal *t; 304 bus_space_tag_t iot; 305 bus_space_handle_t ioh; 306 uint64_t val; 307 308 t = opaque; 309 iot = t->t_iot; 310 ioh = t->t_ioh[slot]; 311 312 val = bus_space_read_8(iot, ioh, MACEKBC_CTRL); 313 if (on) 314 val |= MACEKBC_CTRL_TXON | MACEKBC_CTRL_RXCLKON; 315 else 316 val &= ~(MACEKBC_CTRL_TXON | MACEKBC_CTRL_RXCLKON); 317 bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 318 319 return; 320 } 321 322 static void 323 macekbc_intr_establish(void *opaque, pckbport_slot_t slot) 324 { 325 326 /* XXX */ 327 macekbc_set_poll(opaque, slot, 0); 328 329 return; 330 } 331 332 static void 333 macekbc_set_poll(void *opaque, pckbport_slot_t slot, int on) 334 { 335 struct macekbc_internal *t; 336 bus_space_tag_t iot; 337 bus_space_handle_t ioh; 338 uint64_t val; 339 340 t = opaque; 341 iot = t->t_iot; 342 ioh = t->t_ioh[slot]; 343 344 val = bus_space_read_8(iot, ioh, MACEKBC_CTRL); 345 if (on) 346 val &= ~MACEKBC_CTRL_RXINTEN; 347 else 348 val |= MACEKBC_CTRL_RXINTEN; 349 bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 350 351 return; 352 } 353