xref: /netbsd-src/sys/arch/arc/dev/opms.c (revision 5ab06420d2c61f1ec805d65adf312f051340b253)
1*5ab06420Sthorpej /*	$NetBSD: opms.c,v 1.26 2021/09/26 16:36:18 thorpej Exp $	*/
2b7abba77Ssoda /*	$OpenBSD: pccons.c,v 1.22 1999/01/30 22:39:37 imp Exp $	*/
3b7abba77Ssoda /*	NetBSD: pms.c,v 1.21 1995/04/18 02:25:18 mycroft Exp	*/
4b7abba77Ssoda 
5b7abba77Ssoda /*-
6b7abba77Ssoda  * Copyright (c) 1990 The Regents of the University of California.
7b7abba77Ssoda  * All rights reserved.
8b7abba77Ssoda  *
9b7abba77Ssoda  * This code is derived from software contributed to Berkeley by
10b7abba77Ssoda  * William Jolitz and Don Ahn.
11b7abba77Ssoda  *
12b7abba77Ssoda  * Copyright (c) 1994 Charles M. Hannum.
13b7abba77Ssoda  * Copyright (c) 1992, 1993 Erik Forsberg.
14b7abba77Ssoda  *
15b7abba77Ssoda  * Redistribution and use in source and binary forms, with or without
16b7abba77Ssoda  * modification, are permitted provided that the following conditions
17b7abba77Ssoda  * are met:
18b7abba77Ssoda  * 1. Redistributions of source code must retain the above copyright
19b7abba77Ssoda  *    notice, this list of conditions and the following disclaimer.
20b7abba77Ssoda  * 2. Redistributions in binary form must reproduce the above copyright
21b7abba77Ssoda  *    notice, this list of conditions and the following disclaimer in the
22b7abba77Ssoda  *    documentation and/or other materials provided with the distribution.
23aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
24aad01611Sagc  *    may be used to endorse or promote products derived from this software
25aad01611Sagc  *    without specific prior written permission.
26aad01611Sagc  *
27aad01611Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28aad01611Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29aad01611Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30aad01611Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31aad01611Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32aad01611Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33aad01611Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34aad01611Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35aad01611Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36aad01611Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37aad01611Sagc  * SUCH DAMAGE.
38aad01611Sagc  *
39aad01611Sagc  *	@(#)pccons.c	5.11 (Berkeley) 5/21/91
40aad01611Sagc  */
41aad01611Sagc 
42aad01611Sagc /*-
43aad01611Sagc  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.  All rights reserved.
44aad01611Sagc  *
45aad01611Sagc  * This code is derived from software contributed to Berkeley by
46aad01611Sagc  * William Jolitz and Don Ahn.
47aad01611Sagc  *
48aad01611Sagc  * Copyright (c) 1994 Charles M. Hannum.
49aad01611Sagc  * Copyright (c) 1992, 1993 Erik Forsberg.
50aad01611Sagc  *
51aad01611Sagc  * Redistribution and use in source and binary forms, with or without
52aad01611Sagc  * modification, are permitted provided that the following conditions
53aad01611Sagc  * are met:
54aad01611Sagc  * 1. Redistributions of source code must retain the above copyright
55aad01611Sagc  *    notice, this list of conditions and the following disclaimer.
56aad01611Sagc  * 2. Redistributions in binary form must reproduce the above copyright
57aad01611Sagc  *    notice, this list of conditions and the following disclaimer in the
58aad01611Sagc  *    documentation and/or other materials provided with the distribution.
59b7abba77Ssoda  * 3. All advertising materials mentioning features or use of this software
60b7abba77Ssoda  *    must display the following acknowledgement:
61b7abba77Ssoda  *	This product includes software developed by the University of
62b7abba77Ssoda  *	California, Berkeley and its contributors.
63b7abba77Ssoda  * 4. Neither the name of the University nor the names of its contributors
64b7abba77Ssoda  *    may be used to endorse or promote products derived from this software
65b7abba77Ssoda  *    without specific prior written permission.
66b7abba77Ssoda  *
67b7abba77Ssoda  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
68b7abba77Ssoda  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
69b7abba77Ssoda  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
70b7abba77Ssoda  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
71b7abba77Ssoda  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
72b7abba77Ssoda  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
73b7abba77Ssoda  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
74b7abba77Ssoda  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
75b7abba77Ssoda  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
76b7abba77Ssoda  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
77b7abba77Ssoda  * SUCH DAMAGE.
78b7abba77Ssoda  *
79b7abba77Ssoda  *	@(#)pccons.c	5.11 (Berkeley) 5/21/91
80b7abba77Ssoda  */
81b7abba77Ssoda 
82a4183603Slukem #include <sys/cdefs.h>
83*5ab06420Sthorpej __KERNEL_RCSID(0, "$NetBSD: opms.c,v 1.26 2021/09/26 16:36:18 thorpej Exp $");
84a4183603Slukem 
85b7abba77Ssoda #include <sys/param.h>
86b7abba77Ssoda #include <sys/systm.h>
87b7abba77Ssoda #include <sys/vnode.h>
88b7abba77Ssoda #include <sys/poll.h>
89b7abba77Ssoda #include <sys/tty.h>
90b7abba77Ssoda #include <sys/device.h>
9180373b7eSchs #include <sys/proc.h>
9277a6b82bSgehenna #include <sys/conf.h>
93b7abba77Ssoda 
94cf10107dSdyoung #include <sys/bus.h>
95b7abba77Ssoda #include <machine/kbdreg.h>
96b7abba77Ssoda #include <machine/mouse.h>
97b7abba77Ssoda 
98b7abba77Ssoda #include <arc/dev/pcconsvar.h>
99b7abba77Ssoda #include <arc/dev/opmsvar.h>
100b7abba77Ssoda 
101c234c43aStsutsui #include "ioconf.h"
102c234c43aStsutsui 
103b7abba77Ssoda #define	PMSUNIT(dev)	(minor(dev))
104b7abba77Ssoda 
105b7abba77Ssoda /* status bits */
106b7abba77Ssoda #define	PMS_OBUF_FULL	0x01
107b7abba77Ssoda #define	PMS_IBUF_FULL	0x02
108b7abba77Ssoda 
109b7abba77Ssoda /* controller commands */
110b7abba77Ssoda #define	PMS_INT_ENABLE	0x47	/* enable controller interrupts */
111b7abba77Ssoda #define	PMS_INT_DISABLE	0x65	/* disable controller interrupts */
112b7abba77Ssoda #define	PMS_AUX_ENABLE	0xa7	/* enable auxiliary port */
113b7abba77Ssoda #define	PMS_AUX_DISABLE	0xa8	/* disable auxiliary port */
114b7abba77Ssoda #define	PMS_MAGIC_1	0xa9	/* XXX */
115b7abba77Ssoda 
116b7abba77Ssoda #define	PMS_8042_CMD	0x65
117b7abba77Ssoda 
118b7abba77Ssoda /* mouse commands */
119b7abba77Ssoda #define	PMS_SET_SCALE11	0xe6	/* set scaling 1:1 */
120b7abba77Ssoda #define	PMS_SET_SCALE21 0xe7	/* set scaling 2:1 */
121b7abba77Ssoda #define	PMS_SET_RES	0xe8	/* set resolution */
122b7abba77Ssoda #define	PMS_GET_SCALE	0xe9	/* get scaling factor */
123b7abba77Ssoda #define	PMS_SET_STREAM	0xea	/* set streaming mode */
124b7abba77Ssoda #define	PMS_SET_SAMPLE	0xf3	/* set sampling rate */
125b7abba77Ssoda #define	PMS_DEV_ENABLE	0xf4	/* mouse on */
126b7abba77Ssoda #define	PMS_DEV_DISABLE	0xf5	/* mouse off */
127b7abba77Ssoda #define	PMS_RESET	0xff	/* reset */
128b7abba77Ssoda 
129b7abba77Ssoda #define	PMS_CHUNK	128	/* chunk size for read */
130b7abba77Ssoda #define	PMS_BSIZE	1020	/* buffer size */
131b7abba77Ssoda 
132b7abba77Ssoda #define	FLUSHQ(q) { if((q)->c_cc) ndflush(q, (q)->c_cc); }
133b7abba77Ssoda 
13477a6b82bSgehenna dev_type_open(opmsopen);
13577a6b82bSgehenna dev_type_close(opmsclose);
13677a6b82bSgehenna dev_type_read(opmsread);
13777a6b82bSgehenna dev_type_ioctl(opmsioctl);
13877a6b82bSgehenna dev_type_poll(opmspoll);
139a8dbe271Sjdolecek dev_type_kqfilter(opmskqfilter);
14077a6b82bSgehenna 
14177a6b82bSgehenna const struct cdevsw opms_cdevsw = {
142a68f9396Sdholland 	.d_open = opmsopen,
143a68f9396Sdholland 	.d_close = opmsclose,
144a68f9396Sdholland 	.d_read = opmsread,
145a68f9396Sdholland 	.d_write = nowrite,
146a68f9396Sdholland 	.d_ioctl = opmsioctl,
147a68f9396Sdholland 	.d_stop = nostop,
148a68f9396Sdholland 	.d_tty = notty,
149a68f9396Sdholland 	.d_poll = opmspoll,
150a68f9396Sdholland 	.d_mmap = nommap,
151a68f9396Sdholland 	.d_kqfilter = opmskqfilter,
152f9228f42Sdholland 	.d_discard = nodiscard,
153a68f9396Sdholland 	.d_flag = 0
15477a6b82bSgehenna };
15577a6b82bSgehenna 
1565f1c88d7Sperry static inline void pms_dev_cmd(uint8_t);
1575f1c88d7Sperry static inline void pms_aux_cmd(uint8_t);
1585f1c88d7Sperry static inline void pms_pit_cmd(uint8_t);
159b7abba77Ssoda 
1605f1c88d7Sperry static inline void
pms_dev_cmd(uint8_t value)1617fe2a5a0Stsutsui pms_dev_cmd(uint8_t value)
162b7abba77Ssoda {
1637fe2a5a0Stsutsui 
164b7abba77Ssoda 	kbd_flush_input();
165b7abba77Ssoda 	kbd_cmd_write_1(0xd4);
166b7abba77Ssoda 	kbd_flush_input();
167b7abba77Ssoda 	kbd_data_write_1(value);
168b7abba77Ssoda }
169b7abba77Ssoda 
1705f1c88d7Sperry static inline void
pms_aux_cmd(uint8_t value)1717fe2a5a0Stsutsui pms_aux_cmd(uint8_t value)
172b7abba77Ssoda {
1737fe2a5a0Stsutsui 
174b7abba77Ssoda 	kbd_flush_input();
175b7abba77Ssoda 	kbd_cmd_write_1(value);
176b7abba77Ssoda }
177b7abba77Ssoda 
1785f1c88d7Sperry static inline void
pms_pit_cmd(uint8_t value)1797fe2a5a0Stsutsui pms_pit_cmd(uint8_t value)
180b7abba77Ssoda {
1817fe2a5a0Stsutsui 
182b7abba77Ssoda 	kbd_flush_input();
183b7abba77Ssoda 	kbd_cmd_write_1(0x60);
184b7abba77Ssoda 	kbd_flush_input();
185b7abba77Ssoda 	kbd_data_write_1(value);
186b7abba77Ssoda }
187b7abba77Ssoda 
opms_common_match(bus_space_tag_t kbd_iot,struct pccons_config * config)1887fe2a5a0Stsutsui int opms_common_match(bus_space_tag_t kbd_iot, struct pccons_config *config)
189b7abba77Ssoda {
1907fe2a5a0Stsutsui 	uint8_t x;
191b7abba77Ssoda 
192b7abba77Ssoda 	kbd_context_init(kbd_iot, config);
193b7abba77Ssoda 
194b7abba77Ssoda 	pms_dev_cmd(KBC_RESET);
195b7abba77Ssoda 	pms_aux_cmd(PMS_MAGIC_1);
196b7abba77Ssoda 	delay(10000);
197b7abba77Ssoda 	x = kbd_data_read_1();
198b7abba77Ssoda 	pms_pit_cmd(PMS_INT_DISABLE);
199b7abba77Ssoda 	if (x & 0x04)
200b7abba77Ssoda 		return 0;
201b7abba77Ssoda 
202b7abba77Ssoda 	return 1;
203b7abba77Ssoda }
204b7abba77Ssoda 
205b7abba77Ssoda void
opms_common_attach(struct opms_softc * sc,bus_space_tag_t opms_iot,struct pccons_config * config)2067fe2a5a0Stsutsui opms_common_attach(struct opms_softc *sc, bus_space_tag_t opms_iot,
2077fe2a5a0Stsutsui     struct pccons_config *config)
208b7abba77Ssoda {
2097fe2a5a0Stsutsui 
210b7abba77Ssoda 	kbd_context_init(opms_iot, config);
211c6186facSrmind 	selinit(&sc->sc_rsel);
212b7abba77Ssoda 
213b7abba77Ssoda 	/* Other initialization was done by opmsprobe. */
214b7abba77Ssoda 	sc->sc_state = 0;
215b7abba77Ssoda }
216b7abba77Ssoda 
217b7abba77Ssoda int
opmsopen(dev_t dev,int flag,int mode,struct lwp * l)21895e1ffb1Schristos opmsopen(dev_t dev, int flag, int mode, struct lwp *l)
219b7abba77Ssoda {
220b7abba77Ssoda 	struct opms_softc *sc;
221b7abba77Ssoda 
222fa11f9bfScegger 	sc = device_lookup_private(&opms_cd, PMSUNIT(dev));
223b7abba77Ssoda 	if (!sc)
224b7abba77Ssoda 		return ENXIO;
225b7abba77Ssoda 
226b7abba77Ssoda 	if (sc->sc_state & PMS_OPEN)
227b7abba77Ssoda 		return EBUSY;
228b7abba77Ssoda 
229b7abba77Ssoda 	if (clalloc(&sc->sc_q, PMS_BSIZE, 0) == -1)
230b7abba77Ssoda 		return ENOMEM;
231b7abba77Ssoda 
232b7abba77Ssoda 	sc->sc_state |= PMS_OPEN;
233b7abba77Ssoda 	sc->sc_status = 0;
234b7abba77Ssoda 	sc->sc_x = sc->sc_y = 0;
235b7abba77Ssoda 
236b7abba77Ssoda 	/* Enable interrupts. */
237b7abba77Ssoda 	pms_dev_cmd(PMS_DEV_ENABLE);
238b7abba77Ssoda 	pms_aux_cmd(PMS_AUX_ENABLE);
239b7abba77Ssoda 	pms_dev_cmd(PMS_SET_RES);
240b7abba77Ssoda 	pms_dev_cmd(3);		/* 8 counts/mm */
241b7abba77Ssoda 	pms_dev_cmd(PMS_SET_SCALE21);
242b7abba77Ssoda #if 0
243b7abba77Ssoda 	pms_dev_cmd(PMS_SET_SAMPLE);
244b7abba77Ssoda 	pms_dev_cmd(100);	/* 100 samples/sec */
245b7abba77Ssoda 	pms_dev_cmd(PMS_SET_STREAM);
246b7abba77Ssoda #endif
247b7abba77Ssoda 	pms_pit_cmd(PMS_INT_ENABLE);
248b7abba77Ssoda 
249b7abba77Ssoda 	return 0;
250b7abba77Ssoda }
251b7abba77Ssoda 
252b7abba77Ssoda int
opmsclose(dev_t dev,int flag,int mode,struct lwp * l)25395e1ffb1Schristos opmsclose(dev_t dev, int flag, int mode, struct lwp *l)
254b7abba77Ssoda {
255fa11f9bfScegger 	struct opms_softc *sc = device_lookup_private(&opms_cd, PMSUNIT(dev));
256b7abba77Ssoda 
257b7abba77Ssoda 	/* Disable interrupts. */
258b7abba77Ssoda 	pms_dev_cmd(PMS_DEV_DISABLE);
259b7abba77Ssoda 	pms_pit_cmd(PMS_INT_DISABLE);
260b7abba77Ssoda 	pms_aux_cmd(PMS_AUX_DISABLE);
261b7abba77Ssoda 
262b7abba77Ssoda 	sc->sc_state &= ~PMS_OPEN;
263b7abba77Ssoda 
264b7abba77Ssoda 	clfree(&sc->sc_q);
265b7abba77Ssoda 
266b7abba77Ssoda 	return 0;
267b7abba77Ssoda }
268b7abba77Ssoda 
269b7abba77Ssoda int
opmsread(dev_t dev,struct uio * uio,int flag)2706196dae1Smatt opmsread(dev_t dev, struct uio *uio, int flag)
271b7abba77Ssoda {
272fa11f9bfScegger 	struct opms_softc *sc = device_lookup_private(&opms_cd, PMSUNIT(dev));
273b7abba77Ssoda 	int s;
274b7abba77Ssoda 	int error = 0;
275b7abba77Ssoda 	size_t length;
276b7abba77Ssoda 	u_char buffer[PMS_CHUNK];
277b7abba77Ssoda 
278456dff6cSwiz 	/* Block until mouse activity occurred. */
279b7abba77Ssoda 
280b7abba77Ssoda 	s = spltty();
281b7abba77Ssoda 	while (sc->sc_q.c_cc == 0) {
282b7abba77Ssoda 		if (flag & IO_NDELAY) {
283b7abba77Ssoda 			splx(s);
284b7abba77Ssoda 			return EWOULDBLOCK;
285b7abba77Ssoda 		}
286b7abba77Ssoda 		sc->sc_state |= PMS_ASLP;
28753524e44Schristos 		error = tsleep((void *)sc, PZERO | PCATCH, "pmsrea", 0);
288b7abba77Ssoda 		if (error) {
289b7abba77Ssoda 			sc->sc_state &= ~PMS_ASLP;
290b7abba77Ssoda 			splx(s);
291b7abba77Ssoda 			return error;
292b7abba77Ssoda 		}
293b7abba77Ssoda 	}
294b7abba77Ssoda 	splx(s);
295b7abba77Ssoda 
296b7abba77Ssoda 	/* Transfer as many chunks as possible. */
297b7abba77Ssoda 
298b7abba77Ssoda 	while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) {
299d1579b2dSriastradh 		length = uimin(sc->sc_q.c_cc, uio->uio_resid);
300b7abba77Ssoda 		if (length > sizeof(buffer))
301b7abba77Ssoda 			length = sizeof(buffer);
302b7abba77Ssoda 
303b7abba77Ssoda 		/* Remove a small chunk from the input queue. */
304b7abba77Ssoda 		(void) q_to_b(&sc->sc_q, buffer, length);
305b7abba77Ssoda 
306b7abba77Ssoda 		/* Copy the data to the user process. */
307b7abba77Ssoda 		error = uiomove(buffer, length, uio);
308b7abba77Ssoda 		if (error)
309b7abba77Ssoda 			break;
310b7abba77Ssoda 	}
311b7abba77Ssoda 
312b7abba77Ssoda 	return error;
313b7abba77Ssoda }
314b7abba77Ssoda 
315b7abba77Ssoda int
opmsioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)31653524e44Schristos opmsioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
317b7abba77Ssoda {
318fa11f9bfScegger 	struct opms_softc *sc = device_lookup_private(&opms_cd, PMSUNIT(dev));
319b7abba77Ssoda 	struct mouseinfo info;
320b7abba77Ssoda 	int s;
321b7abba77Ssoda 	int error;
322b7abba77Ssoda 
323b7abba77Ssoda 	switch (cmd) {
324b7abba77Ssoda 	case MOUSEIOCREAD:
325b7abba77Ssoda 		s = spltty();
326b7abba77Ssoda 
327b7abba77Ssoda 		info.status = sc->sc_status;
328b7abba77Ssoda 		if (sc->sc_x || sc->sc_y)
329b7abba77Ssoda 			info.status |= MOVEMENT;
330b7abba77Ssoda 
331b7abba77Ssoda 		if (sc->sc_x > 127)
332b7abba77Ssoda 			info.xmotion = 127;
333b7abba77Ssoda 		else if (sc->sc_x < -127)
334b7abba77Ssoda 			/* Bounding at -127 avoids a bug in XFree86. */
335b7abba77Ssoda 			info.xmotion = -127;
336b7abba77Ssoda 		else
337b7abba77Ssoda 			info.xmotion = sc->sc_x;
338b7abba77Ssoda 
339b7abba77Ssoda 		if (sc->sc_y > 127)
340b7abba77Ssoda 			info.ymotion = 127;
341b7abba77Ssoda 		else if (sc->sc_y < -127)
342b7abba77Ssoda 			info.ymotion = -127;
343b7abba77Ssoda 		else
344b7abba77Ssoda 			info.ymotion = sc->sc_y;
345b7abba77Ssoda 
346b7abba77Ssoda 		/* Reset historical information. */
347b7abba77Ssoda 		sc->sc_x = sc->sc_y = 0;
348b7abba77Ssoda 		sc->sc_status &= ~BUTCHNGMASK;
349b7abba77Ssoda 		ndflush(&sc->sc_q, sc->sc_q.c_cc);
350b7abba77Ssoda 
351b7abba77Ssoda 		splx(s);
352b7abba77Ssoda 		error = copyout(&info, addr, sizeof(struct mouseinfo));
353b7abba77Ssoda 		break;
354b7abba77Ssoda 	default:
355b7abba77Ssoda 		error = EINVAL;
356b7abba77Ssoda 		break;
357b7abba77Ssoda 	}
358b7abba77Ssoda 
359b7abba77Ssoda 	return error;
360b7abba77Ssoda }
361b7abba77Ssoda 
362b7abba77Ssoda /* Masks for the first byte of a packet */
363b7abba77Ssoda #define PS2LBUTMASK 0x01
364b7abba77Ssoda #define PS2RBUTMASK 0x02
365b7abba77Ssoda #define PS2MBUTMASK 0x04
366b7abba77Ssoda 
367b7abba77Ssoda int
opmsintr(void * arg)3687fe2a5a0Stsutsui opmsintr(void *arg)
369b7abba77Ssoda {
370b7abba77Ssoda 	struct opms_softc *sc = arg;
371b7abba77Ssoda 	static int state = 0;
372b7abba77Ssoda 	static u_char buttons;
373b7abba77Ssoda 	u_char changed;
374b7abba77Ssoda 	static char dx, dy;
375b7abba77Ssoda 	u_char buffer[5];
376b7abba77Ssoda 
377b7abba77Ssoda 	if ((sc->sc_state & PMS_OPEN) == 0) {
378b7abba77Ssoda 		/* Interrupts are not expected.  Discard the byte. */
379b7abba77Ssoda 		kbd_flush_input();
380b7abba77Ssoda 		return 0;
381b7abba77Ssoda 	}
382b7abba77Ssoda 
383b7abba77Ssoda 	switch (state) {
384b7abba77Ssoda 
385b7abba77Ssoda 	case 0:
386b7abba77Ssoda 		buttons = kbd_data_read_1();
387b7abba77Ssoda 		if ((buttons & 0xc0) == 0)
388b7abba77Ssoda 			++state;
389b7abba77Ssoda 		break;
390b7abba77Ssoda 
391b7abba77Ssoda 	case 1:
392b7abba77Ssoda 		dx = kbd_data_read_1();
393b7abba77Ssoda 		/* Bounding at -127 avoids a bug in XFree86. */
394b7abba77Ssoda 		dx = (dx == -128) ? -127 : dx;
395b7abba77Ssoda 		++state;
396b7abba77Ssoda 		break;
397b7abba77Ssoda 
398b7abba77Ssoda 	case 2:
399b7abba77Ssoda 		dy = kbd_data_read_1();
400b7abba77Ssoda 		dy = (dy == -128) ? -127 : dy;
401b7abba77Ssoda 		state = 0;
402b7abba77Ssoda 
403b7abba77Ssoda 		buttons = ((buttons & PS2LBUTMASK) << 2) |
404b7abba77Ssoda 		    ((buttons & (PS2RBUTMASK | PS2MBUTMASK)) >> 1);
405b7abba77Ssoda 		changed = ((buttons ^ sc->sc_status) & BUTSTATMASK) << 3;
4067fe2a5a0Stsutsui 		sc->sc_status = buttons | (sc->sc_status & ~BUTSTATMASK) |
4077fe2a5a0Stsutsui 		    changed;
408b7abba77Ssoda 
409b7abba77Ssoda 		if (dx || dy || changed) {
410b7abba77Ssoda 			/* Update accumulated movements. */
411b7abba77Ssoda 			sc->sc_x += dx;
412b7abba77Ssoda 			sc->sc_y += dy;
413b7abba77Ssoda 
414b7abba77Ssoda 			/* Add this event to the queue. */
415b7abba77Ssoda 			buffer[0] = 0x80 | (buttons & BUTSTATMASK);
416b7abba77Ssoda 			if(dx < 0)
417b7abba77Ssoda 				buffer[0] |= 0x10;
418b7abba77Ssoda 			buffer[1] = dx & 0x7f;
419b7abba77Ssoda 			if(dy < 0)
420b7abba77Ssoda 				buffer[0] |= 0x20;
421b7abba77Ssoda 			buffer[2] = dy & 0x7f;
422b7abba77Ssoda 			buffer[3] = buffer[4] = 0;
423b7abba77Ssoda 			(void) b_to_q(buffer, sizeof buffer, &sc->sc_q);
424b7abba77Ssoda 
425b7abba77Ssoda 			if (sc->sc_state & PMS_ASLP) {
426b7abba77Ssoda 				sc->sc_state &= ~PMS_ASLP;
42753524e44Schristos 				wakeup((void *)sc);
428b7abba77Ssoda 			}
429c6186facSrmind 			selnotify(&sc->sc_rsel, 0, 0);
430b7abba77Ssoda 		}
431b7abba77Ssoda 
432b7abba77Ssoda 		break;
433b7abba77Ssoda 	}
434b7abba77Ssoda 	return -1;
435b7abba77Ssoda }
436b7abba77Ssoda 
437b7abba77Ssoda int
opmspoll(dev_t dev,int events,struct lwp * l)43895e1ffb1Schristos opmspoll(dev_t dev, int events, struct lwp *l)
439b7abba77Ssoda {
440fa11f9bfScegger 	struct opms_softc *sc = device_lookup_private(&opms_cd, PMSUNIT(dev));
441b7abba77Ssoda 	int revents = 0;
442b7abba77Ssoda 	int s = spltty();
443b7abba77Ssoda 
444b7abba77Ssoda 	if (events & (POLLIN | POLLRDNORM)) {
445b7abba77Ssoda 		if (sc->sc_q.c_cc > 0)
446b7abba77Ssoda 			revents |= events & (POLLIN | POLLRDNORM);
447b7abba77Ssoda 		else
44895e1ffb1Schristos 			selrecord(l, &sc->sc_rsel);
449b7abba77Ssoda 	}
450b7abba77Ssoda 
451b7abba77Ssoda 	splx(s);
4527fe2a5a0Stsutsui 	return revents;
453b7abba77Ssoda }
454e0cc03a0Sjdolecek 
455e0cc03a0Sjdolecek static void
filt_opmsrdetach(struct knote * kn)456e0cc03a0Sjdolecek filt_opmsrdetach(struct knote *kn)
457e0cc03a0Sjdolecek {
458e0cc03a0Sjdolecek 	struct opms_softc *sc = kn->kn_hook;
459e0cc03a0Sjdolecek 	int s;
460e0cc03a0Sjdolecek 
461e0cc03a0Sjdolecek 	s = spltty();
46266b33a40Sthorpej 	selremove_knote(&sc->sc_rsel, kn);
463e0cc03a0Sjdolecek 	splx(s);
464e0cc03a0Sjdolecek }
465e0cc03a0Sjdolecek 
466e0cc03a0Sjdolecek static int
filt_opmsread(struct knote * kn,long hint)467e0cc03a0Sjdolecek filt_opmsread(struct knote *kn, long hint)
468e0cc03a0Sjdolecek {
469e0cc03a0Sjdolecek 	struct opms_softc *sc = kn->kn_hook;
470e0cc03a0Sjdolecek 
471e0cc03a0Sjdolecek 	kn->kn_data = sc->sc_q.c_cc;
4727fe2a5a0Stsutsui 	return kn->kn_data > 0;
473e0cc03a0Sjdolecek }
474e0cc03a0Sjdolecek 
47518b796d4Smaya static const struct filterops opmsread_filtops = {
47612ae65d9Sthorpej 	.f_flags = FILTEROP_ISFD,
47718b796d4Smaya 	.f_attach = NULL,
47818b796d4Smaya 	.f_detach = filt_opmsrdetach,
47918b796d4Smaya 	.f_event = filt_opmsread,
48018b796d4Smaya };
481e0cc03a0Sjdolecek 
482e0cc03a0Sjdolecek int
opmskqfilter(dev_t dev,struct knote * kn)483e0cc03a0Sjdolecek opmskqfilter(dev_t dev, struct knote *kn)
484e0cc03a0Sjdolecek {
485fa11f9bfScegger 	struct opms_softc *sc = device_lookup_private(&opms_cd, PMSUNIT(dev));
486e0cc03a0Sjdolecek 	int s;
487e0cc03a0Sjdolecek 
488e0cc03a0Sjdolecek 	switch (kn->kn_filter) {
489e0cc03a0Sjdolecek 	case EVFILT_READ:
490e0cc03a0Sjdolecek 		kn->kn_fop = &opmsread_filtops;
491e0cc03a0Sjdolecek 		break;
492e0cc03a0Sjdolecek 
493e0cc03a0Sjdolecek 	default:
494*5ab06420Sthorpej 		return EINVAL;
495e0cc03a0Sjdolecek 	}
496e0cc03a0Sjdolecek 
497e0cc03a0Sjdolecek 	kn->kn_hook = sc;
498e0cc03a0Sjdolecek 
499e0cc03a0Sjdolecek 	s = spltty();
50066b33a40Sthorpej 	selrecord_knote(&sc->sc_rsel, kn);
501e0cc03a0Sjdolecek 	splx(s);
502e0cc03a0Sjdolecek 
5037fe2a5a0Stsutsui 	return 0;
504e0cc03a0Sjdolecek }
505