Home | History | Annotate | Line # | Download | only in tc
dt.c revision 1.3
      1 /*	$NetBSD: dt.c,v 1.3 2003/12/23 09:39:46 ad Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Andrew Doran.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*-
     40  * Copyright (c) 1992, 1993
     41  *	The Regents of the University of California.  All rights reserved.
     42  *
     43  * This code is derived from software contributed to Berkeley by
     44  * Ralph Campbell and Rick Macklem.
     45  *
     46  * Redistribution and use in source and binary forms, with or without
     47  * modification, are permitted provided that the following conditions
     48  * are met:
     49  * 1. Redistributions of source code must retain the above copyright
     50  *    notice, this list of conditions and the following disclaimer.
     51  * 2. Redistributions in binary form must reproduce the above copyright
     52  *    notice, this list of conditions and the following disclaimer in the
     53  *    documentation and/or other materials provided with the distribution.
     54  * 3. Neither the name of the University nor the names of its contributors
     55  *    may be used to endorse or promote products derived from this software
     56  *    without specific prior written permission.
     57  *
     58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     68  * SUCH DAMAGE.
     69  *
     70  *	@(#)dtop.c	8.2 (Berkeley) 11/30/93
     71  */
     72 
     73 /*
     74  * Mach Operating System
     75  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
     76  * All Rights Reserved.
     77  *
     78  * Permission to use, copy, modify and distribute this software and its
     79  * documentation is hereby granted, provided that both the copyright
     80  * notice and this permission notice appear in all copies of the
     81  * software, derivative works or modified versions, and any portions
     82  * thereof, and that both notices appear in supporting documentation.
     83  *
     84  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     85  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     86  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     87  *
     88  * Carnegie Mellon requests users of this software to return to
     89  *
     90  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     91  *  School of Computer Science
     92  *  Carnegie Mellon University
     93  *  Pittsburgh PA 15213-3890
     94  *
     95  * any improvements or extensions that they make and grant Carnegie the
     96  * rights to redistribute these changes.
     97  */
     98 /*
     99  * 	Author: Alessandro Forin, Carnegie Mellon University
    100  *
    101  *	Hardware-level operations for the Desktop serial line
    102  *	bus (i2c aka ACCESS).
    103  */
    104 /************************************************************
    105 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
    106 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
    107 
    108                         All Rights Reserved
    109 
    110 Permission to use, copy, modify, and distribute this software and its
    111 documentation for any purpose and without fee is hereby granted,
    112 provided that the above copyright notice appear in all copies and that
    113 both that copyright notice and this permission notice appear in
    114 supporting documentation, and that the names of Digital or MIT not be
    115 used in advertising or publicity pertaining to distribution of the
    116 software without specific, written prior permission.
    117 
    118 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    119 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
    120 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
    121 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
    122 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
    123 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
    124 SOFTWARE.
    125 
    126 ********************************************************/
    127 
    128 /*
    129  * ACCESS.bus device support for the Personal DECstation.  This code handles
    130  * only the keyboard and mouse, and will likely not work if other ACCESS.bus
    131  * devices are physically attached to the system.
    132  *
    133  * Since we do not know how to drive the hardware (the only reference being
    134  * Mach), we can't identify which devices are connected to the system by
    135  * sending idenfication requests.  With only a mouse and keyboard attached
    136  * to the system, we do know which two slave addresses will be in use.
    137  * However, we don't know which is the mouse, and which is the keyboard.
    138  * So, we resort to inspecting device reports and making an educated guess
    139  * as to which is which.
    140  */
    141 
    142 #include <sys/cdefs.h>
    143 __KERNEL_RCSID(0, "$NetBSD: dt.c,v 1.3 2003/12/23 09:39:46 ad Exp $");
    144 
    145 #include <sys/param.h>
    146 #include <sys/systm.h>
    147 #include <sys/tty.h>
    148 #include <sys/proc.h>
    149 #include <sys/conf.h>
    150 #include <sys/file.h>
    151 #include <sys/kernel.h>
    152 #include <sys/device.h>
    153 #include <sys/malloc.h>
    154 
    155 #include <dev/dec/lk201.h>
    156 
    157 #include <dev/tc/tcvar.h>
    158 #include <dev/tc/ioasicreg.h>
    159 #include <dev/tc/ioasicvar.h>
    160 
    161 #include <pmax/pmax/maxine.h>
    162 
    163 #include <pmax/tc/dtreg.h>
    164 #include <pmax/tc/dtvar.h>
    165 
    166 #define	DT_BUF_CNT		16
    167 #define	DT_ESC_CHAR		0xf8
    168 #define	DT_XMT_OK		0xfb
    169 #define	DT_MAX_POLL		0x70000		/* about half a sec */
    170 
    171 #define	DT_GET_BYTE(data)	(((*(data)) >> 8) & 0xff)
    172 #define	DT_PUT_BYTE(data,c)	{ *(data) = (c) << 8; wbflush(); }
    173 
    174 #define	DT_RX_AVAIL(poll)	((*(poll) & 1) != 0)
    175 #define	DT_TX_AVAIL(poll)	((*(poll) & 2) != 0)
    176 
    177 int	dt_match(struct device *, struct cfdata *, void *);
    178 void	dt_attach(struct device *, struct device *, void *);
    179 int	dt_intr(void *);
    180 int	dt_null_handler(struct device *, struct dt_msg *, int);
    181 int	dt_print(void *, const char *);
    182 void	dt_strvis(uint8_t *, char *, int);
    183 void	dt_dispatch(void *);
    184 
    185 int	dt_kbd_addr = DT_ADDR_KBD;
    186 struct	dt_device dt_kbd_dv;
    187 int	dt_ms_addr = DT_ADDR_MOUSE;
    188 struct	dt_device dt_ms_dv;
    189 struct	dt_state dt_state;
    190 
    191 CFATTACH_DECL(dt, sizeof(struct dt_softc),
    192     dt_match, dt_attach, NULL, NULL);
    193 
    194 int
    195 dt_match(struct device *parent, struct cfdata *match, void *aux)
    196 {
    197 	struct ioasicdev_attach_args *d;
    198 
    199 	d = aux;
    200 
    201 	if (strcmp(d->iada_modname, "dtop") != 0)
    202 		return (0);
    203 
    204 	if (badaddr((caddr_t)(d->iada_addr), 2))
    205 		return (0);
    206 
    207 	return (1);
    208 }
    209 
    210 void
    211 dt_attach(struct device *parent, struct device *self, void *aux)
    212 {
    213 	struct ioasicdev_attach_args *d;
    214 	struct dt_attach_args dta;
    215 	struct dt_softc *sc;
    216 	struct dt_msg *msg;
    217 	int i;
    218 
    219 	d = aux;
    220 	sc = (struct dt_softc*)self;
    221 
    222 	dt_cninit();
    223 
    224 	msg = malloc(sizeof(*msg) * DT_BUF_CNT, M_DEVBUF, M_NOWAIT);
    225 	if (msg == NULL) {
    226 		printf("%s: memory exhausted\n", sc->sc_dv.dv_xname);
    227 		return;
    228 	}
    229 
    230 	sc->sc_sih = softintr_establish(IPL_SOFTSERIAL, dt_dispatch, sc);
    231 	if (sc->sc_sih == NULL) {
    232 		printf("%s: memory exhausted\n", sc->sc_dv.dv_xname);
    233 		free(msg, M_DEVBUF);
    234 	}
    235 
    236 	SIMPLEQ_INIT(&sc->sc_queue);
    237 	SLIST_INIT(&sc->sc_free);
    238 	for (i = 0; i < DT_BUF_CNT; i++, msg++)
    239 		SLIST_INSERT_HEAD(&sc->sc_free, msg, chain.slist);
    240 
    241 	ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_TTY, dt_intr, sc);
    242 	printf("\n");
    243 
    244 	dta.dta_addr = DT_ADDR_KBD;
    245 	config_found(self, &dta, dt_print);
    246 	dta.dta_addr = DT_ADDR_MOUSE;
    247 	config_found(self, &dta, dt_print);
    248 }
    249 
    250 void
    251 dt_cninit(void)
    252 {
    253 
    254 	dt_state.ds_poll = (volatile u_int *)
    255 	    MIPS_PHYS_TO_KSEG1(XINE_REG_INTR);
    256 	dt_state.ds_data = (volatile u_int *)
    257 	    MIPS_PHYS_TO_KSEG1(XINE_PHYS_TC_3_START + 0x280000);
    258 }
    259 
    260 int
    261 dt_print(void *aux, const char *pnp)
    262 {
    263 
    264 	return (QUIET);
    265 }
    266 
    267 int
    268 dt_establish_handler(struct dt_softc *sc, struct dt_device *dtdv,
    269     struct device *dv, void (*hdlr)(void *, struct dt_msg *))
    270 {
    271 
    272 	dtdv->dtdv_dv = dv;
    273 	dtdv->dtdv_handler = hdlr;
    274 	return (0);
    275 }
    276 
    277 int
    278 dt_intr(void *cookie)
    279 {
    280 	struct dt_softc *sc;
    281 	struct dt_msg *msg, *pend;
    282 
    283 	sc = cookie;
    284 
    285 	switch (dt_msg_get(&sc->sc_msg, 1)) {
    286 	case DT_GET_ERROR:
    287 		/*
    288 		 * Ugh! The most common occurrence of a data overrun is upon
    289 		 * a key press and the result is a software generated "stuck
    290 		 * key".  All I can think to do is fake an "all keys up"
    291 		 * whenever a data overrun occurs.
    292 		 */
    293 		sc->sc_msg.src = dt_kbd_addr;
    294 		sc->sc_msg.ctl = DT_CTL(1, 0, 0);
    295 		sc->sc_msg.body[0] = DT_KBD_EMPTY;
    296 #ifdef DIAGNOSTIC
    297 		printf("%s: data overrun or stray interrupt\n",
    298 		    sc->sc_dv.dv_xname);
    299 #endif
    300 		break;
    301 
    302 	case DT_GET_DONE:
    303 		break;
    304 
    305 	case DT_GET_NOTYET:
    306 		return (1);
    307 	}
    308 
    309 	if ((msg = SLIST_FIRST(&sc->sc_free)) == NULL) {
    310 		printf("%s: input overflow\n", sc->sc_dv.dv_xname);
    311 		return (1);
    312 	}
    313 	SLIST_REMOVE_HEAD(&sc->sc_free, chain.slist);
    314 	memcpy(msg, &sc->sc_msg, sizeof(*msg));
    315 
    316 	pend = SIMPLEQ_FIRST(&sc->sc_queue);
    317 	SIMPLEQ_INSERT_TAIL(&sc->sc_queue, msg, chain.simpleq);
    318 	if (pend == NULL)
    319 		softintr_schedule(sc->sc_sih);
    320 
    321 	return (1);
    322 }
    323 
    324 void
    325 dt_dispatch(void *cookie)
    326 {
    327 	struct dt_softc *sc;
    328 	struct dt_msg *msg;
    329 	int s, other, mouse;
    330 	struct dt_device *dtdv;
    331 
    332 	sc = cookie;
    333 	msg = NULL;
    334 	other = DT_ADDR_KBD;
    335 	mouse = 0;
    336 
    337 	for (;;) {
    338 		s = spltty();
    339 		if (msg != NULL) {
    340 			SLIST_INSERT_HEAD(&sc->sc_free, msg, chain.slist);
    341 			if (mouse) {
    342 				dt_ms_addr = msg->src;
    343 				dt_kbd_addr = other;
    344 			} else {
    345 				dt_kbd_addr = msg->src;
    346 				dt_ms_addr = other;
    347 			}
    348 		}
    349 		msg = SIMPLEQ_FIRST(&sc->sc_queue);
    350 		if (msg != NULL)
    351 			SIMPLEQ_REMOVE_HEAD(&sc->sc_queue, chain.simpleq);
    352 		splx(s);
    353 		if (msg == NULL)
    354 			break;
    355 
    356 		if (msg->src == DT_ADDR_MOUSE)
    357 			other = DT_ADDR_KBD;
    358 		else if (msg->src == DT_ADDR_KBD)
    359 			other = DT_ADDR_MOUSE;
    360 		else {
    361 			printf("%s: message from unknown dev 0x%x\n",
    362 			    sc->sc_dv.dv_xname, sc->sc_msg.src);
    363 			dt_msg_dump(msg);
    364 			continue;
    365 		}
    366 		if (DT_CTL_P(msg->ctl) != 0) {
    367 			printf("%s: received control message\n",
    368 			    sc->sc_dv.dv_xname);
    369 			dt_msg_dump(msg);
    370 			continue;
    371 		}
    372 
    373 		/*
    374 		 * 1. Mouse should have no more than eight buttons.
    375 		 * 2. Mouse should always send full locator report.
    376 		 * 3. Keyboard should never report all-up (0x00) in
    377 		 *    a packet with size > 1.
    378 		 */
    379 		if (DT_CTL_LEN(msg->ctl) == sizeof(struct dt_locator_msg) &&
    380 		    msg->body[0] == 0) {
    381 			mouse = 1;
    382 			dtdv = &dt_ms_dv;
    383 		} else {
    384 			mouse = 0;
    385 			dtdv = &dt_kbd_dv;
    386 		}
    387 
    388 		if (dtdv->dtdv_handler != NULL)
    389 			(*dtdv->dtdv_handler)(dtdv->dtdv_dv, msg);
    390 	}
    391 }
    392 
    393 int
    394 dt_msg_get(struct dt_msg *msg, int intr)
    395 {
    396 	volatile u_int *poll, *data;
    397 	uint8_t c;
    398 	int max;
    399 
    400 	poll = dt_state.ds_poll;
    401 	data = dt_state.ds_data;
    402 
    403 	/*
    404 	 * The interface does not hand us the first byte, which is our
    405 	 * address and cannot ever be anything else but 0x50.
    406 	 */
    407 	if (dt_state.ds_state == 0) {
    408 		dt_state.ds_escaped = 0;
    409 		dt_state.ds_ptr = 0;
    410 	}
    411 
    412 	for (;;) {
    413 		max = DT_MAX_POLL;
    414 
    415 		while (!DT_RX_AVAIL(poll)) {
    416 			if (intr)
    417 				return (DT_GET_NOTYET);
    418 			if (max-- <= 0)
    419 				break;
    420 			DELAY(1);
    421 		}
    422 
    423 		if (max <= 0) {
    424 			if (dt_state.ds_state != 0) {
    425 				dt_state.ds_bad_pkts++;
    426 				dt_state.ds_state = 0;
    427 			}
    428 			return (DT_GET_ERROR);
    429 		}
    430 
    431 		c = DT_GET_BYTE(data);
    432 
    433 		if (dt_state.ds_escaped) {
    434 			switch (c) {
    435 			case 0xe8:
    436 			case 0xe9:
    437 			case 0xea:
    438 			case 0xeb:
    439 				c += 0x10;
    440 				break;
    441 			}
    442 			if (c == 'O') {
    443 				dt_state.ds_bad_pkts++;
    444 				dt_state.ds_state = 0;
    445 				return (DT_GET_ERROR);
    446 			}
    447 			dt_state.ds_escaped = 0;
    448 		} else if (c == DT_ESC_CHAR) {
    449 			dt_state.ds_escaped = 1;
    450 			continue;
    451 		}
    452 
    453 		if (dt_state.ds_state == 0) {
    454 			msg->src = c;
    455 			dt_state.ds_state = 1;
    456 		} else if (dt_state.ds_state == 1) {
    457 			msg->ctl = c;
    458 			dt_state.ds_state = 2;
    459 			dt_state.ds_len = DT_CTL_LEN(msg->ctl) + 1;
    460 			if (dt_state.ds_len > sizeof(msg->body))
    461 				printf("dt_msg_get: msg truncated: %d\n",
    462 				    dt_state.ds_len);
    463 		} else /* if (dt_state.ds_state == 2) */ {
    464 			if (dt_state.ds_ptr < sizeof(msg->body))
    465 				msg->body[dt_state.ds_ptr++] = c;
    466 			if (dt_state.ds_ptr >= dt_state.ds_len)
    467 				break;
    468 		}
    469 	}
    470 
    471 	msg->dst = DT_ADDR_HOST;
    472 	dt_state.ds_state = 0;
    473 	return (DT_GET_DONE);
    474 }
    475 
    476 void
    477 dt_msg_dump(struct dt_msg *msg)
    478 {
    479 	int i, l;
    480 
    481 	l = DT_CTL_LEN(msg->ctl);
    482 
    483 	printf("hdr: dst=%02x src=%02x p=%02x sub=%02x len=%02x\n",
    484 	   msg->dst, msg->src, DT_CTL_P(msg->ctl), DT_CTL_SUBADDR(msg->ctl),
    485 	   l);
    486 
    487 	printf("body: ");
    488 	for (i = 0; i < l && i < 20; i++)
    489 		printf("%02x ", msg->body[i]);
    490 	if (i < l) {
    491 		printf("\n");
    492 		for (; i < l; i++)
    493 			printf("%02x ", msg->body[i]);
    494 	}
    495 	printf("\n");
    496 }
    497