1 /*        $NetBSD: ms.c,v 1.40 2014/07/25 08:10:39 dholland Exp $     */
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * All advertising materials mentioning features or use of this software
12  * must display the following acknowledgement:
13  *        This product includes software developed by the University of
14  *        California, Lawrence Berkeley Laboratory.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *        @(#)ms.c  8.1 (Berkeley) 6/11/93
41  */
42 
43 /*
44  * Mouse driver (/dev/mouse)
45  */
46 
47 /*
48  * Zilog Z8530 Dual UART driver (mouse interface)
49  *
50  * This is the "slave" driver that will be attached to
51  * the "zsc" driver for a Sun mouse.
52  */
53 
54 #include <sys/cdefs.h>
55 __KERNEL_RCSID(0, "$NetBSD: ms.c,v 1.40 2014/07/25 08:10:39 dholland Exp $");
56 
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/conf.h>
60 #include <sys/device.h>
61 #include <sys/ioctl.h>
62 #include <sys/kernel.h>
63 #include <sys/proc.h>
64 #include <sys/signal.h>
65 #include <sys/signalvar.h>
66 #include <sys/time.h>
67 #include <sys/syslog.h>
68 #include <sys/select.h>
69 #include <sys/poll.h>
70 
71 #include <machine/vuid_event.h>
72 
73 #include <dev/ic/z8530reg.h>
74 #include <machine/z8530var.h>
75 #include <dev/sun/event_var.h>
76 #include <dev/sun/msvar.h>
77 
78 #include <dev/wscons/wsconsio.h>
79 #include <dev/wscons/wsmousevar.h>
80 
81 #include "ioconf.h"
82 #include "locators.h"
83 #include "wsmouse.h"
84 
85 dev_type_open(msopen);
86 dev_type_close(msclose);
87 dev_type_read(msread);
88 dev_type_ioctl(msioctl);
89 dev_type_poll(mspoll);
90 dev_type_kqfilter(mskqfilter);
91 
92 const struct cdevsw ms_cdevsw = {
93           .d_open = msopen,
94           .d_close = msclose,
95           .d_read = msread,
96           .d_write = nowrite,
97           .d_ioctl = msioctl,
98           .d_stop = nostop,
99           .d_tty = notty,
100           .d_poll = mspoll,
101           .d_mmap = nommap,
102           .d_kqfilter = mskqfilter,
103           .d_discard = nodiscard,
104           .d_flag = D_OTHER
105 };
106 
107 /****************************************************************
108  *  Entry points for /dev/mouse
109  *  (open,close,read,write,...)
110  ****************************************************************/
111 
112 int
msopen(dev_t dev,int flags,int mode,struct lwp * l)113 msopen(dev_t dev, int flags, int mode, struct lwp *l)
114 {
115           struct ms_softc *ms;
116 
117           ms = device_lookup_private(&ms_cd, minor(dev));
118           if (ms == NULL)
119                     return ENXIO;
120 
121           /* This is an exclusive open device. */
122           if (ms->ms_events.ev_io)
123                     return EBUSY;
124 
125           if (ms->ms_deviopen) {
126                     int err;
127                     err = (*ms->ms_deviopen)(ms->ms_dev, flags);
128                     if (err)
129                               return err;
130           }
131           ms->ms_events.ev_io = l->l_proc;
132           ev_init(&ms->ms_events);      /* may cause sleep */
133 
134           ms->ms_ready = 1;             /* start accepting events */
135           return 0;
136 }
137 
138 int
msclose(dev_t dev,int flags,int mode,struct lwp * l)139 msclose(dev_t dev, int flags, int mode, struct lwp *l)
140 {
141           struct ms_softc *ms;
142 
143           ms = device_lookup_private(&ms_cd, minor(dev));
144           ms->ms_ready = 0;             /* stop accepting events */
145           ev_fini(&ms->ms_events);
146 
147           ms->ms_events.ev_io = NULL;
148           if (ms->ms_deviclose) {
149                     int err;
150                     err = (*ms->ms_deviclose)(ms->ms_dev, flags);
151                     if (err)
152                               return err;
153           }
154           return 0;
155 }
156 
157 int
msread(dev_t dev,struct uio * uio,int flags)158 msread(dev_t dev, struct uio *uio, int flags)
159 {
160           struct ms_softc *ms;
161 
162           ms = device_lookup_private(&ms_cd, minor(dev));
163           return ev_read(&ms->ms_events, uio, flags);
164 }
165 
166 int
msioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)167 msioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
168 {
169           struct ms_softc *ms;
170 
171           ms = device_lookup_private(&ms_cd, minor(dev));
172 
173           switch (cmd) {
174 
175           case FIONBIO:                 /* we will remove this someday (soon???) */
176                     return 0;
177 
178           case FIOASYNC:
179                     ms->ms_events.ev_async = *(int *)data != 0;
180                     return 0;
181 
182           case FIOSETOWN:
183                     if (-*(int *)data != ms->ms_events.ev_io->p_pgid
184                         && *(int *)data != ms->ms_events.ev_io->p_pid)
185                               return EPERM;
186                     return 0;
187 
188           case TIOCSPGRP:
189                     if (*(int *)data != ms->ms_events.ev_io->p_pgid)
190                               return EPERM;
191                     return 0;
192 
193           case VUIDGFORMAT:
194                     /* we only do firm_events */
195                     *(int *)data = VUID_FIRM_EVENT;
196                     return 0;
197 
198           case VUIDSFORMAT:
199                     if (*(int *)data != VUID_FIRM_EVENT)
200                               return EINVAL;
201                     return 0;
202           }
203           return ENOTTY;
204 }
205 
206 int
mspoll(dev_t dev,int events,struct lwp * l)207 mspoll(dev_t dev, int events, struct lwp *l)
208 {
209           struct ms_softc *ms;
210 
211           ms = device_lookup_private(&ms_cd, minor(dev));
212           return ev_poll(&ms->ms_events, events, l);
213 }
214 
215 int
mskqfilter(dev_t dev,struct knote * kn)216 mskqfilter(dev_t dev, struct knote *kn)
217 {
218           struct ms_softc *ms;
219 
220           ms = device_lookup_private(&ms_cd, minor(dev));
221           return ev_kqfilter(&ms->ms_events, kn);
222 }
223 
224 /****************************************************************
225  * Middle layer (translator)
226  ****************************************************************/
227 
228 /*
229  * Called by our ms_softint() routine on input.
230  */
231 void
ms_input(struct ms_softc * ms,int c)232 ms_input(struct ms_softc *ms, int c)
233 {
234           struct firm_event *fe;
235           int mb, ub, d, get, put, any;
236           static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 };
237           static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT };
238 
239           /*
240            * Discard input if not ready.  Drop sync on parity or framing
241            * error; gain sync on button byte.
242            */
243           if (ms->ms_ready == 0)
244                     return;
245           if (c == -1) {
246                     ms->ms_byteno = -1;
247                     return;
248           }
249           if ((c & 0xb0) == 0x80) {     /* if in 0x80..0x8f of 0xc0..0xcf */
250                     if (c & 8) {
251                               ms->ms_byteno = 1;  /* short form (3 bytes) */
252                     } else {
253                               ms->ms_byteno = 0;  /* long form (5 bytes) */
254                     }
255           }
256 
257           /*
258            * Run the decode loop, adding to the current information.
259            * We add, rather than replace, deltas, so that if the event queue
260            * fills, we accumulate data for when it opens up again.
261            */
262           switch (ms->ms_byteno) {
263 
264           case -1:
265                     return;
266 
267           case 0:
268                     /* buttons (long form) */
269                     ms->ms_byteno = 2;
270                     ms->ms_mb = (~c) & 0x7;
271                     return;
272 
273           case 1:
274                     /* buttons (short form) */
275                     ms->ms_byteno = 4;
276                     ms->ms_mb = (~c) & 0x7;
277                     return;
278 
279           case 2:
280                     /* first delta-x */
281                     ms->ms_byteno = 3;
282                     ms->ms_dx += (char)c;
283                     return;
284 
285           case 3:
286                     /* first delta-y */
287                     ms->ms_byteno = 4;
288                     ms->ms_dy += (char)c;
289                     return;
290 
291           case 4:
292                     /* second delta-x */
293                     ms->ms_byteno = 5;
294                     ms->ms_dx += (char)c;
295                     return;
296 
297           case 5:
298                     /* second delta-y */
299                     ms->ms_byteno = -1; /* wait for button-byte again */
300                     ms->ms_dy += (char)c;
301                     break;
302 
303           default:
304                     panic("ms_rint");
305                     /* NOTREACHED */
306           }
307 
308 #if NWSMOUSE > 0
309           if (ms->ms_wsmousedev != NULL && ms->ms_ready == 2) {
310                     mb = ((ms->ms_mb & 4) >> 2) |
311                               (ms->ms_mb & 2) |
312                               ((ms->ms_mb & 1) << 2);
313                     wsmouse_input(ms->ms_wsmousedev,
314                                         mb,
315                                         ms->ms_dx, ms->ms_dy, 0, 0,
316                                         WSMOUSE_INPUT_DELTA);
317                     ms->ms_dx = 0;
318                     ms->ms_dy = 0;
319                     return;
320           }
321 #endif
322           /*
323            * We have at least one event (mouse button, delta-X, or
324            * delta-Y; possibly all three, and possibly three separate
325            * button events).  Deliver these events until we are out
326            * of changes or out of room.  As events get delivered,
327            * mark them `unchanged'.
328            */
329           any = 0;
330           get = ms->ms_events.ev_get;
331           put = ms->ms_events.ev_put;
332           fe = &ms->ms_events.ev_q[put];
333 
334           /* NEXT prepares to put the next event, backing off if necessary */
335 #define   NEXT \
336           if ((++put) % EV_QSIZE == get) { \
337                     put--; \
338                     goto out; \
339           }
340           /* ADVANCE completes the `put' of the event */
341 #define   ADVANCE \
342           fe++; \
343           if (put >= EV_QSIZE) { \
344                     put = 0; \
345                     fe = &ms->ms_events.ev_q[0]; \
346           } \
347           any = 1
348 
349           mb = ms->ms_mb;
350           ub = ms->ms_ub;
351           while ((d = mb ^ ub) != 0) {
352                     /*
353                      * Mouse button change.  Convert up to three changes
354                      * to the `first' change, and drop it into the event queue.
355                      */
356                     NEXT;
357                     d = to_one[d - 1];            /* from 1..7 to {1,2,4} */
358                     fe->id = to_id[d - 1];                  /* from {1,2,4} to ID */
359                     fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
360                     firm_gettime(fe);
361                     ADVANCE;
362                     ub ^= d;
363           }
364           if (ms->ms_dx) {
365                     NEXT;
366                     fe->id = LOC_X_DELTA;
367                     fe->value = ms->ms_dx;
368                     firm_gettime(fe);
369                     ADVANCE;
370                     ms->ms_dx = 0;
371           }
372           if (ms->ms_dy) {
373                     NEXT;
374                     fe->id = LOC_Y_DELTA;
375                     fe->value = ms->ms_dy;
376                     firm_gettime(fe);
377                     ADVANCE;
378                     ms->ms_dy = 0;
379           }
380 out:
381           if (any) {
382                     ms->ms_ub = ub;
383                     ms->ms_events.ev_put = put;
384                     EV_WAKEUP(&ms->ms_events);
385           }
386 }
387