1 /* $NetBSD: macekbc.c,v 1.7 2012/10/27 17:18:10 chs 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.7 2012/10/27 17:18:10 chs Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/device.h> 38 #include <sys/syslog.h> 39 #include <sys/malloc.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 = malloc(sizeof(struct macekbc_internal), M_DEVBUF, M_NOWAIT|M_ZERO); 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 return; 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 return; 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 return; 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 } 173 174 static int 175 macekbc_intr(void *opaque) 176 { 177 struct macekbc_internal *t; 178 bus_space_tag_t iot; 179 bus_space_handle_t ioh; 180 uint64_t stat, val; 181 pckbport_slot_t slot; 182 int rv; 183 184 t = opaque; 185 iot = t->t_iot; 186 rv = 0; 187 188 for (slot = 0; slot < PCKBPORT_NSLOTS; slot++) { 189 if (t->t_present[slot] == 0) 190 continue; 191 192 ioh = t->t_ioh[slot]; 193 stat = bus_space_read_8(iot, ioh, MACEKBC_STAT); 194 if (stat & MACEKBC_STAT_RXFULL) { 195 val = bus_space_read_8(iot, ioh, MACEKBC_RX); 196 pckbportintr(t->t_pt, slot, val & 0xff); 197 rv = 1; 198 } 199 } 200 201 return rv; 202 } 203 204 static void 205 macekbc_reset(struct macekbc_internal *t, pckbport_slot_t slot) 206 { 207 bus_space_tag_t iot; 208 bus_space_handle_t ioh; 209 uint64_t val; 210 211 iot = t->t_iot; 212 ioh = t->t_ioh[slot]; 213 214 val = bus_space_read_8(iot, ioh, MACEKBC_CTRL); 215 val |= MACEKBC_CTRL_TXCLKOFF | MACEKBC_CTRL_RESET; 216 bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 217 218 delay(10000); 219 220 val &= ~(MACEKBC_CTRL_TXCLKOFF | MACEKBC_CTRL_RESET); 221 val |= MACEKBC_CTRL_TXON | MACEKBC_CTRL_RXCLKON | MACEKBC_CTRL_RXINTEN; 222 bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 223 224 return; 225 } 226 227 static int 228 macekbc_wait(struct macekbc_internal *t, pckbport_slot_t slot, 229 uint64_t mask, bool set) 230 { 231 bus_space_tag_t iot; 232 bus_space_handle_t ioh; 233 uint64_t val, tmp; 234 int timeout; 235 236 iot = t->t_iot; 237 ioh = t->t_ioh[slot]; 238 val = (set ? mask : 0); 239 timeout = 1000; 240 241 while (timeout-- > 0) { 242 tmp = bus_space_read_8(iot, ioh, MACEKBC_STAT); 243 if ((tmp & mask) == val) 244 return 0; 245 delay(10); 246 } 247 248 return 1; 249 } 250 251 static int 252 macekbc_xt_translation(void *opaque, pckbport_slot_t port, int on) 253 { 254 255 if (on) 256 return 0; 257 258 return 1; 259 } 260 261 static int 262 macekbc_send_devcmd(void *opaque, pckbport_slot_t slot, u_char byte) 263 { 264 struct macekbc_internal *t; 265 bus_space_tag_t iot; 266 bus_space_handle_t ioh; 267 268 t = opaque; 269 iot = t->t_iot; 270 ioh = t->t_ioh[slot]; 271 272 if (macekbc_wait(t, slot, MACEKBC_STAT_TXEMPTY, 1)) 273 return 0; 274 275 bus_space_write_8(iot, ioh, MACEKBC_TX, byte & 0xff); 276 277 return 1; 278 } 279 280 static int 281 macekbc_poll_data1(void *opaque, pckbport_slot_t slot) 282 { 283 struct macekbc_internal *t; 284 bus_space_tag_t iot; 285 bus_space_handle_t ioh; 286 287 t = opaque; 288 iot = t->t_iot; 289 ioh = t->t_ioh[slot]; 290 291 if (macekbc_wait(t, slot, MACEKBC_STAT_RXFULL, 1)) /* rx full */ 292 return -1; 293 294 return bus_space_read_8(iot, ioh, MACEKBC_RX) & 0xff; 295 } 296 297 static void 298 macekbc_slot_enable(void *opaque, pckbport_slot_t slot, int on) 299 { 300 struct macekbc_internal *t; 301 bus_space_tag_t iot; 302 bus_space_handle_t ioh; 303 uint64_t val; 304 305 t = opaque; 306 iot = t->t_iot; 307 ioh = t->t_ioh[slot]; 308 309 val = bus_space_read_8(iot, ioh, MACEKBC_CTRL); 310 if (on) 311 val |= MACEKBC_CTRL_TXON | MACEKBC_CTRL_RXCLKON; 312 else 313 val &= ~(MACEKBC_CTRL_TXON | MACEKBC_CTRL_RXCLKON); 314 bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 315 316 return; 317 } 318 319 static void 320 macekbc_intr_establish(void *opaque, pckbport_slot_t slot) 321 { 322 323 /* XXX */ 324 macekbc_set_poll(opaque, slot, 0); 325 326 return; 327 } 328 329 static void 330 macekbc_set_poll(void *opaque, pckbport_slot_t slot, int on) 331 { 332 struct macekbc_internal *t; 333 bus_space_tag_t iot; 334 bus_space_handle_t ioh; 335 uint64_t val; 336 337 t = opaque; 338 iot = t->t_iot; 339 ioh = t->t_ioh[slot]; 340 341 val = bus_space_read_8(iot, ioh, MACEKBC_CTRL); 342 if (on) 343 val &= ~MACEKBC_CTRL_RXINTEN; 344 else 345 val |= MACEKBC_CTRL_RXINTEN; 346 bus_space_write_8(iot, ioh, MACEKBC_CTRL, val); 347 348 return; 349 } 350