xref: /netbsd-src/sys/arch/pmax/tc/dt.c (revision fad4c9f71477ae11cea2ee75ec82151ac770a534)
1 /*	$NetBSD: dt.c,v 1.6 2005/12/11 12:18:41 christos 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@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.6 2005/12/11 12:18:41 christos 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;
330 	struct dt_device *dtdv;
331 
332 	sc = cookie;
333 	msg = NULL;
334 
335 	for (;;) {
336 		s = spltty();
337 		if (msg != NULL)
338 			SLIST_INSERT_HEAD(&sc->sc_free, msg, chain.slist);
339 		msg = SIMPLEQ_FIRST(&sc->sc_queue);
340 		if (msg != NULL)
341 			SIMPLEQ_REMOVE_HEAD(&sc->sc_queue, chain.simpleq);
342 		splx(s);
343 		if (msg == NULL)
344 			break;
345 
346 		if (msg->src != DT_ADDR_MOUSE && msg->src != DT_ADDR_KBD) {
347 			printf("%s: message from unknown dev 0x%x\n",
348 			    sc->sc_dv.dv_xname, sc->sc_msg.src);
349 			dt_msg_dump(msg);
350 			continue;
351 		}
352 		if (DT_CTL_P(msg->ctl) != 0) {
353 			printf("%s: received control message\n",
354 			    sc->sc_dv.dv_xname);
355 			dt_msg_dump(msg);
356 			continue;
357 		}
358 
359 		/*
360 		 * 1. Mouse should have no more than eight buttons, so first
361 		 *    8 bits of body will be zero.
362 		 * 2. Mouse should always send full locator report.
363 		 *    Note:  my mouse does not send 'z' data, so the size
364 		 *    did not match the size of struct dt_locator_msg - mhitch
365 		 * 3. Keyboard should never report all-up (0x00) in
366 		 *    a packet with size > 1.
367 		 */
368 		if (DT_CTL_LEN(msg->ctl) >= 6 &&
369 		    msg->body[0] == 0 && msg->src != dt_ms_addr) {
370 			dt_kbd_addr = dt_ms_addr;
371 			dt_ms_addr = msg->src;
372 		} else if (DT_CTL_LEN(msg->ctl) < 6 && msg->body[0] != 0 &&
373 		    msg->src != dt_kbd_addr) {
374 			dt_ms_addr = dt_kbd_addr;
375 			dt_kbd_addr = msg->src;
376 		}
377 
378 		if (msg->src == dt_kbd_addr)
379 			dtdv = &dt_kbd_dv;
380 		else
381 			dtdv = &dt_ms_dv;
382 
383 		if (dtdv->dtdv_handler != NULL)
384 			(*dtdv->dtdv_handler)(dtdv->dtdv_dv, msg);
385 	}
386 }
387 
388 int
389 dt_msg_get(struct dt_msg *msg, int intr)
390 {
391 	volatile u_int *poll, *data;
392 	uint8_t c;
393 	int max_polls;
394 
395 	poll = dt_state.ds_poll;
396 	data = dt_state.ds_data;
397 
398 	/*
399 	 * The interface does not hand us the first byte, which is our
400 	 * address and cannot ever be anything else but 0x50.
401 	 */
402 	if (dt_state.ds_state == 0) {
403 		dt_state.ds_escaped = 0;
404 		dt_state.ds_ptr = 0;
405 	}
406 
407 	for (;;) {
408 		max_polls = DT_MAX_POLL;
409 
410 		while (!DT_RX_AVAIL(poll)) {
411 			if (intr)
412 				return (DT_GET_NOTYET);
413 			if (max_polls-- <= 0)
414 				break;
415 			DELAY(1);
416 		}
417 
418 		if (max_polls <= 0) {
419 			if (dt_state.ds_state != 0) {
420 				dt_state.ds_bad_pkts++;
421 				dt_state.ds_state = 0;
422 			}
423 			return (DT_GET_ERROR);
424 		}
425 
426 		c = DT_GET_BYTE(data);
427 
428 		if (dt_state.ds_escaped) {
429 			switch (c) {
430 			case 0xe8:
431 			case 0xe9:
432 			case 0xea:
433 			case 0xeb:
434 				c += 0x10;
435 				break;
436 			}
437 			if (c == 'O') {
438 				dt_state.ds_bad_pkts++;
439 				dt_state.ds_state = 0;
440 				return (DT_GET_ERROR);
441 			}
442 			dt_state.ds_escaped = 0;
443 		} else if (c == DT_ESC_CHAR) {
444 			dt_state.ds_escaped = 1;
445 			continue;
446 		}
447 
448 		if (dt_state.ds_state == 0) {
449 			msg->src = c;
450 			dt_state.ds_state = 1;
451 		} else if (dt_state.ds_state == 1) {
452 			msg->ctl = c;
453 			dt_state.ds_state = 2;
454 			dt_state.ds_len = DT_CTL_LEN(msg->ctl) + 1;
455 			if (dt_state.ds_len > sizeof(msg->body))
456 				printf("dt_msg_get: msg truncated: %d\n",
457 				    dt_state.ds_len);
458 		} else /* if (dt_state.ds_state == 2) */ {
459 			if (dt_state.ds_ptr < sizeof(msg->body))
460 				msg->body[dt_state.ds_ptr++] = c;
461 			if (dt_state.ds_ptr >= dt_state.ds_len)
462 				break;
463 		}
464 	}
465 
466 	msg->dst = DT_ADDR_HOST;
467 	dt_state.ds_state = 0;
468 	return (DT_GET_DONE);
469 }
470 
471 void
472 dt_msg_dump(struct dt_msg *msg)
473 {
474 	int i, l;
475 
476 	l = DT_CTL_LEN(msg->ctl);
477 
478 	printf("hdr: dst=%02x src=%02x p=%02x sub=%02x len=%02x\n",
479 	   msg->dst, msg->src, DT_CTL_P(msg->ctl), DT_CTL_SUBADDR(msg->ctl),
480 	   l);
481 
482 	printf("body: ");
483 	for (i = 0; i < l && i < 20; i++)
484 		printf("%02x ", msg->body[i]);
485 	if (i < l) {
486 		printf("\n");
487 		for (; i < l; i++)
488 			printf("%02x ", msg->body[i]);
489 	}
490 	printf("\n");
491 }
492