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