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