2 * Copyright (c) 2001, 2002 Greg Hughes (greg@NetBSD.org). All rights reserved.
3 * Copyright (c) 1999 PocketBSD Project. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 * Wscons mouse driver for DSIU TrackPoint on IBM WorkPad z50 by
29 * Greg Hughes (greg@NetBSD.org).
31 * Template for interrupt/device registration taken from vrdsu.c.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: vrdsiu_mouse.c,v 1.10 2009/03/14 14:46:00 dsl Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
41 #include <dev/wscons/wsconsio.h>
42 #include <dev/wscons/wsmousevar.h>
44 #include <machine/bus.h>
45 #include <machine/platid.h>
46 #include <machine/platid_mask.h>
48 #include <hpcmips/vr/vripvar.h>
49 #include <hpcmips/vr/vrdsiureg.h>
50 #include <hpcmips/vr/cmureg.h>
52 enum vrdsiu_mouse_stat
{
53 VRDSIU_MOUSE_STAT_DISABLE
,
54 VRDSIU_MOUSE_STAT_ENABLE
57 enum vrdsiu_ps2_input_state
{
58 VRDSIU_PS2_INPUT_STATE_BYTE0
,
59 VRDSIU_PS2_INPUT_STATE_BYTE1
,
60 VRDSIU_PS2_INPUT_STATE_BYTE2
65 bus_space_tag_t sc_iot
;
66 bus_space_handle_t sc_ioh
;
69 vrip_chipset_tag_t sc_vrip
;
71 enum vrdsiu_mouse_stat sc_mouse_stat
;
73 struct device
*sc_wsmousedev
;
76 static int asimOld
= 0;
78 static int vrdsiu_match(struct device
*, struct cfdata
*, void *);
79 static void vrdsiu_attach(struct device
*, struct device
*, void *);
81 static void vrdsiu_write(struct vrdsiu_softc
*, int, unsigned short);
82 static unsigned short vrdsiu_read(struct vrdsiu_softc
*, int);
84 /* Interrupt handlers */
85 static int vrdsiu_intr(void *);
86 static void vrdsiu_mouse_intr(struct vrdsiu_softc
*);
88 /* Enable/disable DSIU handling */
89 static int vrdsiu_mouse_enable(void *);
90 static int vrdsiu_mouse_ioctl(void *, u_long
, void *, int, struct lwp
*);
91 static void vrdsiu_mouse_disable(void *);
93 /* wsmouse access ops */
94 const struct wsmouse_accessops vrdsiu_accessops
= {
100 CFATTACH_DECL(vrdsiu_mouse
, sizeof(struct vrdsiu_softc
),
101 vrdsiu_match
, vrdsiu_attach
, NULL
, NULL
);
104 vrdsiu_write(struct vrdsiu_softc
*sc
, int port
, unsigned short val
)
106 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, port
, val
);
109 static inline unsigned short
110 vrdsiu_read(struct vrdsiu_softc
*sc
, int port
)
112 return bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, port
);
116 vrdsiu_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
122 vrdsiu_attach(struct device
*parent
, struct device
*self
, void *aux
)
124 struct vrdsiu_softc
*sc
= (struct vrdsiu_softc
*)self
;
125 struct vrip_attach_args
*va
= aux
;
126 struct wsmousedev_attach_args wsmaa
;
129 bus_space_tag_t iot
= va
->va_iot
;
131 if (va
->va_parent_ioh
!= 0)
132 res
= bus_space_subregion(iot
, va
->va_parent_ioh
, va
->va_addr
,
133 va
->va_size
, &sc
->sc_ioh
);
135 res
= bus_space_map(iot
, va
->va_addr
, va
->va_size
, 0,
138 printf(": can't map bus space\n");
143 sc
->sc_unit
= va
->va_unit
;
144 sc
->sc_vrip
= va
->va_vc
;
146 /* install interrupt handler and enable interrupt */
147 if (!(sc
->sc_handler
=
148 vrip_intr_establish(sc
->sc_vrip
, sc
->sc_unit
, 0, IPL_TTY
,
150 printf(": can't map interrupt line\n");
154 /* disable the handler initially */
155 vrdsiu_mouse_disable(sc
);
159 /* attach the mouse */
160 wsmaa
.accessops
= &vrdsiu_accessops
;
161 wsmaa
.accesscookie
= sc
;
162 sc
->sc_wsmousedev
= config_found(self
, &wsmaa
, wsmousedevprint
);
165 * TODO: Initialize the DSIU ourselves.
166 * We currently assume WinCE has set up the DSIU properly
169 asimOld
= vrdsiu_read(sc
, DSIUASIM00_REG_W
);
171 /* supply clock to the DSIU */
172 vrip_power(sc
->sc_vrip
, sc
->sc_unit
, 1);
176 vrdsiu_mouse_enable(void *v
)
178 struct vrdsiu_softc
*sc
= v
;
180 /* ensure the DSIU mouse is currently disabled! */
181 if (sc
->sc_mouse_stat
!= VRDSIU_MOUSE_STAT_DISABLE
)
184 /* enable the DSIU mouse */
185 sc
->sc_mouse_stat
= VRDSIU_MOUSE_STAT_ENABLE
;
187 /* unmask interrupts */
188 vrip_intr_setmask2(sc
->sc_vrip
, sc
->sc_handler
, (1 << 8) | (1 << 9) | (1 << 10), 1);
189 vrip_power(sc
->sc_vrip
, sc
->sc_unit
, 1);
195 vrdsiu_mouse_disable(void *v
)
197 struct vrdsiu_softc
*sc
= v
;
199 /* mask interrupts */
200 vrip_intr_setmask2(sc
->sc_vrip
, sc
->sc_handler
, (1 << 8) | (1 << 9) | (1 << 10), 0);
202 /* disable the DSIU mouse */
203 sc
->sc_mouse_stat
= VRDSIU_MOUSE_STAT_DISABLE
;
207 vrdsiu_mouse_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
209 /*struct vrdsiu_softc *sc = v;*/
213 case WSMOUSEIO_GTYPE
:
214 *(u_int
*)data
= WSMOUSE_TYPE_PS2
;
219 * TODO: Handle setting mouse resolution
231 vrdsiu_intr(void *arg
)
233 struct vrdsiu_softc
*sc
= arg
;
235 vrdsiu_mouse_intr(sc
);
241 * PS/2 protocol defines
243 #define PS2_L_BUTTON_MASK (1 << 0)
244 #define PS2_R_BUTTON_MASK (1 << 1)
245 #define PS2_M_BUTTON_MASK (1 << 2)
246 #define PS2_BYTE0_BIT3_MASK (1 << 3)
247 #define PS2_DX_SIGN_MASK (1 << 4)
248 #define PS2_DY_SIGN_MASK (1 << 5)
249 #define PS2_DX_OVERFLOW_MASK (1 << 6)
250 #define PS2_DY_OVERFLOW_MASK (1 << 7)
255 #define WSC_L_BUTTON 0x01
256 #define WSC_M_BUTTON 0x02
257 #define WSC_R_BUTTON 0x04
260 vrdsiu_mouse_intr(struct vrdsiu_softc
*sc
)
267 static u_char buttons
;
268 static enum vrdsiu_ps2_input_state ps2_state
= 0;
270 /* What caused the interrupt? */
271 intrReason
= vrdsiu_read(sc
, DSIUINTR0_REG_W
);
274 * TODO: Check for error conditions; specifically need to handle
275 * overruns (which currently mess up the mouse).
278 /* disable reception */
279 vrdsiu_write(sc
, DSIUASIM00_REG_W
, asimOld
& ~DSIUASIM00_RXE0
);
281 if (intrReason
& DSIUINTR0_INTSER0
)
284 /* Ignore everything except receive notifications */
285 if ((intrReason
& DSIUINTR0_INTSR0
) == 0)
289 b
= (unsigned char)vrdsiu_read(sc
, DSIURXB0L_REG_W
);
291 /* check if the DSIU is enabled */
292 if (sc
->sc_mouse_stat
== VRDSIU_MOUSE_STAT_DISABLE
)
294 /* Throw away input to keep the DSIU's buffer clean */
299 * PS/2 protocol interpretation
301 * A PS/2 packet consists of 3 bytes. We read them in, in order, and
302 * piece together the mouse info.
304 * Byte 0 contains button info and dx/dy signedness
305 * Byte 1 contains dx info
306 * Byte 2 contains dy info
308 * Please see PS/2 specs for detailed information; brief descriptions
309 * are provided below.
311 * PS/2 mouse specs for the TrackPoint from IBM's TrackPoint Engineering
312 * Specification Version 4.0.
316 case VRDSIU_PS2_INPUT_STATE_BYTE0
:
317 /* Bit 3 of byte 0 is always 1; we use that info to sync input */
318 if ((b
& PS2_BYTE0_BIT3_MASK
) == 0)
321 if (b
& (PS2_M_BUTTON_MASK
| PS2_DX_OVERFLOW_MASK
|
322 PS2_DY_OVERFLOW_MASK
))
325 /* Extract button state */
326 buttons
= ((b
& PS2_L_BUTTON_MASK
) ? WSC_L_BUTTON
: 0)
327 | ((b
& PS2_M_BUTTON_MASK
) ? WSC_M_BUTTON
: 0)
328 | ((b
& PS2_R_BUTTON_MASK
) ? WSC_R_BUTTON
: 0);
330 /* Extract dx/dy signedness -- 9-bit 2's comp */
331 /* dx = (b & PS2_DX_SIGN_MASK) ? 0xFFFFFFFF : 0;
332 dy = (b & PS2_DY_SIGN_MASK) ? 0xFFFFFFFF : 0; */
334 ps2_state
= VRDSIU_PS2_INPUT_STATE_BYTE1
;
337 case VRDSIU_PS2_INPUT_STATE_BYTE1
:
338 /* put in the lower 8 bits of dx */
343 ps2_state
= VRDSIU_PS2_INPUT_STATE_BYTE2
;
346 case VRDSIU_PS2_INPUT_STATE_BYTE2
:
347 /* put in the lower 8 bits of dy */
352 /* We now have a complete packet; send to wscons */
353 wsmouse_input(sc
->sc_wsmousedev
,
356 WSMOUSE_INPUT_DELTA
);
358 ps2_state
= VRDSIU_PS2_INPUT_STATE_BYTE0
;
363 /* clear the interrupt */
364 vrdsiu_write(sc
, DSIUINTR0_REG_W
, intrReason
);
366 /* enable reception */
367 vrdsiu_write(sc
, DSIUASIM00_REG_W
, asimOld
| DSIUASIM00_RXE0
);