]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mse/mse.c
Remove joy(4) driver.
[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         gone_in_dev(dev, 12, "mse(4) driver");
157
158         return 0;
159 }
160
161 int
162 mse_detach(device_t dev)
163 {
164         mse_softc_t *sc;
165         int rid;
166
167         sc = device_get_softc(dev);
168         MSE_LOCK(sc);
169         if (sc->sc_flags & MSESC_OPEN) {
170                 MSE_UNLOCK(sc);
171                 return EBUSY;
172         }
173
174         /* Sabotage subsequent opens. */
175         sc->sc_mousetype = MSE_NONE;
176         MSE_UNLOCK(sc);
177
178         destroy_dev(sc->sc_dev);
179         destroy_dev(sc->sc_ndev);
180
181         rid = 0;
182         bus_teardown_intr(dev, sc->sc_intr, sc->sc_ih);
183         bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
184         bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
185
186         callout_drain(&sc->sc_callout);
187         mtx_destroy(&sc->sc_lock);
188
189         return 0;
190 }
191
192 /*
193  * Exclusive open the mouse, initialize it and enable interrupts.
194  */
195 static  int
196 mseopen(struct cdev *dev, int flags, int fmt, struct thread *td)
197 {
198         mse_softc_t *sc = dev->si_drv1;
199
200         MSE_LOCK(sc);
201         if (sc->sc_mousetype == MSE_NONE) {
202                 MSE_UNLOCK(sc);
203                 return (ENXIO);
204         }
205         if (sc->sc_flags & MSESC_OPEN) {
206                 MSE_UNLOCK(sc);
207                 return (EBUSY);
208         }
209         sc->sc_flags |= MSESC_OPEN;
210         sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS;
211         sc->sc_deltax = sc->sc_deltay = 0;
212         sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
213         sc->sc_watchdog = FALSE;
214         callout_reset(&sc->sc_callout, hz * 2, msetimeout, dev);
215         sc->mode.level = 0;
216         sc->status.flags = 0;
217         sc->status.button = sc->status.obutton = 0;
218         sc->status.dx = sc->status.dy = sc->status.dz = 0;
219
220         /*
221          * Initialize mouse interface and enable interrupts.
222          */
223         (*sc->sc_enablemouse)(sc->sc_port);
224         MSE_UNLOCK(sc);
225         return (0);
226 }
227
228 /*
229  * mseclose: just turn off mouse innterrupts.
230  */
231 static  int
232 mseclose(struct cdev *dev, int flags, int fmt, struct thread *td)
233 {
234         mse_softc_t *sc = dev->si_drv1;
235
236         MSE_LOCK(sc);
237         callout_stop(&sc->sc_callout);
238         (*sc->sc_disablemouse)(sc->sc_port);
239         sc->sc_flags &= ~MSESC_OPEN;
240         MSE_UNLOCK(sc);
241         return(0);
242 }
243
244 /*
245  * mseread: return mouse info using the MSC serial protocol, but without
246  * using bytes 4 and 5.
247  * (Yes this is cheesy, but it makes the X386 server happy, so...)
248  */
249 static  int
250 mseread(struct cdev *dev, struct uio *uio, int ioflag)
251 {
252         mse_softc_t *sc = dev->si_drv1;
253         int xfer, error;
254
255         /*
256          * If there are no protocol bytes to be read, set up a new protocol
257          * packet.
258          */
259         MSE_LOCK(sc);
260         while (sc->sc_flags & MSESC_READING) {
261                 if (MSE_NBLOCKIO(dev)) {
262                         MSE_UNLOCK(sc);
263                         return (0);
264                 }
265                 sc->sc_flags |= MSESC_WANT;
266                 error = mtx_sleep(sc, &sc->sc_lock, MSEPRI | PCATCH, "mseread",
267                     0);
268                 if (error) {
269                         MSE_UNLOCK(sc);
270                         return (error);
271                 }
272         }
273         sc->sc_flags |= MSESC_READING;
274         xfer = 0;
275         if (sc->sc_bytesread >= sc->mode.packetsize) {
276                 while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
277                        (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
278                         if (MSE_NBLOCKIO(dev))
279                                 goto out;
280                         sc->sc_flags |= MSESC_WANT;
281                         error = mtx_sleep(sc, &sc->sc_lock, MSEPRI | PCATCH,
282                                 "mseread", 0);
283                         if (error)
284                                 goto out;
285                 }
286
287                 /*
288                  * Generate protocol bytes.
289                  * For some reason X386 expects 5 bytes but never uses
290                  * the fourth or fifth?
291                  */
292                 sc->sc_bytes[0] = sc->mode.syncmask[1] 
293                     | (sc->sc_buttons & ~sc->mode.syncmask[0]);
294                 if (sc->sc_deltax > 127)
295                         sc->sc_deltax = 127;
296                 if (sc->sc_deltax < -127)
297                         sc->sc_deltax = -127;
298                 sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */
299                 if (sc->sc_deltay > 127)
300                         sc->sc_deltay = 127;
301                 if (sc->sc_deltay < -127)
302                         sc->sc_deltay = -127;
303                 sc->sc_bytes[1] = sc->sc_deltax;
304                 sc->sc_bytes[2] = sc->sc_deltay;
305                 sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
306                 sc->sc_bytes[5] = sc->sc_bytes[6] = 0;
307                 sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS;
308                 sc->sc_obuttons = sc->sc_buttons;
309                 sc->sc_deltax = sc->sc_deltay = 0;
310                 sc->sc_bytesread = 0;
311         }
312         xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread);
313         MSE_UNLOCK(sc);
314         error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio);
315         MSE_LOCK(sc);
316 out:
317         sc->sc_flags &= ~MSESC_READING;
318         if (error == 0)
319                 sc->sc_bytesread += xfer;
320         if (sc->sc_flags & MSESC_WANT) {
321                 sc->sc_flags &= ~MSESC_WANT;
322                 MSE_UNLOCK(sc);
323                 wakeup(sc);
324         } else
325                 MSE_UNLOCK(sc);
326         return (error);
327 }
328
329 /*
330  * mseioctl: process ioctl commands.
331  */
332 static int
333 mseioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
334 {
335         mse_softc_t *sc = dev->si_drv1;
336         mousestatus_t status;
337         int err = 0;
338
339         switch (cmd) {
340
341         case MOUSE_GETHWINFO:
342                 MSE_LOCK(sc);
343                 *(mousehw_t *)addr = sc->hw;
344                 if (sc->mode.level == 0)
345                         ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
346                 MSE_UNLOCK(sc);
347                 break;
348
349         case MOUSE_GETMODE:
350                 MSE_LOCK(sc);
351                 *(mousemode_t *)addr = sc->mode;
352                 switch (sc->mode.level) {
353                 case 0:
354                         break;
355                 case 1:
356                         ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
357                         ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
358                         ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
359                         break;
360                 }
361                 MSE_UNLOCK(sc);
362                 break;
363
364         case MOUSE_SETMODE:
365                 switch (((mousemode_t *)addr)->level) {
366                 case 0:
367                 case 1:
368                         break;
369                 default:
370                         return (EINVAL);
371                 }
372                 MSE_LOCK(sc);
373                 if (((mousemode_t *)addr)->accelfactor < -1) {
374                         MSE_UNLOCK(sc);
375                         return (EINVAL);
376                 } else if (((mousemode_t *)addr)->accelfactor >= 0)
377                         sc->mode.accelfactor = 
378                             ((mousemode_t *)addr)->accelfactor;
379                 sc->mode.level = ((mousemode_t *)addr)->level;
380                 switch (sc->mode.level) {
381                 case 0:
382                         sc->sc_bytesread = sc->mode.packetsize 
383                             = MOUSE_MSC_PACKETSIZE;
384                         break;
385                 case 1:
386                         sc->sc_bytesread = sc->mode.packetsize 
387                             = MOUSE_SYS_PACKETSIZE;
388                         break;
389                 }
390                 MSE_UNLOCK(sc);
391                 break;
392
393         case MOUSE_GETLEVEL:
394                 MSE_LOCK(sc);
395                 *(int *)addr = sc->mode.level;
396                 MSE_UNLOCK(sc);
397                 break;
398
399         case MOUSE_SETLEVEL:
400                 switch (*(int *)addr) {
401                 case 0:
402                         MSE_LOCK(sc);
403                         sc->mode.level = *(int *)addr;
404                         sc->sc_bytesread = sc->mode.packetsize 
405                             = MOUSE_MSC_PACKETSIZE;
406                         MSE_UNLOCK(sc);
407                         break;
408                 case 1:
409                         MSE_LOCK(sc);
410                         sc->mode.level = *(int *)addr;
411                         sc->sc_bytesread = sc->mode.packetsize 
412                             = MOUSE_SYS_PACKETSIZE;
413                         MSE_UNLOCK(sc);
414                         break;
415                 default:
416                         return (EINVAL);
417                 }
418                 break;
419
420         case MOUSE_GETSTATUS:
421                 MSE_LOCK(sc);
422                 status = sc->status;
423                 sc->status.flags = 0;
424                 sc->status.obutton = sc->status.button;
425                 sc->status.button = 0;
426                 sc->status.dx = 0;
427                 sc->status.dy = 0;
428                 sc->status.dz = 0;
429                 MSE_UNLOCK(sc);
430                 *(mousestatus_t *)addr = status;
431                 break;
432
433         case MOUSE_READSTATE:
434         case MOUSE_READDATA:
435                 return (ENODEV);
436
437         default:
438                 return (ENOTTY);
439         }
440         return (err);
441 }
442
443 /*
444  * msepoll: check for mouse input to be processed.
445  */
446 static  int
447 msepoll(struct cdev *dev, int events, struct thread *td)
448 {
449         mse_softc_t *sc = dev->si_drv1;
450         int revents = 0;
451
452         MSE_LOCK(sc);
453         if (events & (POLLIN | POLLRDNORM)) {
454                 if (sc->sc_bytesread != sc->mode.packetsize ||
455                     sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
456                     (sc->sc_obuttons ^ sc->sc_buttons) != 0)
457                         revents |= events & (POLLIN | POLLRDNORM);
458                 else
459                         selrecord(td, &sc->sc_selp);
460         }
461         MSE_UNLOCK(sc);
462         return (revents);
463 }
464
465 /*
466  * msetimeout: watchdog timer routine.
467  */
468 static void
469 msetimeout(void *arg)
470 {
471         struct cdev *dev;
472         mse_softc_t *sc;
473
474         dev = (struct cdev *)arg;
475         sc = dev->si_drv1;
476         MSE_ASSERT_LOCKED(sc);
477         if (sc->sc_watchdog) {
478                 if (bootverbose)
479                         printf("%s: lost interrupt?\n", devtoname(dev));
480                 mseintr_locked(sc);
481         }
482         sc->sc_watchdog = TRUE;
483         callout_schedule(&sc->sc_callout, hz);
484 }
485
486 /*
487  * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
488  */
489 static void
490 mseintr(void *arg)
491 {
492         mse_softc_t *sc = arg;
493
494         MSE_LOCK(sc);
495         mseintr_locked(sc);
496         MSE_UNLOCK(sc);
497 }
498
499 static void
500 mseintr_locked(mse_softc_t *sc)
501 {
502         /*
503          * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP)
504          * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
505          */
506         static int butmap[8] = {
507                 0, 
508                 MOUSE_BUTTON3DOWN, 
509                 MOUSE_BUTTON2DOWN, 
510                 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 
511                 MOUSE_BUTTON1DOWN, 
512                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 
513                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
514                 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
515         };
516         int dx, dy, but;
517         int sign;
518
519 #ifdef DEBUG
520         static int mse_intrcnt = 0;
521         if((mse_intrcnt++ % 10000) == 0)
522                 printf("mseintr\n");
523 #endif /* DEBUG */
524         if ((sc->sc_flags & MSESC_OPEN) == 0)
525                 return;
526
527         (*sc->sc_getmouse)(sc->sc_port, &dx, &dy, &but);
528         if (sc->mode.accelfactor > 0) {
529                 sign = (dx < 0);
530                 dx = dx * dx / sc->mode.accelfactor;
531                 if (dx == 0)
532                         dx = 1;
533                 if (sign)
534                         dx = -dx;
535                 sign = (dy < 0);
536                 dy = dy * dy / sc->mode.accelfactor;
537                 if (dy == 0)
538                         dy = 1;
539                 if (sign)
540                         dy = -dy;
541         }
542         sc->sc_deltax += dx;
543         sc->sc_deltay += dy;
544         sc->sc_buttons = but;
545
546         but = butmap[~but & MOUSE_MSC_BUTTONS];
547         sc->status.dx += dx;
548         sc->status.dy += dy;
549         sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0)
550             | (sc->status.button ^ but);
551         sc->status.button = but;
552
553         sc->sc_watchdog = FALSE;
554
555         /*
556          * If mouse state has changed, wake up anyone wanting to know.
557          */
558         if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
559             (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
560                 if (sc->sc_flags & MSESC_WANT) {
561                         sc->sc_flags &= ~MSESC_WANT;
562                         wakeup(sc);
563                 }
564                 selwakeuppri(&sc->sc_selp, MSEPRI);
565         }
566 }