2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2004 M. Warner Losh
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
32 * Copyright 1992 by the University of Guelph
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
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.
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!
57 * Modification history:
58 * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com)
59 * improved probe based on input from Logitech.
61 * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
62 * fixes to make it work with Microsoft InPort busmouse
64 * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
65 * added patches for new "select" interface
67 * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
68 * changed position of some spl()'s in mseread
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.
75 #include <sys/param.h>
76 #include <sys/systm.h>
78 #include <sys/kernel.h>
79 #include <sys/module.h>
82 #include <sys/selinfo.h>
84 #include <sys/mouse.h>
86 #include <machine/bus.h>
87 #include <machine/resource.h>
90 #include <isa/isavar.h>
92 #include <dev/mse/msevar.h>
94 static int mse_isa_probe(device_t dev);
95 static int mse_isa_attach(device_t dev);
97 static device_method_t mse_methods[] = {
98 DEVMETHOD(device_probe, mse_isa_probe),
99 DEVMETHOD(device_attach, mse_isa_attach),
100 DEVMETHOD(device_detach, mse_detach),
104 static driver_t mse_driver = {
110 DRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0);
112 static struct isa_pnp_id mse_ids[] = {
113 { 0x000fd041, "Bus mouse" }, /* PNP0F00 */
114 { 0x020fd041, "InPort mouse" }, /* PNP0F02 */
115 { 0x0d0fd041, "InPort mouse compatible" }, /* PNP0F0D */
116 { 0x110fd041, "Bus mouse compatible" }, /* PNP0F11 */
117 { 0x150fd041, "Logitech bus mouse" }, /* PNP0F15 */
118 { 0x180fd041, "Logitech bus mouse compatible" },/* PNP0F18 */
123 * Logitech bus mouse definitions
125 #define MSE_SETUP 0x91 /* What does this mean? */
126 /* The definition for the control port */
129 /* D7 = Mode set flag (1 = active) */
130 /* D6,D5 = Mode selection (port A) */
131 /* 00 = Mode 0 = Basic I/O */
132 /* 01 = Mode 1 = Strobed I/O */
133 /* 10 = Mode 2 = Bi-dir bus */
134 /* D4 = Port A direction (1 = input)*/
135 /* D3 = Port C (upper 4 bits) */
136 /* direction. (1 = input) */
137 /* D2 = Mode selection (port B & C) */
138 /* 0 = Mode 0 = Basic I/O */
139 /* 1 = Mode 1 = Strobed I/O */
140 /* D1 = Port B direction (1 = input)*/
141 /* D0 = Port C (lower 4 bits) */
142 /* direction. (1 = input) */
144 /* So 91 means Basic I/O on all 3 ports,*/
145 /* Port A is an input port, B is an */
146 /* output port, C is split with upper */
147 /* 4 bits being an output port and lower*/
148 /* 4 bits an input port, and enable the */
150 /* Courtesy Intel 8255 databook. Lars */
151 #define MSE_HOLD 0x80
152 #define MSE_RXLOW 0x00
153 #define MSE_RXHIGH 0x20
154 #define MSE_RYLOW 0x40
155 #define MSE_RYHIGH 0x60
156 #define MSE_DISINTR 0x10
157 #define MSE_INTREN 0x00
159 static int mse_probelogi(device_t dev, mse_softc_t *sc);
160 static void mse_disablelogi(struct resource *port);
161 static void mse_getlogi(struct resource *port, int *dx, int *dy,
163 static void mse_enablelogi(struct resource *port);
166 * ATI Inport mouse definitions
168 #define MSE_INPORT_RESET 0x80
169 #define MSE_INPORT_STATUS 0x00
170 #define MSE_INPORT_DX 0x01
171 #define MSE_INPORT_DY 0x02
172 #define MSE_INPORT_MODE 0x07
173 #define MSE_INPORT_HOLD 0x20
174 #define MSE_INPORT_INTREN 0x09
176 static int mse_probeati(device_t dev, mse_softc_t *sc);
177 static void mse_enableati(struct resource *port);
178 static void mse_disableati(struct resource *port);
179 static void mse_getati(struct resource *port, int *dx, int *dy,
182 static struct mse_types mse_types[] = {
184 mse_probeati, mse_enableati, mse_disableati, mse_getati,
185 { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
186 { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
187 { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
189 mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi,
190 { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
191 { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
192 { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
197 mse_isa_probe(device_t dev)
205 error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids);
209 sc = device_get_softc(dev);
211 sc->sc_port = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid,
212 MSE_IOSIZE, RF_ACTIVE);
213 if (sc->sc_port == NULL)
217 * Check for each mouse type in the table.
220 while (mse_types[i].m_type) {
221 if ((*mse_types[i].m_probe)(dev, sc)) {
222 sc->sc_mousetype = mse_types[i].m_type;
223 sc->sc_enablemouse = mse_types[i].m_enable;
224 sc->sc_disablemouse = mse_types[i].m_disable;
225 sc->sc_getmouse = mse_types[i].m_get;
226 sc->hw = mse_types[i].m_hw;
227 sc->mode = mse_types[i].m_mode;
228 bus_release_resource(dev, SYS_RES_IOPORT, rid,
230 device_set_desc(dev, "Bus/InPort Mouse");
235 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
240 mse_isa_attach(device_t dev)
245 sc = device_get_softc(dev);
248 sc->sc_port = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid,
249 MSE_IOSIZE, RF_ACTIVE);
250 if (sc->sc_port == NULL)
253 return (mse_common_attach(dev));
257 * Routines for the Logitech mouse.
260 * Test for a Logitech bus mouse and return 1 if it is.
261 * (until I know how to use the signature port properly, just disable
262 * interrupts and return 1)
265 mse_probelogi(device_t dev, mse_softc_t *sc)
270 bus_write_1(sc->sc_port, MSE_PORTD, MSE_SETUP);
271 /* set the signature port */
272 bus_write_1(sc->sc_port, MSE_PORTB, MSE_LOGI_SIG);
274 DELAY(30000); /* 30 ms delay */
275 sig = bus_read_1(sc->sc_port, MSE_PORTB) & 0xFF;
276 if (sig == MSE_LOGI_SIG) {
277 bus_write_1(sc->sc_port, MSE_PORTC, MSE_DISINTR);
281 device_printf(dev, "wrong signature %x\n", sig);
287 * Initialize Logitech mouse and enable interrupts.
290 mse_enablelogi(struct resource *port)
294 bus_write_1(port, MSE_PORTD, MSE_SETUP);
295 mse_getlogi(port, &dx, &dy, &but);
299 * Disable interrupts for Logitech mouse.
302 mse_disablelogi(struct resource *port)
305 bus_write_1(port, MSE_PORTC, MSE_DISINTR);
309 * Get the current dx, dy and button up/down state.
312 mse_getlogi(struct resource *port, int *dx, int *dy, int *but)
316 bus_write_1(port, MSE_PORTC, MSE_HOLD | MSE_RXLOW);
317 x = bus_read_1(port, MSE_PORTA);
318 *but = (x >> 5) & MOUSE_MSC_BUTTONS;
320 bus_write_1(port, MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
321 x |= (bus_read_1(port, MSE_PORTA) << 4);
322 bus_write_1(port, MSE_PORTC, MSE_HOLD | MSE_RYLOW);
323 y = (bus_read_1(port, MSE_PORTA) & 0xf);
324 bus_write_1(port, MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
325 y |= (bus_read_1(port, MSE_PORTA) << 4);
328 bus_write_1(port, MSE_PORTC, MSE_INTREN);
332 * Routines for the ATI Inport bus mouse.
335 * Test for an ATI Inport bus mouse and return 1 if it is.
336 * (do not enable interrupts)
339 mse_probeati(device_t dev, mse_softc_t *sc)
343 for (i = 0; i < 2; i++)
344 if (bus_read_1(sc->sc_port, MSE_PORTC) == 0xde)
350 * Initialize ATI Inport mouse and enable interrupts.
353 mse_enableati(struct resource *port)
356 bus_write_1(port, MSE_PORTA, MSE_INPORT_RESET);
357 bus_write_1(port, MSE_PORTA, MSE_INPORT_MODE);
358 bus_write_1(port, MSE_PORTB, MSE_INPORT_INTREN);
362 * Disable interrupts for ATI Inport mouse.
365 mse_disableati(struct resource *port)
368 bus_write_1(port, MSE_PORTA, MSE_INPORT_MODE);
369 bus_write_1(port, MSE_PORTB, 0);
373 * Get current dx, dy and up/down button state.
376 mse_getati(struct resource *port, int *dx, int *dy, int *but)
380 bus_write_1(port, MSE_PORTA, MSE_INPORT_MODE);
381 bus_write_1(port, MSE_PORTB, MSE_INPORT_HOLD);
382 bus_write_1(port, MSE_PORTA, MSE_INPORT_STATUS);
383 *but = ~bus_read_1(port, MSE_PORTB) & MOUSE_MSC_BUTTONS;
384 bus_write_1(port, MSE_PORTA, MSE_INPORT_DX);
385 byte = bus_read_1(port, MSE_PORTB);
387 bus_write_1(port, MSE_PORTA, MSE_INPORT_DY);
388 byte = bus_read_1(port, MSE_PORTB);
390 bus_write_1(port, MSE_PORTA, MSE_INPORT_MODE);
391 bus_write_1(port, MSE_PORTB, MSE_INPORT_INTREN);