mouse.h - Change to be not per-architecture.
[dragonfly.git] / sys / dev / misc / mse / mse.c
CommitLineData
984263bc
MD
1/*
2 * Copyright 1992 by the University of Guelph
3 *
4 * Permission to use, copy and modify this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation.
10 * University of Guelph makes no representations about the suitability of
11 * this software for any purpose. It is provided "as is"
12 * without express or implied warranty.
13 *
14 * $FreeBSD: src/sys/i386/isa/mse.c,v 1.49.2.1 2000/03/20 13:58:47 yokota Exp $
e3869ec7 15 * $DragonFly: src/sys/dev/misc/mse/mse.c,v 1.20 2006/12/22 23:26:17 swildner Exp $
984263bc
MD
16 */
17/*
18 * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and
19 * the X386 port, courtesy of
20 * Rick Macklem, rick@snowhite.cis.uoguelph.ca
21 * Caveats: The driver currently uses spltty(), but doesn't use any
22 * generic tty code. It could use splmse() (that only masks off the
23 * bus mouse interrupt, but that would require hacking in i386/isa/icu.s.
24 * (This may be worth the effort, since the Logitech generates 30/60
25 * interrupts/sec continuously while it is open.)
26 * NB: The ATI has NOT been tested yet!
27 */
28
29/*
30 * Modification history:
31 * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com)
32 * improved probe based on input from Logitech.
33 *
34 * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
35 * fixes to make it work with Microsoft InPort busmouse
36 *
37 * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
38 * added patches for new "select" interface
39 *
40 * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
41 * changed position of some spl()'s in mseread
42 *
43 * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu)
44 * limit maximum negative x/y value to -127 to work around XFree problem
45 * that causes spurious button pushes.
46 */
47
48#include <sys/param.h>
49#include <sys/systm.h>
50#include <sys/conf.h>
fef8985e 51#include <sys/device.h>
984263bc
MD
52#include <sys/kernel.h>
53#include <sys/bus.h>
6edc75f2 54#include <sys/event.h>
984263bc 55#include <sys/uio.h>
1f7ab7c9
MD
56#include <sys/rman.h>
57#include <sys/thread2.h>
984263bc 58
984263bc 59#include <machine/clock.h>
62770245 60#include <sys/mouse.h>
984263bc 61
1f2de5d4 62#include <bus/isa/isavar.h>
984263bc
MD
63
64/* driver configuration flags (config) */
65#define MSE_CONFIG_ACCEL 0x00f0 /* acceleration factor */
66#define MSE_CONFIG_FLAGS (MSE_CONFIG_ACCEL)
67
68/*
69 * Software control structure for mouse. The sc_enablemouse(),
70 * sc_disablemouse() and sc_getmouse() routines must be called spl'd().
71 */
72typedef struct mse_softc {
73 int sc_flags;
74 int sc_mousetype;
5b22f1a7 75 struct kqinfo sc_kqp;
984263bc
MD
76 struct resource *sc_port;
77 struct resource *sc_intr;
78 bus_space_tag_t sc_iot;
79 bus_space_handle_t sc_ioh;
80 void *sc_ih;
38e94a25
RG
81 void (*sc_enablemouse) (bus_space_tag_t t,
82 bus_space_handle_t h);
83 void (*sc_disablemouse) (bus_space_tag_t t,
84 bus_space_handle_t h);
85 void (*sc_getmouse) (bus_space_tag_t t,
984263bc 86 bus_space_handle_t h,
38e94a25 87 int *dx, int *dy, int *but);
984263bc
MD
88 int sc_deltax;
89 int sc_deltay;
90 int sc_obuttons;
91 int sc_buttons;
92 int sc_bytesread;
93 u_char sc_bytes[MOUSE_SYS_PACKETSIZE];
da8ef4a8 94 struct callout sc_callout;
984263bc 95 int sc_watchdog;
984263bc
MD
96 mousehw_t hw;
97 mousemode_t mode;
98 mousestatus_t status;
99} mse_softc_t;
100
101static devclass_t mse_devclass;
102
38e94a25
RG
103static int mse_probe (device_t dev);
104static int mse_attach (device_t dev);
105static int mse_detach (device_t dev);
984263bc
MD
106
107static device_method_t mse_methods[] = {
108 DEVMETHOD(device_probe, mse_probe),
109 DEVMETHOD(device_attach, mse_attach),
110 DEVMETHOD(device_detach, mse_detach),
111 { 0, 0 }
112};
113
114static driver_t mse_driver = {
115 "mse",
116 mse_methods,
117 sizeof(mse_softc_t),
118};
119
120DRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0);
121
122static struct isa_pnp_id mse_ids[] = {
123 { 0x000fd041, "Bus mouse" }, /* PNP0F00 */
124 { 0x020fd041, "InPort mouse" }, /* PNP0F02 */
125 { 0x0d0fd041, "InPort mouse compatible" }, /* PNP0F0D */
126 { 0x110fd041, "Bus mouse compatible" }, /* PNP0F11 */
127 { 0x150fd041, "Logitech bus mouse" }, /* PNP0F15 */
128 { 0x180fd041, "Logitech bus mouse compatible" },/* PNP0F18 */
129 { 0 }
130};
131
132static d_open_t mseopen;
133static d_close_t mseclose;
134static d_read_t mseread;
135static d_ioctl_t mseioctl;
6edc75f2
SG
136static d_kqfilter_t msekqfilter;
137
138static void msefilter_detach(struct knote *);
139static int msefilter(struct knote *, long);
984263bc
MD
140
141#define CDEV_MAJOR 27
fef8985e
MD
142static struct dev_ops mse_ops = {
143 { "mse", CDEV_MAJOR, 0 },
144 .d_open = mseopen,
145 .d_close = mseclose,
146 .d_read = mseread,
147 .d_ioctl = mseioctl,
6edc75f2 148 .d_kqfilter = msekqfilter
984263bc
MD
149};
150
38e94a25 151static void mseintr (void *);
984263bc
MD
152static timeout_t msetimeout;
153
154/* Flags */
155#define MSESC_OPEN 0x1
156#define MSESC_WANT 0x2
157
158/* and Mouse Types */
159#define MSE_NONE 0 /* don't move this! */
160#define MSE_LOGITECH 0x1
161#define MSE_ATIINPORT 0x2
162#define MSE_LOGI_SIG 0xA5
163
164#define MSE_PORTA 0
165#define MSE_PORTB 1
166#define MSE_PORTC 2
167#define MSE_PORTD 3
168#define MSE_IOSIZE 4
169
170#define MSE_UNIT(dev) (minor(dev) >> 1)
171#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1)
172
173/*
174 * Logitech bus mouse definitions
175 */
176#define MSE_SETUP 0x91 /* What does this mean? */
177 /* The definition for the control port */
178 /* is as follows: */
179
180 /* D7 = Mode set flag (1 = active) */
181 /* D6,D5 = Mode selection (port A) */
182 /* 00 = Mode 0 = Basic I/O */
183 /* 01 = Mode 1 = Strobed I/O */
184 /* 10 = Mode 2 = Bi-dir bus */
185 /* D4 = Port A direction (1 = input)*/
186 /* D3 = Port C (upper 4 bits) */
187 /* direction. (1 = input) */
188 /* D2 = Mode selection (port B & C) */
189 /* 0 = Mode 0 = Basic I/O */
190 /* 1 = Mode 1 = Strobed I/O */
191 /* D1 = Port B direction (1 = input)*/
192 /* D0 = Port C (lower 4 bits) */
193 /* direction. (1 = input) */
194
195 /* So 91 means Basic I/O on all 3 ports,*/
196 /* Port A is an input port, B is an */
197 /* output port, C is split with upper */
198 /* 4 bits being an output port and lower*/
199 /* 4 bits an input port, and enable the */
200 /* sucker. */
201 /* Courtesy Intel 8255 databook. Lars */
202#define MSE_HOLD 0x80
203#define MSE_RXLOW 0x00
204#define MSE_RXHIGH 0x20
205#define MSE_RYLOW 0x40
206#define MSE_RYHIGH 0x60
207#define MSE_DISINTR 0x10
208#define MSE_INTREN 0x00
209
38e94a25
RG
210static int mse_probelogi (device_t dev, mse_softc_t *sc);
211static void mse_disablelogi (bus_space_tag_t t,
212 bus_space_handle_t h);
213static void mse_getlogi (bus_space_tag_t t,
984263bc 214 bus_space_handle_t h,
38e94a25
RG
215 int *dx, int *dy, int *but);
216static void mse_enablelogi (bus_space_tag_t t,
217 bus_space_handle_t h);
984263bc
MD
218
219/*
220 * ATI Inport mouse definitions
221 */
222#define MSE_INPORT_RESET 0x80
223#define MSE_INPORT_STATUS 0x00
224#define MSE_INPORT_DX 0x01
225#define MSE_INPORT_DY 0x02
226#define MSE_INPORT_MODE 0x07
227#define MSE_INPORT_HOLD 0x20
228#define MSE_INPORT_INTREN 0x09
229
38e94a25
RG
230static int mse_probeati (device_t dev, mse_softc_t *sc);
231static void mse_enableati (bus_space_tag_t t,
232 bus_space_handle_t h);
233static void mse_disableati (bus_space_tag_t t,
234 bus_space_handle_t h);
235static void mse_getati (bus_space_tag_t t,
984263bc 236 bus_space_handle_t h,
38e94a25 237 int *dx, int *dy, int *but);
984263bc 238
984263bc
MD
239/*
240 * Table of mouse types.
241 * Keep the Logitech last, since I haven't figured out how to probe it
242 * properly yet. (Someday I'll have the documentation.)
243 */
244static struct mse_types {
245 int m_type; /* Type of bus mouse */
38e94a25 246 int (*m_probe) (device_t dev, mse_softc_t *sc);
984263bc 247 /* Probe routine to test for it */
38e94a25 248 void (*m_enable) (bus_space_tag_t t, bus_space_handle_t h);
984263bc 249 /* Start routine */
38e94a25 250 void (*m_disable) (bus_space_tag_t t, bus_space_handle_t h);
984263bc 251 /* Disable interrupts routine */
38e94a25
RG
252 void (*m_get) (bus_space_tag_t t, bus_space_handle_t h,
253 int *dx, int *dy, int *but);
984263bc
MD
254 /* and get mouse status */
255 mousehw_t m_hw; /* buttons iftype type model hwid */
256 mousemode_t m_mode; /* proto rate res accel level size mask */
257} mse_types[] = {
258 { MSE_ATIINPORT,
259 mse_probeati, mse_enableati, mse_disableati, mse_getati,
260 { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
261 { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
262 { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
263 { MSE_LOGITECH,
264 mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi,
265 { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
266 { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
267 { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
268 { 0, },
269};
270
271static int
c436375a 272mse_probe(device_t dev)
984263bc
MD
273{
274 mse_softc_t *sc;
275 int error;
276 int rid;
277 int i;
278
279 /* check PnP IDs */
280 error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids);
281 if (error == ENXIO)
282 return ENXIO;
283
284 sc = device_get_softc(dev);
285 rid = 0;
286 sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
287 MSE_IOSIZE, RF_ACTIVE);
288 if (sc->sc_port == NULL)
289 return ENXIO;
290 sc->sc_iot = rman_get_bustag(sc->sc_port);
291 sc->sc_ioh = rman_get_bushandle(sc->sc_port);
292
293 /*
294 * Check for each mouse type in the table.
295 */
296 i = 0;
297 while (mse_types[i].m_type) {
298 if ((*mse_types[i].m_probe)(dev, sc)) {
299 sc->sc_mousetype = mse_types[i].m_type;
300 sc->sc_enablemouse = mse_types[i].m_enable;
301 sc->sc_disablemouse = mse_types[i].m_disable;
302 sc->sc_getmouse = mse_types[i].m_get;
303 sc->hw = mse_types[i].m_hw;
304 sc->mode = mse_types[i].m_mode;
305 bus_release_resource(dev, SYS_RES_IOPORT, rid,
306 sc->sc_port);
307 device_set_desc(dev, "Bus/InPort Mouse");
308 return 0;
309 }
310 i++;
311 }
312 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
313 return ENXIO;
314}
315
316static int
c436375a 317mse_attach(device_t dev)
984263bc
MD
318{
319 mse_softc_t *sc;
320 int flags;
321 int unit;
322 int rid;
323
324 sc = device_get_softc(dev);
325 unit = device_get_unit(dev);
326
327 rid = 0;
328 sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
329 MSE_IOSIZE, RF_ACTIVE);
330 if (sc->sc_port == NULL)
331 return ENXIO;
332 sc->sc_intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
333 RF_ACTIVE);
334 if (sc->sc_intr == NULL) {
335 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
336 return ENXIO;
337 }
338 sc->sc_iot = rman_get_bustag(sc->sc_port);
339 sc->sc_ioh = rman_get_bushandle(sc->sc_port);
340
341 if (BUS_SETUP_INTR(device_get_parent(dev), dev, sc->sc_intr,
ee61f228 342 0, mseintr, sc, &sc->sc_ih, NULL)) {
984263bc
MD
343 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
344 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
345 return ENXIO;
346 }
347
348 flags = device_get_flags(dev);
349 sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4;
da8ef4a8 350 callout_init(&sc->sc_callout);
984263bc 351
fef8985e
MD
352 make_dev(&mse_ops, unit << 1, 0, 0, 0600, "mse%d", unit);
353 make_dev(&mse_ops, (unit<<1)+1, 0, 0, 0600, "nmse%d", unit);
984263bc
MD
354
355 return 0;
356}
357
358static int
c436375a 359mse_detach(device_t dev)
984263bc
MD
360{
361 mse_softc_t *sc;
362 int rid;
363
364 sc = device_get_softc(dev);
365 if (sc->sc_flags & MSESC_OPEN)
366 return EBUSY;
367
368 rid = 0;
369 BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih);
370 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
371 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
cd29885a 372 dev_ops_remove_minor(&mse_ops, device_get_unit(dev) << 1);
984263bc
MD
373
374 return 0;
375}
376
377/*
378 * Exclusive open the mouse, initialize it and enable interrupts.
379 */
380static int
fef8985e 381mseopen(struct dev_open_args *ap)
984263bc 382{
b13267a5 383 cdev_t dev = ap->a_head.a_dev;
984263bc 384 mse_softc_t *sc;
984263bc
MD
385
386 sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
387 if (sc == NULL)
388 return (ENXIO);
389 if (sc->sc_mousetype == MSE_NONE)
390 return (ENXIO);
391 if (sc->sc_flags & MSESC_OPEN)
392 return (EBUSY);
393 sc->sc_flags |= MSESC_OPEN;
394 sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS;
395 sc->sc_deltax = sc->sc_deltay = 0;
396 sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
397 sc->sc_watchdog = FALSE;
da8ef4a8 398 callout_reset(&sc->sc_callout, hz * 2, msetimeout, dev);
984263bc
MD
399 sc->mode.level = 0;
400 sc->status.flags = 0;
401 sc->status.button = sc->status.obutton = 0;
402 sc->status.dx = sc->status.dy = sc->status.dz = 0;
403
404 /*
405 * Initialize mouse interface and enable interrupts.
406 */
ed2a6656 407 crit_enter();
984263bc 408 (*sc->sc_enablemouse)(sc->sc_iot, sc->sc_ioh);
ed2a6656 409 crit_exit();
984263bc
MD
410 return (0);
411}
412
413/*
414 * mseclose: just turn off mouse innterrupts.
415 */
416static int
fef8985e 417mseclose(struct dev_close_args *ap)
984263bc 418{
b13267a5 419 cdev_t dev = ap->a_head.a_dev;
984263bc 420 mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
984263bc 421
ed2a6656 422 crit_enter();
da8ef4a8 423 callout_stop(&sc->sc_callout);
984263bc
MD
424 (*sc->sc_disablemouse)(sc->sc_iot, sc->sc_ioh);
425 sc->sc_flags &= ~MSESC_OPEN;
ed2a6656 426 crit_exit();
984263bc
MD
427 return(0);
428}
429
430/*
431 * mseread: return mouse info using the MSC serial protocol, but without
432 * using bytes 4 and 5.
433 * (Yes this is cheesy, but it makes the X386 server happy, so...)
434 */
435static int
fef8985e 436mseread(struct dev_read_args *ap)
984263bc 437{
b13267a5 438 cdev_t dev = ap->a_head.a_dev;
fef8985e 439 struct uio *uio = ap->a_uio;
984263bc 440 mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
ed2a6656 441 int xfer, error;
984263bc
MD
442
443 /*
444 * If there are no protocol bytes to be read, set up a new protocol
445 * packet.
446 */
ed2a6656 447 crit_enter(); /* XXX Should be its own spl, but where is imlXX() */
984263bc
MD
448 if (sc->sc_bytesread >= sc->mode.packetsize) {
449 while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
450 (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
451 if (MSE_NBLOCKIO(dev)) {
ed2a6656 452 crit_exit();
984263bc
MD
453 return (0);
454 }
455 sc->sc_flags |= MSESC_WANT;
377d4740 456 error = tsleep((caddr_t)sc, PCATCH, "mseread", 0);
984263bc 457 if (error) {
ed2a6656 458 crit_exit();
984263bc
MD
459 return (error);
460 }
461 }
462
463 /*
464 * Generate protocol bytes.
465 * For some reason X386 expects 5 bytes but never uses
466 * the fourth or fifth?
467 */
468 sc->sc_bytes[0] = sc->mode.syncmask[1]
469 | (sc->sc_buttons & ~sc->mode.syncmask[0]);
470 if (sc->sc_deltax > 127)
471 sc->sc_deltax = 127;
472 if (sc->sc_deltax < -127)
473 sc->sc_deltax = -127;
474 sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */
475 if (sc->sc_deltay > 127)
476 sc->sc_deltay = 127;
477 if (sc->sc_deltay < -127)
478 sc->sc_deltay = -127;
479 sc->sc_bytes[1] = sc->sc_deltax;
480 sc->sc_bytes[2] = sc->sc_deltay;
481 sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
482 sc->sc_bytes[5] = sc->sc_bytes[6] = 0;
483 sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS;
484 sc->sc_obuttons = sc->sc_buttons;
485 sc->sc_deltax = sc->sc_deltay = 0;
486 sc->sc_bytesread = 0;
487 }
ed2a6656 488 crit_exit();
e54488bb
MD
489 xfer = (int)szmin(uio->uio_resid,
490 sc->mode.packetsize - sc->sc_bytesread);
491 error = uiomove(&sc->sc_bytes[sc->sc_bytesread], (size_t)xfer, uio);
984263bc
MD
492 if (error)
493 return (error);
494 sc->sc_bytesread += xfer;
495 return(0);
496}
497
498/*
499 * mseioctl: process ioctl commands.
500 */
501static int
fef8985e 502mseioctl(struct dev_ioctl_args *ap)
984263bc 503{
b13267a5 504 cdev_t dev = ap->a_head.a_dev;
fef8985e 505 caddr_t addr = ap->a_data;
984263bc
MD
506 mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
507 mousestatus_t status;
508 int err = 0;
984263bc 509
fef8985e 510 switch (ap->a_cmd) {
984263bc 511 case MOUSE_GETHWINFO:
ed2a6656 512 crit_enter();
984263bc
MD
513 *(mousehw_t *)addr = sc->hw;
514 if (sc->mode.level == 0)
515 ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
ed2a6656 516 crit_exit();
984263bc
MD
517 break;
518
519 case MOUSE_GETMODE:
ed2a6656 520 crit_enter();
984263bc
MD
521 *(mousemode_t *)addr = sc->mode;
522 switch (sc->mode.level) {
523 case 0:
524 break;
525 case 1:
526 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
527 ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
528 ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
529 break;
530 }
ed2a6656 531 crit_exit();
984263bc
MD
532 break;
533
534 case MOUSE_SETMODE:
535 switch (((mousemode_t *)addr)->level) {
536 case 0:
537 case 1:
538 break;
539 default:
540 return (EINVAL);
541 }
542 if (((mousemode_t *)addr)->accelfactor < -1)
543 return (EINVAL);
544 else if (((mousemode_t *)addr)->accelfactor >= 0)
545 sc->mode.accelfactor =
546 ((mousemode_t *)addr)->accelfactor;
547 sc->mode.level = ((mousemode_t *)addr)->level;
548 switch (sc->mode.level) {
549 case 0:
550 sc->sc_bytesread = sc->mode.packetsize
551 = MOUSE_MSC_PACKETSIZE;
552 break;
553 case 1:
554 sc->sc_bytesread = sc->mode.packetsize
555 = MOUSE_SYS_PACKETSIZE;
556 break;
557 }
558 break;
559
560 case MOUSE_GETLEVEL:
561 *(int *)addr = sc->mode.level;
562 break;
563
564 case MOUSE_SETLEVEL:
565 switch (*(int *)addr) {
566 case 0:
567 sc->mode.level = *(int *)addr;
568 sc->sc_bytesread = sc->mode.packetsize
569 = MOUSE_MSC_PACKETSIZE;
570 break;
571 case 1:
572 sc->mode.level = *(int *)addr;
573 sc->sc_bytesread = sc->mode.packetsize
574 = MOUSE_SYS_PACKETSIZE;
575 break;
576 default:
577 return (EINVAL);
578 }
579 break;
580
581 case MOUSE_GETSTATUS:
ed2a6656 582 crit_enter();
984263bc
MD
583 status = sc->status;
584 sc->status.flags = 0;
585 sc->status.obutton = sc->status.button;
586 sc->status.button = 0;
587 sc->status.dx = 0;
588 sc->status.dy = 0;
589 sc->status.dz = 0;
ed2a6656 590 crit_exit();
984263bc
MD
591 *(mousestatus_t *)addr = status;
592 break;
593
594 case MOUSE_READSTATE:
595 case MOUSE_READDATA:
596 return (ENODEV);
597
598#if (defined(MOUSE_GETVARS))
599 case MOUSE_GETVARS:
600 case MOUSE_SETVARS:
601 return (ENODEV);
602#endif
603
604 default:
605 return (ENOTTY);
606 }
607 return (err);
608}
609
6edc75f2 610static struct filterops msefiltops =
4c91dbc9 611 { FILTEROP_ISFD, NULL, msefilter_detach, msefilter };
6edc75f2
SG
612
613static int
614msekqfilter(struct dev_kqfilter_args *ap)
615{
616 cdev_t dev = ap->a_head.a_dev;
617 mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
618 struct knote *kn = ap->a_kn;
619 struct klist *klist;
620
621 ap->a_result = 0;
622
623 switch (kn->kn_filter) {
624 case EVFILT_READ:
625 kn->kn_fop = &msefiltops;
626 kn->kn_hook = (caddr_t)sc;
627 break;
628 default:
b287d649 629 ap->a_result = EOPNOTSUPP;
6edc75f2
SG
630 return (0);
631 }
632
5b22f1a7
SG
633 klist = &sc->sc_kqp.ki_note;
634 knote_insert(klist, kn);
6edc75f2
SG
635
636 return (0);
637}
638
639static void
640msefilter_detach(struct knote *kn)
641{
642 mse_softc_t *sc = (mse_softc_t *)kn->kn_hook;
643 struct klist *klist;
644
5b22f1a7
SG
645 klist = &sc->sc_kqp.ki_note;
646 knote_remove(klist, kn);
6edc75f2
SG
647}
648
649static int
650msefilter(struct knote *kn, long hint)
651{
652 mse_softc_t *sc = (mse_softc_t *)kn->kn_hook;
653 int ready = 0;
654
655 crit_enter();
656 if (sc->sc_bytesread != sc->mode.packetsize ||
657 sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
658 (sc->sc_obuttons ^ sc->sc_buttons) != 0)
659 ready = 1;
660
661 crit_exit();
662
663 return (ready);
664}
665
984263bc
MD
666/*
667 * msetimeout: watchdog timer routine.
668 */
669static void
c436375a 670msetimeout(void *arg)
984263bc 671{
b13267a5 672 cdev_t dev;
984263bc
MD
673 mse_softc_t *sc;
674
b13267a5 675 dev = (cdev_t)arg;
984263bc
MD
676 sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
677 if (sc->sc_watchdog) {
678 if (bootverbose)
e3869ec7 679 kprintf("mse%d: lost interrupt?\n", MSE_UNIT(dev));
984263bc
MD
680 mseintr(sc);
681 }
682 sc->sc_watchdog = TRUE;
da8ef4a8 683 callout_reset(&sc->sc_callout, hz, msetimeout, dev);
984263bc
MD
684}
685
686/*
687 * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
688 */
689static void
c436375a 690mseintr(void *arg)
984263bc
MD
691{
692 /*
693 * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP)
694 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
695 */
696 static int butmap[8] = {
697 0,
698 MOUSE_BUTTON3DOWN,
699 MOUSE_BUTTON2DOWN,
700 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
701 MOUSE_BUTTON1DOWN,
702 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
703 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
704 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
705 };
706 mse_softc_t *sc = arg;
707 int dx, dy, but;
708 int sign;
709
710#ifdef DEBUG
711 static int mse_intrcnt = 0;
712 if((mse_intrcnt++ % 10000) == 0)
e3869ec7 713 kprintf("mseintr\n");
984263bc
MD
714#endif /* DEBUG */
715 if ((sc->sc_flags & MSESC_OPEN) == 0)
716 return;
717
718 (*sc->sc_getmouse)(sc->sc_iot, sc->sc_ioh, &dx, &dy, &but);
719 if (sc->mode.accelfactor > 0) {
720 sign = (dx < 0);
721 dx = dx * dx / sc->mode.accelfactor;
722 if (dx == 0)
723 dx = 1;
724 if (sign)
725 dx = -dx;
726 sign = (dy < 0);
727 dy = dy * dy / sc->mode.accelfactor;
728 if (dy == 0)
729 dy = 1;
730 if (sign)
731 dy = -dy;
732 }
733 sc->sc_deltax += dx;
734 sc->sc_deltay += dy;
735 sc->sc_buttons = but;
736
737 but = butmap[~but & MOUSE_MSC_BUTTONS];
738 sc->status.dx += dx;
739 sc->status.dy += dy;
740 sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0)
741 | (sc->status.button ^ but);
742 sc->status.button = but;
743
744 sc->sc_watchdog = FALSE;
745
746 /*
747 * If mouse state has changed, wake up anyone wanting to know.
748 */
749 if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
750 (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
751 if (sc->sc_flags & MSESC_WANT) {
752 sc->sc_flags &= ~MSESC_WANT;
753 wakeup((caddr_t)sc);
754 }
5b22f1a7 755 KNOTE(&sc->sc_kqp.ki_note, 0);
984263bc
MD
756 }
757}
758
759/*
760 * Routines for the Logitech mouse.
761 */
762/*
763 * Test for a Logitech bus mouse and return 1 if it is.
764 * (until I know how to use the signature port properly, just disable
765 * interrupts and return 1)
766 */
767static int
c436375a 768mse_probelogi(device_t dev, mse_softc_t *sc)
984263bc
MD
769{
770
771 int sig;
772
773 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTD, MSE_SETUP);
774 /* set the signature port */
775 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB, MSE_LOGI_SIG);
776
777 DELAY(30000); /* 30 ms delay */
778 sig = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB) & 0xFF;
779 if (sig == MSE_LOGI_SIG) {
780 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC,
781 MSE_DISINTR);
782 return(1);
783 } else {
784 if (bootverbose)
785 device_printf(dev, "wrong signature %x\n", sig);
786 return(0);
787 }
788}
789
790/*
791 * Initialize Logitech mouse and enable interrupts.
792 */
793static void
c436375a 794mse_enablelogi(bus_space_tag_t tag, bus_space_handle_t handle)
984263bc
MD
795{
796 int dx, dy, but;
797
798 bus_space_write_1(tag, handle, MSE_PORTD, MSE_SETUP);
799 mse_getlogi(tag, handle, &dx, &dy, &but);
800}
801
802/*
803 * Disable interrupts for Logitech mouse.
804 */
805static void
c436375a 806mse_disablelogi(bus_space_tag_t tag, bus_space_handle_t handle)
984263bc
MD
807{
808
809 bus_space_write_1(tag, handle, MSE_PORTC, MSE_DISINTR);
810}
811
812/*
813 * Get the current dx, dy and button up/down state.
814 */
815static void
c436375a
SW
816mse_getlogi(bus_space_tag_t tag, bus_space_handle_t handle, int *dx, int *dy,
817 int *but)
984263bc 818{
506ac56b 819 char x, y;
984263bc
MD
820
821 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXLOW);
822 x = bus_space_read_1(tag, handle, MSE_PORTA);
823 *but = (x >> 5) & MOUSE_MSC_BUTTONS;
824 x &= 0xf;
825 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
826 x |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4);
827 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYLOW);
828 y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0xf);
829 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
830 y |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4);
831 *dx = x;
832 *dy = y;
833 bus_space_write_1(tag, handle, MSE_PORTC, MSE_INTREN);
834}
835
836/*
837 * Routines for the ATI Inport bus mouse.
838 */
839/*
840 * Test for a ATI Inport bus mouse and return 1 if it is.
841 * (do not enable interrupts)
842 */
843static int
c436375a 844mse_probeati(device_t dev, mse_softc_t *sc)
984263bc
MD
845{
846 int i;
847
848 for (i = 0; i < 2; i++)
849 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC) == 0xde)
850 return (1);
851 return (0);
852}
853
854/*
855 * Initialize ATI Inport mouse and enable interrupts.
856 */
857static void
c436375a 858mse_enableati(bus_space_tag_t tag, bus_space_handle_t handle)
984263bc
MD
859{
860
861 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_RESET);
862 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
863 bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN);
864}
865
866/*
867 * Disable interrupts for ATI Inport mouse.
868 */
869static void
c436375a 870mse_disableati(bus_space_tag_t tag, bus_space_handle_t handle)
984263bc
MD
871{
872
873 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
874 bus_space_write_1(tag, handle, MSE_PORTB, 0);
875}
876
877/*
878 * Get current dx, dy and up/down button state.
879 */
880static void
c436375a
SW
881mse_getati(bus_space_tag_t tag, bus_space_handle_t handle, int *dx, int *dy,
882 int *but)
984263bc 883{
506ac56b 884 char byte;
984263bc
MD
885
886 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
887 bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_HOLD);
888 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_STATUS);
889 *but = ~bus_space_read_1(tag, handle, MSE_PORTB) & MOUSE_MSC_BUTTONS;
890 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DX);
891 byte = bus_space_read_1(tag, handle, MSE_PORTB);
892 *dx = byte;
893 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DY);
894 byte = bus_space_read_1(tag, handle, MSE_PORTB);
895 *dy = byte;
896 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
897 bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN);
898}