mse_cbus.c revision 139749
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 *    without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in
13 *    the documentation and/or other materials provided with the
14 *    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 FOR
20 * 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: head/sys/dev/mse/mse_cbus.c 139749 2005-01-06 01:43:34Z imp $
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/clock.h>
88#include <machine/resource.h>
89#include <sys/rman.h>
90
91#include <isa/isavar.h>
92
93#include <dev/mse/msevar.h>
94
95static	int		mse_probe(device_t dev);
96static	int		mse_attach(device_t dev);
97static	int		mse_detach(device_t dev);
98
99static	device_method_t	mse_methods[] = {
100	DEVMETHOD(device_probe,		mse_probe),
101	DEVMETHOD(device_attach,	mse_attach),
102	DEVMETHOD(device_detach,	mse_detach),
103	{ 0, 0 }
104};
105
106static	driver_t	mse_driver = {
107	"mse",
108	mse_methods,
109	sizeof(mse_softc_t),
110};
111
112DRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0);
113
114static struct isa_pnp_id mse_ids[] = {
115#if 0
116	{ 0x001fa3b8, "PC-98 bus mouse" },		/* NEC1F00 */
117#endif
118	{ 0 }
119};
120
121/*
122 * PC-9801 Bus mouse definitions
123 */
124
125#define	MODE	MSE_PORTD
126#define	HC	MSE_PORTD
127#define	INT	MSE_PORTD
128
129#define	XL	0x00
130#define	XH	0x20
131#define	YL	0x40
132#define	YH	0x60
133
134#define	INT_ENABLE	0x8
135#define	INT_DISABLE	0x9
136#define	HC_NO_CLEAR	0xe
137#define	HC_CLEAR	0xf
138
139static	bus_addr_t	mse_port[] = {0, 2, 4, 6};
140
141static	int		mse_probe98m(device_t dev, mse_softc_t *sc);
142static	void		mse_disable98m(bus_space_tag_t t, bus_space_handle_t h);
143static	void		mse_get98m(bus_space_tag_t t, bus_space_handle_t h,
144			    int *dx, int *dy, int *but);
145static	void		mse_enable98m(bus_space_tag_t t, bus_space_handle_t h);
146
147static struct mse_types mse_types[] = {
148	{ MSE_98BUSMOUSE,
149	  mse_probe98m, mse_enable98m, mse_disable98m, mse_get98m,
150	  { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
151	  { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
152	    { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
153	{ 0, },
154};
155
156static	int
157mse_probe(dev)
158	device_t dev;
159{
160	mse_softc_t *sc;
161	int error;
162	int rid;
163	int i;
164
165	/* check PnP IDs */
166	error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids);
167	if (error == ENXIO)
168		return error;
169
170	sc = device_get_softc(dev);
171	rid = 0;
172	sc->sc_port = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, mse_port,
173					  MSE_IOSIZE, RF_ACTIVE);
174	if (sc->sc_port == NULL)
175		return ENXIO;
176	if (isa_load_resourcev(sc->sc_port, mse_port, MSE_IOSIZE)) {
177		bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
178		return ENXIO;
179	}
180	sc->sc_iot = rman_get_bustag(sc->sc_port);
181	sc->sc_ioh = rman_get_bushandle(sc->sc_port);
182
183	/*
184	 * Check for each mouse type in the table.
185	 */
186	i = 0;
187	while (mse_types[i].m_type) {
188		if ((*mse_types[i].m_probe)(dev, sc)) {
189			sc->sc_mousetype = mse_types[i].m_type;
190			sc->sc_enablemouse = mse_types[i].m_enable;
191			sc->sc_disablemouse = mse_types[i].m_disable;
192			sc->sc_getmouse = mse_types[i].m_get;
193			sc->hw = mse_types[i].m_hw;
194			sc->mode = mse_types[i].m_mode;
195			bus_release_resource(dev, SYS_RES_IOPORT, rid,
196					     sc->sc_port);
197			device_set_desc(dev, "Bus/InPort Mouse");
198			return 0;
199		}
200		i++;
201	}
202	bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
203	return ENXIO;
204}
205
206static	int
207mse_attach(dev)
208	device_t dev;
209{
210	mse_softc_t *sc;
211	int rid;
212
213	sc = device_get_softc(dev);
214
215	rid = 0;
216	sc->sc_port = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, mse_port,
217					  MSE_IOSIZE, RF_ACTIVE);
218	if (sc->sc_port == NULL)
219		return ENXIO;
220	if (isa_load_resourcev(sc->sc_port, mse_port, MSE_IOSIZE)) {
221		bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
222		return ENXIO;
223	}
224	sc->sc_iot = rman_get_bustag(sc->sc_port);
225	sc->sc_ioh = rman_get_bushandle(sc->sc_port);
226
227	return (mse_common_attach(dev));
228}
229
230static	int
231mse_detach(dev)
232	device_t dev;
233{
234	mse_softc_t *sc;
235	int rid;
236
237	sc = device_get_softc(dev);
238	if (sc->sc_flags & MSESC_OPEN)
239		return EBUSY;
240
241	rid = 0;
242	BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih);
243	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
244	bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
245
246	destroy_dev(sc->sc_dev);
247	destroy_dev(sc->sc_ndev);
248
249	return 0;
250}
251
252/*
253 * Routines for the PC98 bus mouse.
254 */
255
256/*
257 * Test for a PC98 bus mouse and return 1 if it is.
258 * (do not enable interrupts)
259 */
260static int
261mse_probe98m(dev, sc)
262	device_t dev;
263	mse_softc_t *sc;
264{
265	/* mode set */
266	bus_space_write_1(sc->sc_iot, sc->sc_ioh, MODE, 0x93);
267
268	/* initialize */
269	/* INT disable */
270	bus_space_write_1(sc->sc_iot, sc->sc_ioh, INT, INT_DISABLE);
271	/* HC = 0 */
272	bus_space_write_1(sc->sc_iot, sc->sc_ioh, HC, HC_NO_CLEAR);
273	/* HC = 1 */
274	bus_space_write_1(sc->sc_iot, sc->sc_ioh, HC, HC_CLEAR);
275
276	return (1);
277}
278
279/*
280 * Initialize PC98 bus mouse and enable interrupts.
281 */
282static void
283mse_enable98m(tag, handle)
284	bus_space_tag_t tag;
285	bus_space_handle_t handle;
286{
287	bus_space_write_1(tag, handle, INT, INT_ENABLE);    /* INT enable */
288	bus_space_write_1(tag, handle, HC, HC_NO_CLEAR);    /* HC = 0 */
289	bus_space_write_1(tag, handle, HC, HC_CLEAR);       /* HC = 1 */
290}
291
292/*
293 * Disable interrupts for PC98 Bus mouse.
294 */
295static void
296mse_disable98m(tag, handle)
297        bus_space_tag_t tag;
298        bus_space_handle_t handle;
299{
300	bus_space_write_1(tag, handle, INT, INT_DISABLE);   /* INT disable */
301	bus_space_write_1(tag, handle, HC, HC_NO_CLEAR);    /* HC = 0 */
302	bus_space_write_1(tag, handle, HC, HC_CLEAR);       /* HC = 1 */
303}
304
305/*
306 * Get current dx, dy and up/down button state.
307 */
308static void
309mse_get98m(tag, handle, dx, dy, but)
310        bus_space_tag_t tag;
311        bus_space_handle_t handle;
312        int *dx;
313        int *dy;
314        int *but;
315{
316	register char x, y;
317
318	bus_space_write_1(tag, handle, INT, INT_DISABLE);   /* INT disable */
319
320	bus_space_write_1(tag, handle, HC, HC_CLEAR);       /* HC = 1 */
321
322	/* X low */
323	bus_space_write_1(tag, handle, MSE_PORTC, 0x90 | XL);
324	x = bus_space_read_1(tag, handle, MSE_PORTA) & 0x0f;
325	/* X high */
326	bus_space_write_1(tag, handle, MSE_PORTC, 0x90 | XH);
327	x |= ((bus_space_read_1(tag, handle, MSE_PORTA)  & 0x0f) << 4);
328
329	/* Y low */
330	bus_space_write_1(tag, handle, MSE_PORTC, 0x90 | YL);
331	y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0x0f);
332	/* Y high */
333	bus_space_write_1(tag, handle, MSE_PORTC, 0x90 | YH);
334	y |= ((bus_space_read_1(tag, handle, MSE_PORTA) & 0x0f) << 4);
335
336	*but = (bus_space_read_1(tag, handle, MSE_PORTA) >> 5) & 7;
337
338	*dx = x;
339	*dy = y;
340
341	bus_space_write_1(tag, handle, HC, HC_NO_CLEAR);    /* HC = 0 */
342
343	bus_space_write_1(tag, handle, INT, INT_ENABLE);    /* INT enable */
344}
345