1 /* $NetBSD: pstwo.c,v 1.5 2012/10/27 17:17:51 chs Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Jachym Holecek 5 * All rights reserved. 6 * 7 * Written for DFC Design, s.r.o. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: pstwo.c,v 1.5 2012/10/27 17:17:51 chs Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/conf.h> 38 #include <sys/device.h> 39 #include <sys/file.h> 40 #include <sys/ioctl.h> 41 #include <sys/kernel.h> 42 #include <sys/proc.h> 43 #include <sys/time.h> 44 #include <sys/syslog.h> 45 46 #include <machine/intr.h> 47 #include <sys/bus.h> 48 49 #include <dev/pckbport/pckbportvar.h> 50 51 #include <evbppc/virtex/virtex.h> 52 #include <evbppc/virtex/dev/xcvbusvar.h> 53 #include <evbppc/virtex/dev/pstworeg.h> 54 55 56 #define PSTWO_RXBUF_SIZE 32 57 #define NEXT(idx) (void)((idx) = ((idx) + 1) % PSTWO_RXBUF_SIZE) 58 59 struct pstwo_softc { 60 device_t sc_dev; 61 void *sc_ih; 62 63 bus_space_tag_t sc_iot; 64 bus_space_handle_t sc_ioh; 65 66 pckbport_tag_t sc_pt; 67 pckbport_slot_t sc_slot; 68 }; 69 70 static int pstwo_intr(void *); 71 static void pstwo_reset(bus_space_tag_t, bus_space_handle_t, bool); 72 #if 0 73 static void pstwo_printreg(struct pstwo_softc *); 74 #endif 75 76 /* Interface to pckbport. */ 77 static int pstwo_xt_translation(void *, pckbport_slot_t, int); 78 static int pstwo_send_devcmd(void *, pckbport_slot_t, u_char); 79 static int pstwo_poll_data1(void *, pckbport_slot_t); 80 static void pstwo_slot_enable(void *, pckbport_slot_t, int); 81 static void pstwo_intr_establish(void *, pckbport_slot_t); 82 static void pstwo_set_poll(void *, pckbport_slot_t, int); 83 84 /* Generic device. */ 85 static void pstwo_attach(device_t, device_t, void *); 86 87 CFATTACH_DECL_NEW(pstwo, sizeof(struct pstwo_softc), 88 xcvbus_child_match, pstwo_attach, NULL, NULL); 89 90 static struct pckbport_accessops pstwo_ops = { 91 .t_xt_translation = pstwo_xt_translation, 92 .t_send_devcmd = pstwo_send_devcmd, 93 .t_poll_data1 = pstwo_poll_data1, 94 .t_slot_enable = pstwo_slot_enable, 95 .t_intr_establish = pstwo_intr_establish, 96 .t_set_poll = pstwo_set_poll, 97 }; 98 99 static void 100 pstwo_attach(device_t parent, device_t self, void *aux) 101 { 102 struct xcvbus_attach_args *vaa = aux; 103 struct pstwo_softc *sc = device_private(self); 104 int i; 105 106 aprint_normal(": PS2 port\n"); 107 108 if ((sc->sc_ih = intr_establish(vaa->vaa_intr, IST_LEVEL, IPL_TTY, 109 pstwo_intr, sc)) == NULL) { 110 aprint_error_dev(self, "could not establish interrupt\n"); 111 return; 112 } 113 114 sc->sc_dev = self; 115 sc->sc_iot = vaa->vaa_iot; 116 117 if (bus_space_map(vaa->vaa_iot, vaa->vaa_addr, PSTWO_SIZE, 0, 118 &sc->sc_ioh) != 0) { 119 aprint_error_dev(self, "could not map registers\n"); 120 return ; 121 } 122 123 pstwo_reset(sc->sc_iot, sc->sc_ioh, 1); 124 125 sc->sc_pt = pckbport_attach(sc, &pstwo_ops); 126 127 /* Emulate the concept of "slot" to make pms(4)/pckbd(4) happy. */ 128 for (i = 0; i < PCKBPORT_NSLOTS; i++) 129 if (pckbport_attach_slot(self, sc->sc_pt, i) != NULL) { 130 sc->sc_slot = i; 131 break; /* only one device allowed */ 132 } 133 } 134 135 #if 0 136 static void 137 pstwo_printreg(struct pstwo_softc *sc) 138 { 139 #define PRINTREG(name, reg) \ 140 printf("%s: [0x%08x] %s -> 0x%08x\n", device_xname(sc->sc_dev), \ 141 reg, name, bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg)) 142 143 PRINTREG("status ", PSTWO_STAT); 144 PRINTREG("recv byte", PSTWO_RX_DATA); 145 PRINTREG("intr stat", PSTWO_INTR_STAT); 146 PRINTREG("intr mask", PSTWO_INTR_MSET); 147 148 #undef PRINTREG 149 } 150 #endif 151 152 static int 153 pstwo_intr(void *arg) 154 { 155 struct pstwo_softc *sc = arg; 156 uint32_t stat; 157 158 stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSTWO_INTR_STAT); 159 bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSTWO_INTR_ACK, stat); 160 161 if (stat & INTR_RX_FULL) { 162 uint32_t val; 163 164 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSTWO_RX_DATA); 165 pckbportintr(sc->sc_pt, sc->sc_slot, DATA_RECV(val)); 166 } 167 return (0); 168 } 169 170 static void 171 pstwo_reset(bus_space_tag_t iot, bus_space_handle_t ioh, bool restart) 172 { 173 bus_space_write_4(iot, ioh, PSTWO_CTRL, CTRL_RESET); 174 175 delay(10); 176 177 if (restart) { 178 bus_space_write_4(iot, ioh, PSTWO_CTRL, ~CTRL_RESET); 179 bus_space_write_4(iot, ioh, PSTWO_INTR_MSET, INTR_ANY); 180 } 181 } 182 183 /* 184 * pstwo_wait: 185 * 186 * Wait while status bits indicated by ${mask} have the value ${set}. 187 * Return zero on success, one on timeout. 188 */ 189 static int 190 pstwo_wait(struct pstwo_softc *sc, uint32_t mask, bool set) 191 { 192 uint32_t val = (set ? mask : 0); 193 int i = 1000; 194 195 while (i--) { 196 if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSTWO_STAT) & 197 mask) == val) { 198 delay(10); 199 continue; 200 } 201 202 return (0); 203 } 204 205 return (1); 206 } 207 208 /* 209 * pckbport 210 */ 211 212 static int 213 pstwo_xt_translation(void *arg, pckbport_slot_t port, int enable) 214 { 215 /* Can't do translation, so disable succeeds & enable fails. */ 216 return (!enable); 217 } 218 219 static int 220 pstwo_send_devcmd(void *arg, pckbport_slot_t slot, u_char byte) 221 { 222 struct pstwo_softc *sc = arg; 223 224 if (pstwo_wait(sc, STAT_TX_BUSY, 1)) 225 return (0); 226 227 bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSTWO_TX_DATA, 228 DATA_SEND(byte)); 229 return (1); 230 } 231 232 static int 233 pstwo_poll_data1(void *arg, pckbport_slot_t slot) 234 { 235 struct pstwo_softc *sc = arg; 236 uint32_t val; 237 238 if (pstwo_wait(sc, STAT_RX_DONE, 0)) 239 return (-1); 240 241 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSTWO_RX_DATA); 242 return DATA_RECV(val); 243 } 244 245 static void 246 pstwo_slot_enable(void *arg, pckbport_slot_t slot, int enable) 247 { 248 /* Nothing to do */ 249 } 250 251 static void 252 pstwo_intr_establish(void *arg, pckbport_slot_t slot) 253 { 254 /* XXX no-op because we don't support polled mode */ 255 } 256 257 static void 258 pstwo_set_poll(void *arg, pckbport_slot_t slot, int enable) 259 { 260 /* XXX only needed by console */ 261 } 262