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$
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_flags = D_NEEDGIANT,
103 .d_open = mseopen,
104 .d_close = mseclose,
105 .d_read = mseread,
106 .d_ioctl = mseioctl,
107 .d_poll = msepoll,
108 .d_name = "mse",
109 };
110
111 static void mseintr(void *);
112 static timeout_t msetimeout;
113
114 #define MSE_NBLOCKIO(dev) dev2unit(dev)
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
127 rid = 0;
128 sc->sc_intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
129 RF_ACTIVE);
130 if (sc->sc_intr == NULL) {
131 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
132 return ENXIO;
133 }
134
135 if (bus_setup_intr(dev, sc->sc_intr,
136 INTR_TYPE_TTY, NULL, mseintr, sc, &sc->sc_ih)) {
137 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
138 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
139 return ENXIO;
140 }
141 flags = device_get_flags(dev);
142 sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4;
143 callout_handle_init(&sc->sc_callout);
144
145 sc->sc_dev = make_dev(&mse_cdevsw, 0, 0, 0, 0600, "mse%d", unit);
146 sc->sc_dev->si_drv1 = sc;
147 sc->sc_ndev = make_dev(&mse_cdevsw, 1, 0, 0, 0600, "nmse%d", unit);
148 sc->sc_ndev->si_drv1 = sc;
149 return 0;
150 }
151
152 /*
153 * Exclusive open the mouse, initialize it and enable interrupts.
154 */
155 static int
156 mseopen(struct cdev *dev, int flags, int fmt, struct thread *td)
157 {
158 mse_softc_t *sc = dev->si_drv1;
159 int s;
160
161 if (sc->sc_mousetype == MSE_NONE)
162 return (ENXIO);
163 if (sc->sc_flags & MSESC_OPEN)
164 return (EBUSY);
165 sc->sc_flags |= MSESC_OPEN;
166 sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS;
167 sc->sc_deltax = sc->sc_deltay = 0;
168 sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
169 sc->sc_watchdog = FALSE;
170 sc->sc_callout = timeout(msetimeout, dev, hz*2);
171 sc->mode.level = 0;
172 sc->status.flags = 0;
173 sc->status.button = sc->status.obutton = 0;
174 sc->status.dx = sc->status.dy = sc->status.dz = 0;
175
176 /*
177 * Initialize mouse interface and enable interrupts.
178 */
179 s = spltty();
180 (*sc->sc_enablemouse)(sc->sc_iot, sc->sc_ioh);
181 splx(s);
182 return (0);
183 }
184
185 /*
186 * mseclose: just turn off mouse innterrupts.
187 */
188 static int
189 mseclose(struct cdev *dev, int flags, int fmt, struct thread *td)
190 {
191 mse_softc_t *sc = dev->si_drv1;
192 int s;
193
194 untimeout(msetimeout, dev, sc->sc_callout);
195 callout_handle_init(&sc->sc_callout);
196 s = spltty();
197 (*sc->sc_disablemouse)(sc->sc_iot, sc->sc_ioh);
198 sc->sc_flags &= ~MSESC_OPEN;
199 splx(s);
200 return(0);
201 }
202
203 /*
204 * mseread: return mouse info using the MSC serial protocol, but without
205 * using bytes 4 and 5.
206 * (Yes this is cheesy, but it makes the X386 server happy, so...)
207 */
208 static int
209 mseread(struct cdev *dev, struct uio *uio, int ioflag)
210 {
211 mse_softc_t *sc = dev->si_drv1;
212 int xfer, s, error;
213
214 /*
215 * If there are no protocol bytes to be read, set up a new protocol
216 * packet.
217 */
218 s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
219 if (sc->sc_bytesread >= sc->mode.packetsize) {
220 while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
221 (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
222 if (MSE_NBLOCKIO(dev)) {
223 splx(s);
224 return (0);
225 }
226 sc->sc_flags |= MSESC_WANT;
227 error = tsleep(sc, MSEPRI | PCATCH,
228 "mseread", 0);
229 if (error) {
230 splx(s);
231 return (error);
232 }
233 }
234
235 /*
236 * Generate protocol bytes.
237 * For some reason X386 expects 5 bytes but never uses
238 * the fourth or fifth?
239 */
240 sc->sc_bytes[0] = sc->mode.syncmask[1]
241 | (sc->sc_buttons & ~sc->mode.syncmask[0]);
242 if (sc->sc_deltax > 127)
243 sc->sc_deltax = 127;
244 if (sc->sc_deltax < -127)
245 sc->sc_deltax = -127;
246 sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */
247 if (sc->sc_deltay > 127)
248 sc->sc_deltay = 127;
249 if (sc->sc_deltay < -127)
250 sc->sc_deltay = -127;
251 sc->sc_bytes[1] = sc->sc_deltax;
252 sc->sc_bytes[2] = sc->sc_deltay;
253 sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
254 sc->sc_bytes[5] = sc->sc_bytes[6] = 0;
255 sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS;
256 sc->sc_obuttons = sc->sc_buttons;
257 sc->sc_deltax = sc->sc_deltay = 0;
258 sc->sc_bytesread = 0;
259 }
260 splx(s);
261 xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread);
262 error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio);
263 if (error)
264 return (error);
265 sc->sc_bytesread += xfer;
266 return(0);
267 }
268
269 /*
270 * mseioctl: process ioctl commands.
271 */
272 static int
273 mseioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
274 {
275 mse_softc_t *sc = dev->si_drv1;
276 mousestatus_t status;
277 int err = 0;
278 int s;
279
280 switch (cmd) {
281
282 case MOUSE_GETHWINFO:
283 s = spltty();
284 *(mousehw_t *)addr = sc->hw;
285 if (sc->mode.level == 0)
286 ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
287 splx(s);
288 break;
289
290 case MOUSE_GETMODE:
291 s = spltty();
292 *(mousemode_t *)addr = sc->mode;
293 switch (sc->mode.level) {
294 case 0:
295 break;
296 case 1:
297 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
298 ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
299 ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
300 break;
301 }
302 splx(s);
303 break;
304
305 case MOUSE_SETMODE:
306 switch (((mousemode_t *)addr)->level) {
307 case 0:
308 case 1:
309 break;
310 default:
311 return (EINVAL);
312 }
313 if (((mousemode_t *)addr)->accelfactor < -1)
314 return (EINVAL);
315 else if (((mousemode_t *)addr)->accelfactor >= 0)
316 sc->mode.accelfactor =
317 ((mousemode_t *)addr)->accelfactor;
318 sc->mode.level = ((mousemode_t *)addr)->level;
319 switch (sc->mode.level) {
320 case 0:
321 sc->sc_bytesread = sc->mode.packetsize
322 = MOUSE_MSC_PACKETSIZE;
323 break;
324 case 1:
325 sc->sc_bytesread = sc->mode.packetsize
326 = MOUSE_SYS_PACKETSIZE;
327 break;
328 }
329 break;
330
331 case MOUSE_GETLEVEL:
332 *(int *)addr = sc->mode.level;
333 break;
334
335 case MOUSE_SETLEVEL:
336 switch (*(int *)addr) {
337 case 0:
338 sc->mode.level = *(int *)addr;
339 sc->sc_bytesread = sc->mode.packetsize
340 = MOUSE_MSC_PACKETSIZE;
341 break;
342 case 1:
343 sc->mode.level = *(int *)addr;
344 sc->sc_bytesread = sc->mode.packetsize
345 = MOUSE_SYS_PACKETSIZE;
346 break;
347 default:
348 return (EINVAL);
349 }
350 break;
351
352 case MOUSE_GETSTATUS:
353 s = spltty();
354 status = sc->status;
355 sc->status.flags = 0;
356 sc->status.obutton = sc->status.button;
357 sc->status.button = 0;
358 sc->status.dx = 0;
359 sc->status.dy = 0;
360 sc->status.dz = 0;
361 splx(s);
362 *(mousestatus_t *)addr = status;
363 break;
364
365 case MOUSE_READSTATE:
366 case MOUSE_READDATA:
367 return (ENODEV);
368
369 #if (defined(MOUSE_GETVARS))
370 case MOUSE_GETVARS:
371 case MOUSE_SETVARS:
372 return (ENODEV);
373 #endif
374
375 default:
376 return (ENOTTY);
377 }
378 return (err);
379 }
380
381 /*
382 * msepoll: check for mouse input to be processed.
383 */
384 static int
385 msepoll(struct cdev *dev, int events, struct thread *td)
386 {
387 mse_softc_t *sc = dev->si_drv1;
388 int s;
389 int revents = 0;
390
391 s = spltty();
392 if (events & (POLLIN | POLLRDNORM)) {
393 if (sc->sc_bytesread != sc->mode.packetsize ||
394 sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
395 (sc->sc_obuttons ^ sc->sc_buttons) != 0)
396 revents |= events & (POLLIN | POLLRDNORM);
397 else {
398 /*
399 * Since this is an exclusive open device, any previous
400 * proc pointer is trash now, so we can just assign it.
401 */
402 selrecord(td, &sc->sc_selp);
403 }
404 }
405 splx(s);
406 return (revents);
407 }
408
409 /*
410 * msetimeout: watchdog timer routine.
411 */
412 static void
413 msetimeout(void *arg)
414 {
415 struct cdev *dev;
416 mse_softc_t *sc;
417
418 dev = (struct cdev *)arg;
419 sc = dev->si_drv1;
420 if (sc->sc_watchdog) {
421 if (bootverbose)
422 printf("%s: lost interrupt?\n", devtoname(dev));
423 mseintr(sc);
424 }
425 sc->sc_watchdog = TRUE;
426 sc->sc_callout = timeout(msetimeout, dev, hz);
427 }
428
429 /*
430 * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
431 */
432 static void
433 mseintr(void *arg)
434 {
435 /*
436 * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP)
437 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
438 */
439 static int butmap[8] = {
440 0,
441 MOUSE_BUTTON3DOWN,
442 MOUSE_BUTTON2DOWN,
443 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
444 MOUSE_BUTTON1DOWN,
445 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
446 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
447 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
448 };
449 mse_softc_t *sc = arg;
450 int dx, dy, but;
451 int sign;
452
453 #ifdef DEBUG
454 static int mse_intrcnt = 0;
455 if((mse_intrcnt++ % 10000) == 0)
456 printf("mseintr\n");
457 #endif /* DEBUG */
458 if ((sc->sc_flags & MSESC_OPEN) == 0)
459 return;
460
461 (*sc->sc_getmouse)(sc->sc_iot, sc->sc_ioh, &dx, &dy, &but);
462 if (sc->mode.accelfactor > 0) {
463 sign = (dx < 0);
464 dx = dx * dx / sc->mode.accelfactor;
465 if (dx == 0)
466 dx = 1;
467 if (sign)
468 dx = -dx;
469 sign = (dy < 0);
470 dy = dy * dy / sc->mode.accelfactor;
471 if (dy == 0)
472 dy = 1;
473 if (sign)
474 dy = -dy;
475 }
476 sc->sc_deltax += dx;
477 sc->sc_deltay += dy;
478 sc->sc_buttons = but;
479
480 but = butmap[~but & MOUSE_MSC_BUTTONS];
481 sc->status.dx += dx;
482 sc->status.dy += dy;
483 sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0)
484 | (sc->status.button ^ but);
485 sc->status.button = but;
486
487 sc->sc_watchdog = FALSE;
488
489 /*
490 * If mouse state has changed, wake up anyone wanting to know.
491 */
492 if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
493 (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
494 if (sc->sc_flags & MSESC_WANT) {
495 sc->sc_flags &= ~MSESC_WANT;
496 wakeup(sc);
497 }
498 selwakeuppri(&sc->sc_selp, MSEPRI);
499 }
500 }
Cache object: dd143ed28123e7ddb1d98f45b513088e
|