]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mse/mse.c
Import lua 5.3.4 to contrib
[FreeBSD/FreeBSD.git] / sys / dev / mse / mse.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004 M. Warner Losh
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 /*
32  * Copyright 1992 by the University of Guelph
33  *
34  * Permission to use, copy and modify this
35  * software and its documentation for any purpose and without
36  * fee is hereby granted, provided that the above copyright
37  * notice appear in all copies and that both that copyright
38  * notice and this permission notice appear in supporting
39  * documentation.
40  * University of Guelph makes no representations about the suitability of
41  * this software for any purpose.  It is provided "as is"
42  * without express or implied warranty.
43  */
44 /*
45  * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and
46  * the X386 port, courtesy of
47  * Rick Macklem, rick@snowhite.cis.uoguelph.ca
48  * Caveats: The driver currently uses spltty(), but doesn't use any
49  * generic tty code. It could use splmse() (that only masks off the
50  * bus mouse interrupt, but that would require hacking in i386/isa/icu.s.
51  * (This may be worth the effort, since the Logitech generates 30/60
52  * interrupts/sec continuously while it is open.)
53  * NB: The ATI has NOT been tested yet!
54  */
55
56 /*
57  * Modification history:
58  * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com)
59  *   improved probe based on input from Logitech.
60  *
61  * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
62  *   fixes to make it work with Microsoft InPort busmouse
63  *
64  * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
65  *   added patches for new "select" interface
66  *
67  * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
68  *   changed position of some spl()'s in mseread
69  *
70  * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu)
71  *   limit maximum negative x/y value to -127 to work around XFree problem
72  *   that causes spurious button pushes.
73  */
74
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/conf.h>
78 #include <sys/kernel.h>
79 #include <sys/module.h>
80 #include <sys/bus.h>
81 #include <sys/poll.h>
82 #include <sys/selinfo.h>
83 #include <sys/uio.h>
84 #include <sys/mouse.h>
85
86 #include <machine/bus.h>
87 #include <machine/resource.h>
88 #include <sys/rman.h>
89
90 #include <isa/isavar.h>
91
92 #include <dev/mse/msevar.h>
93
94 devclass_t      mse_devclass;
95
96 static  d_open_t        mseopen;
97 static  d_close_t       mseclose;
98 static  d_read_t        mseread;
99 static  d_ioctl_t       mseioctl;
100 static  d_poll_t        msepoll;
101
102 static struct cdevsw mse_cdevsw = {
103         .d_version =    D_VERSION,
104         .d_open =       mseopen,
105         .d_close =      mseclose,
106         .d_read =       mseread,
107         .d_ioctl =      mseioctl,
108         .d_poll =       msepoll,
109         .d_name =       "mse",
110 };
111
112 static  void            mseintr(void *);
113 static  void            mseintr_locked(mse_softc_t *sc);
114 static  void            msetimeout(void *);
115
116 #define MSE_NBLOCKIO(dev)       (dev2unit(dev) != 0)
117
118 #define MSEPRI  (PZERO + 3)
119
120 int
121 mse_common_attach(device_t dev)
122 {
123         mse_softc_t *sc;
124         int unit, flags, rid;
125
126         sc = device_get_softc(dev);
127         unit = device_get_unit(dev);
128         mtx_init(&sc->sc_lock, "mse", NULL, MTX_DEF);
129         callout_init_mtx(&sc->sc_callout, &sc->sc_lock, 0);
130
131         rid = 0;
132         sc->sc_intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
133                                              RF_ACTIVE);
134         if (sc->sc_intr == NULL) {
135                 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
136                 mtx_destroy(&sc->sc_lock);
137                 return ENXIO;
138         }
139
140         if (bus_setup_intr(dev, sc->sc_intr, INTR_TYPE_TTY | INTR_MPSAFE,
141             NULL, mseintr, sc, &sc->sc_ih)) {
142                 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
143                 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
144                 mtx_destroy(&sc->sc_lock);
145                 return ENXIO;
146         }
147         flags = device_get_flags(dev);
148         sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4;
149
150         sc->sc_dev = make_dev(&mse_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
151             "mse%d", unit);
152         sc->sc_dev->si_drv1 = sc;
153         sc->sc_ndev = make_dev(&mse_cdevsw, 1, UID_ROOT, GID_WHEEL, 0600,
154             "nmse%d", unit);
155         sc->sc_ndev->si_drv1 = sc;
156         return 0;
157 }
158
159 int
160 mse_detach(device_t dev)
161 {
162         mse_softc_t *sc;
163         int rid;
164
165         sc = device_get_softc(dev);
166         MSE_LOCK(sc);
167         if (sc->sc_flags & MSESC_OPEN) {
168                 MSE_UNLOCK(sc);
169                 return EBUSY;
170         }
171
172         /* Sabotage subsequent opens. */
173         sc->sc_mousetype = MSE_NONE;
174         MSE_UNLOCK(sc);
175
176         destroy_dev(sc->sc_dev);
177         destroy_dev(sc->sc_ndev);
178
179         rid = 0;
180         bus_teardown_intr(dev, sc->sc_intr, sc->sc_ih);
181         bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
182         bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
183
184         callout_drain(&sc->sc_callout);
185         mtx_destroy(&sc->sc_lock);
186
187         return 0;
188 }
189
190 /*
191  * Exclusive open the mouse, initialize it and enable interrupts.
192  */
193 static  int
194 mseopen(struct cdev *dev, int flags, int fmt, struct thread *td)
195 {
196         mse_softc_t *sc = dev->si_drv1;
197
198         MSE_LOCK(sc);
199         if (sc->sc_mousetype == MSE_NONE) {
200                 MSE_UNLOCK(sc);
201                 return (ENXIO);
202         }
203         if (sc->sc_flags & MSESC_OPEN) {
204                 MSE_UNLOCK(sc);
205                 return (EBUSY);
206         }
207         sc->sc_flags |= MSESC_OPEN;
208         sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS;
209         sc->sc_deltax = sc->sc_deltay = 0;
210         sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
211         sc->sc_watchdog = FALSE;
212         callout_reset(&sc->sc_callout, hz * 2, msetimeout, dev);
213         sc->mode.level = 0;
214         sc->status.flags = 0;
215         sc->status.button = sc->status.obutton = 0;
216         sc->status.dx = sc->status.dy = sc->status.dz = 0;
217
218         /*
219          * Initialize mouse interface and enable interrupts.
220          */
221         (*sc->sc_enablemouse)(sc->sc_port);
222         MSE_UNLOCK(sc);
223         return (0);
224 }
225
226 /*
227  * mseclose: just turn off mouse innterrupts.
228  */
229 static  int
230 mseclose(struct cdev *dev, int flags, int fmt, struct thread *td)
231 {
232         mse_softc_t *sc = dev->si_drv1;
233
234         MSE_LOCK(sc);
235         callout_stop(&sc->sc_callout);
236         (*sc->sc_disablemouse)(sc->sc_port);
237         sc->sc_flags &= ~MSESC_OPEN;
238         MSE_UNLOCK(sc);
239         return(0);
240 }
241
242 /*
243  * mseread: return mouse info using the MSC serial protocol, but without
244  * using bytes 4 and 5.
245  * (Yes this is cheesy, but it makes the X386 server happy, so...)
246  */
247 static  int
248 mseread(struct cdev *dev, struct uio *uio, int ioflag)
249 {
250         mse_softc_t *sc = dev->si_drv1;
251         int xfer, error;
252
253         /*
254          * If there are no protocol bytes to be read, set up a new protocol
255          * packet.
256          */
257         MSE_LOCK(sc);
258         while (sc->sc_flags & MSESC_READING) {
259                 if (MSE_NBLOCKIO(dev)) {
260                         MSE_UNLOCK(sc);
261                         return (0);
262                 }
263                 sc->sc_flags |= MSESC_WANT;
264                 error = mtx_sleep(sc, &sc->sc_lock, MSEPRI | PCATCH, "mseread",
265                     0);
266                 if (error) {
267                         MSE_UNLOCK(sc);
268                         return (error);
269                 }
270         }
271         sc->sc_flags |= MSESC_READING;
272         xfer = 0;
273         if (sc->sc_bytesread >= sc->mode.packetsize) {
274                 while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
275                        (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
276                         if (MSE_NBLOCKIO(dev))
277                                 goto out;
278                         sc->sc_flags |= MSESC_WANT;
279                         error = mtx_sleep(sc, &sc->sc_lock, MSEPRI | PCATCH,
280                                 "mseread", 0);
281                         if (error)
282                                 goto out;
283                 }
284
285                 /*
286                  * Generate protocol bytes.
287                  * For some reason X386 expects 5 bytes but never uses
288                  * the fourth or fifth?
289                  */
290                 sc->sc_bytes[0] = sc->mode.syncmask[1] 
291                     | (sc->sc_buttons & ~sc->mode.syncmask[0]);
292                 if (sc->sc_deltax > 127)
293                         sc->sc_deltax = 127;
294                 if (sc->sc_deltax < -127)
295                         sc->sc_deltax = -127;
296                 sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */
297                 if (sc->sc_deltay > 127)
298                         sc->sc_deltay = 127;
299                 if (sc->sc_deltay < -127)
300                         sc->sc_deltay = -127;
301                 sc->sc_bytes[1] = sc->sc_deltax;
302                 sc->sc_bytes[2] = sc->sc_deltay;
303                 sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
304                 sc->sc_bytes[5] = sc->sc_bytes[6] = 0;
305                 sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS;
306                 sc->sc_obuttons = sc->sc_buttons;
307                 sc->sc_deltax = sc->sc_deltay = 0;
308                 sc->sc_bytesread = 0;
309         }
310         xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread);
311         MSE_UNLOCK(sc);
312         error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio);
313         MSE_LOCK(sc);
314 out:
315         sc->sc_flags &= ~MSESC_READING;
316         if (error == 0)
317                 sc->sc_bytesread += xfer;
318         if (sc->sc_flags & MSESC_WANT) {
319                 sc->sc_flags &= ~MSESC_WANT;
320                 MSE_UNLOCK(sc);
321                 wakeup(sc);
322         } else
323                 MSE_UNLOCK(sc);
324         return (error);
325 }
326
327 /*
328  * mseioctl: process ioctl commands.
329  */
330 static int
331 mseioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
332 {
333         mse_softc_t *sc = dev->si_drv1;
334         mousestatus_t status;
335         int err = 0;
336
337         switch (cmd) {
338
339         case MOUSE_GETHWINFO:
340                 MSE_LOCK(sc);
341                 *(mousehw_t *)addr = sc->hw;
342                 if (sc->mode.level == 0)
343                         ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
344                 MSE_UNLOCK(sc);
345                 break;
346
347         case MOUSE_GETMODE:
348                 MSE_LOCK(sc);
349                 *(mousemode_t *)addr = sc->mode;
350                 switch (sc->mode.level) {
351                 case 0:
352                         break;
353                 case 1:
354                         ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
355                         ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
356                         ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
357                         break;
358                 }
359                 MSE_UNLOCK(sc);
360                 break;
361
362         case MOUSE_SETMODE:
363                 switch (((mousemode_t *)addr)->level) {
364                 case 0:
365                 case 1:
366                         break;
367                 default:
368                         return (EINVAL);
369                 }
370                 MSE_LOCK(sc);
371                 if (((mousemode_t *)addr)->accelfactor < -1) {
372                         MSE_UNLOCK(sc);
373                         return (EINVAL);
374                 } else if (((mousemode_t *)addr)->accelfactor >= 0)
375                         sc->mode.accelfactor = 
376                             ((mousemode_t *)addr)->accelfactor;
377                 sc->mode.level = ((mousemode_t *)addr)->level;
378                 switch (sc->mode.level) {
379                 case 0:
380                         sc->sc_bytesread = sc->mode.packetsize 
381                             = MOUSE_MSC_PACKETSIZE;
382                         break;
383                 case 1:
384                         sc->sc_bytesread = sc->mode.packetsize 
385                             = MOUSE_SYS_PACKETSIZE;
386                         break;
387                 }
388                 MSE_UNLOCK(sc);
389                 break;
390
391         case MOUSE_GETLEVEL:
392                 MSE_LOCK(sc);
393                 *(int *)addr = sc->mode.level;
394                 MSE_UNLOCK(sc);
395                 break;
396
397         case MOUSE_SETLEVEL:
398                 switch (*(int *)addr) {
399                 case 0:
400                         MSE_LOCK(sc);
401                         sc->mode.level = *(int *)addr;
402                         sc->sc_bytesread = sc->mode.packetsize 
403                             = MOUSE_MSC_PACKETSIZE;
404                         MSE_UNLOCK(sc);
405                         break;
406                 case 1:
407                         MSE_LOCK(sc);
408                         sc->mode.level = *(int *)addr;
409                         sc->sc_bytesread = sc->mode.packetsize 
410                             = MOUSE_SYS_PACKETSIZE;
411                         MSE_UNLOCK(sc);
412                         break;
413                 default:
414                         return (EINVAL);
415                 }
416                 break;
417
418         case MOUSE_GETSTATUS:
419                 MSE_LOCK(sc);
420                 status = sc->status;
421                 sc->status.flags = 0;
422                 sc->status.obutton = sc->status.button;
423                 sc->status.button = 0;
424                 sc->status.dx = 0;
425                 sc->status.dy = 0;
426                 sc->status.dz = 0;
427                 MSE_UNLOCK(sc);
428                 *(mousestatus_t *)addr = status;
429                 break;
430
431         case MOUSE_READSTATE:
432         case MOUSE_READDATA:
433                 return (ENODEV);
434
435 #if (defined(MOUSE_GETVARS))
436         case MOUSE_GETVARS:
437         case MOUSE_SETVARS:
438                 return (ENODEV);
439 #endif
440
441         default:
442                 return (ENOTTY);
443         }
444         return (err);
445 }
446
447 /*
448  * msepoll: check for mouse input to be processed.
449  */
450 static  int
451 msepoll(struct cdev *dev, int events, struct thread *td)
452 {
453         mse_softc_t *sc = dev->si_drv1;
454         int revents = 0;
455
456         MSE_LOCK(sc);
457         if (events & (POLLIN | POLLRDNORM)) {
458                 if (sc->sc_bytesread != sc->mode.packetsize ||
459                     sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
460                     (sc->sc_obuttons ^ sc->sc_buttons) != 0)
461                         revents |= events & (POLLIN | POLLRDNORM);
462                 else
463                         selrecord(td, &sc->sc_selp);
464         }
465         MSE_UNLOCK(sc);
466         return (revents);
467 }
468
469 /*
470  * msetimeout: watchdog timer routine.
471  */
472 static void
473 msetimeout(void *arg)
474 {
475         struct cdev *dev;
476         mse_softc_t *sc;
477
478         dev = (struct cdev *)arg;
479         sc = dev->si_drv1;
480         MSE_ASSERT_LOCKED(sc);
481         if (sc->sc_watchdog) {
482                 if (bootverbose)
483                         printf("%s: lost interrupt?\n", devtoname(dev));
484                 mseintr_locked(sc);
485         }
486         sc->sc_watchdog = TRUE;
487         callout_schedule(&sc->sc_callout, hz);
488 }
489
490 /*
491  * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
492  */
493 static void
494 mseintr(void *arg)
495 {
496         mse_softc_t *sc = arg;
497
498         MSE_LOCK(sc);
499         mseintr_locked(sc);
500         MSE_UNLOCK(sc);
501 }
502
503 static void
504 mseintr_locked(mse_softc_t *sc)
505 {
506         /*
507          * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP)
508          * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
509          */
510         static int butmap[8] = {
511                 0, 
512                 MOUSE_BUTTON3DOWN, 
513                 MOUSE_BUTTON2DOWN, 
514                 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 
515                 MOUSE_BUTTON1DOWN, 
516                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 
517                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
518                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
519         };
520         int dx, dy, but;
521         int sign;
522
523 #ifdef DEBUG
524         static int mse_intrcnt = 0;
525         if((mse_intrcnt++ % 10000) == 0)
526                 printf("mseintr\n");
527 #endif /* DEBUG */
528         if ((sc->sc_flags & MSESC_OPEN) == 0)
529                 return;
530
531         (*sc->sc_getmouse)(sc->sc_port, &dx, &dy, &but);
532         if (sc->mode.accelfactor > 0) {
533                 sign = (dx < 0);
534                 dx = dx * dx / sc->mode.accelfactor;
535                 if (dx == 0)
536                         dx = 1;
537                 if (sign)
538                         dx = -dx;
539                 sign = (dy < 0);
540                 dy = dy * dy / sc->mode.accelfactor;
541                 if (dy == 0)
542                         dy = 1;
543                 if (sign)
544                         dy = -dy;
545         }
546         sc->sc_deltax += dx;
547         sc->sc_deltay += dy;
548         sc->sc_buttons = but;
549
550         but = butmap[~but & MOUSE_MSC_BUTTONS];
551         sc->status.dx += dx;
552         sc->status.dy += dy;
553         sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0)
554             | (sc->status.button ^ but);
555         sc->status.button = but;
556
557         sc->sc_watchdog = FALSE;
558
559         /*
560          * If mouse state has changed, wake up anyone wanting to know.
561          */
562         if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
563             (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
564                 if (sc->sc_flags & MSESC_WANT) {
565                         sc->sc_flags &= ~MSESC_WANT;
566                         wakeup(sc);
567                 }
568                 selwakeuppri(&sc->sc_selp, MSEPRI);
569         }
570 }