xref: /illumos-gate/usr/src/uts/common/io/vuidmice/vuidm4p.c (revision 3dbfc80346c4b24f1337e411111b9521c729cf9e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * 4-Byte Mouse Protocol
30  */
31 
32 #include <sys/param.h>
33 #include <sys/stream.h>
34 #include <sys/strsun.h>
35 #include <sys/vuid_event.h>
36 #include <sys/vuidmice.h>
37 
38 #ifdef	VUIDM4P_DEBUG
39 #define	VBUF_SIZE	511
40 static unsigned char vuidm4p_buf[VBUF_SIZE+1];
41 static int vuidm4p_ptr = 0;
42 #endif
43 
44 #define	VUID_BUT(b)		BUT((b*2)+1)
45 
46 /*
47  * VUID_BUT(0)	BUT(1)		LEFT  BUTTON
48  * VUID_BUT(1)	BUT(3)		RIGHT BUTTON
49  */
50 
51 #define	MOUSE_NUMBUTTONS	3		/* Number of buttons	*/
52 #define	MOUSE_BUTTON_M		(uchar_t)(0x40)	/* Middle button */
53 #define	MOUSE_BUTTON_L		(uchar_t)(0x20)	/* Left   button */
54 #define	MOUSE_BUTTON_R		(uchar_t)(0x10)	/* Right  button */
55 
56 #define	MOUSE_START_CODE	(uchar_t)(0x40)	/* Start code in char	*/
57 
58 #define	MOUSE_START		0		/* Beginning of packet	*/
59 #define	MOUSE_BUTTON		1		/* Got button status	*/
60 #define	MOUSE_DELTA_X		2		/* got delta X		*/
61 #define	MOUSE_DELTA_Y		3		/* got delta Y		*/
62 
63 extern void VUID_PUTNEXT(queue_t *const, uchar_t, uchar_t, uchar_t, int);
64 
65 int
66 VUID_OPEN(queue_t *const qp)
67 {
68 	/*
69 	 * The current kdmconfig tables imply that this module can be used
70 	 * for both 2- and 3- button mice, so based on that evidence we
71 	 * can't assume a constant.  It should be possible to autodetect
72 	 * based on the mouse's startup behavior - "M" means 2 buttons,
73 	 * "M3" means 3 buttons - but that's for another day.
74 	 */
75 	STATEP->nbuttons = 0;	/* Don't know. */
76 
77 	return (0);
78 }
79 
80 static void
81 vuidm4p_sendButtonEvent(queue_t *const qp)
82 {
83 	int b;
84 
85 	/* for the LEFT and RIGHT button, see if it has changed */
86 	for (b = 0; b < 2; b++) {
87 		uchar_t mask = 0x20 >> b;
88 
89 		if ((STATEP->buttons & mask) != (STATEP->oldbuttons & mask))
90 			VUID_PUTNEXT(qp, VUID_BUT(b), FE_PAIR_NONE, 0,
91 			    ((STATEP->buttons & mask) ? 1 : 0));
92 	}
93 }
94 
95 void
96 vuidm4p(queue_t *const qp, mblk_t *mp)
97 {
98 	int r, code;
99 	unsigned char *bufp;
100 
101 	bufp = mp->b_rptr;
102 	r = MBLKL(mp);
103 
104 	for (r--; r >= 0; r--) {
105 		code = *bufp++;
106 
107 #ifdef	VUIDM4P_DEBUG
108 		vuidm4p_buf[vuidm4p_ptr] = code;
109 		vuidm4p_ptr = ((vuidm4p_ptr + 1) & VBUF_SIZE);
110 #endif
111 
112 		if (code & MOUSE_START_CODE) {
113 			/*
114 			 * sync it here
115 			 */
116 			STATEP->state = MOUSE_START;
117 		}
118 
119 		switch (STATEP->state) {
120 			/*
121 			 * Start state. We stay here if the start code is not
122 			 * received thus forcing us back into sync. When we
123 			 * get a start code the	button mask comes with it
124 			 * forcing us to the next state.
125 			 */
126 		default:
127 		case MOUSE_START:
128 			/* look for sync */
129 			if ((code & MOUSE_START_CODE) == 0)
130 				break;
131 
132 			STATEP->deltax = STATEP->deltay = 0;
133 			STATEP->buttons = 0;
134 
135 			/* Get the new state for the LEFT & RIGHT Button */
136 			STATEP->buttons |=
137 			    (code & (MOUSE_BUTTON_L | MOUSE_BUTTON_R));
138 
139 			/*
140 			 * bits 0 & 1 are bits 6 & 7 of X value
141 			 * (Sign extend them with the cast.)
142 			 */
143 			STATEP->deltax = (signed char)((code & 0x03) << 6);
144 
145 			/*
146 			 * bits 2 & 3 are bits 6 & 7 of Y value
147 			 * (Sign extend them with the cast.)
148 			 */
149 			STATEP->deltay = (signed char)((code & 0x0c) << 4);
150 			STATEP->state = MOUSE_BUTTON;
151 				/* go to the next state */
152 			break;
153 
154 		case MOUSE_BUTTON:
155 			/*
156 			 * We receive the remaining 6 bits of delta x,
157 			 * forcing us to the next state. We just piece the
158 			 * value of delta x together.
159 			 */
160 			STATEP->deltax |= code & 0x3f;
161 			STATEP->state = MOUSE_DELTA_X;
162 			break;
163 
164 			/*
165 			 * The last part of delta Y, and the packet *may be*
166 			 * complete
167 			 */
168 		case MOUSE_DELTA_X:
169 			STATEP->deltay |= code & 0x3f;
170 			STATEP->state = MOUSE_DELTA_Y;
171 
172 			STATEP->buttons |=
173 			    (STATEP->oldbuttons & MOUSE_BUTTON_M);
174 
175 			/*
176 			 * If we can peek at the next two mouse characters,
177 			 * and  neither  of  them  is  the start of the next
178 			 * packet, don't use this packet.
179 			 */
180 			if (r > 1 && !(bufp[0] & MOUSE_START_CODE) &&
181 			    !(bufp[1] & MOUSE_START_CODE)) {
182 				STATEP->state = MOUSE_START;
183 				break;
184 			}
185 
186 			if (STATEP->buttons != STATEP->oldbuttons) {
187 				vuidm4p_sendButtonEvent(qp);
188 			}
189 
190 			/*
191 			 * remember state
192 			 */
193 			STATEP->oldbuttons = STATEP->buttons;
194 
195 			/*
196 			 * generate motion Events for delta_x
197 			 */
198 			if (STATEP->deltax)
199 				VUID_PUTNEXT(qp,
200 				    (uchar_t)LOC_X_DELTA, FE_PAIR_ABSOLUTE,
201 				    (uchar_t)LOC_X_ABSOLUTE, STATEP->deltax);
202 			/*
203 			 * Reverse the Sign for DELTA_Y
204 			 */
205 			if (STATEP->deltay)
206 				VUID_PUTNEXT(qp,
207 				    (uchar_t)LOC_Y_DELTA, FE_PAIR_ABSOLUTE,
208 				    (uchar_t)LOC_Y_ABSOLUTE, -STATEP->deltay);
209 
210 			STATEP->deltax = STATEP->deltay = 0;
211 
212 			/* allow us to keep looking for an optional 4th byte */
213 			break;
214 
215 		case MOUSE_DELTA_Y:
216 			/*
217 			 * We've seen delta Y.  If we do NOT have the sync
218 			 * bit set, this indicates the middle button's status.
219 			 */
220 			STATEP->state = MOUSE_START;
221 
222 			/*
223 			 * if we're here, the fourth byte is indeed present
224 			 * to indicate something with the middle button.
225 			 */
226 
227 			/*
228 			 * If we can peek at the next mouse character, and
229 			 * its not the start of the next packet, don't use
230 			 * this packet.
231 			 */
232 			if (r > 0 && !(bufp[0] & MOUSE_START_CODE))
233 				break;
234 
235 			/*
236 			 * Check if the byte is a valid middle button state.
237 			 * It must either be 0x00 or 0x20 only.
238 			 */
239 
240 			/*
241 			 * Get the new state for the MIDDLE Button
242 			 * Left button set in 4th byte indicates that the
243 			 * middle button is pressed, cleared means it
244 			 * has been released.
245 			 */
246 			if (code == MOUSE_BUTTON_L)
247 				STATEP->buttons |= MOUSE_BUTTON_M;
248 			else if (code == 0)
249 				STATEP->buttons &= ~MOUSE_BUTTON_M;
250 			else {
251 				/*
252 				 * Invalid data in the 4th byte of the packet.
253 				 * Skip this byte.
254 				 */
255 #ifdef VUIDM4P_DEBUG
256 				vuidm4p_break();
257 #endif
258 				break;
259 			}
260 
261 			/*
262 			 * generate an Event with the middle button's status
263 			 */
264 			if (STATEP->oldbuttons != STATEP->buttons) {
265 				VUID_PUTNEXT(qp,
266 				    (uchar_t)MS_MIDDLE, FE_PAIR_NONE, 0,
267 				    ((STATEP->buttons & MOUSE_BUTTON_M) ?
268 				    1 : 0));
269 			}
270 
271 			/*
272 			 * remember state
273 			 */
274 			STATEP->oldbuttons = STATEP->buttons;
275 			break;
276 		}
277 	}
278 	freemsg(mp);
279 }
280 
281 
282 #ifdef	VUIDM4P_DEBUG
283 int
284 vuidm4p_break()
285 {
286 	char buf[VBUF_SIZE+1];
287 	int i;
288 
289 	for (i = 0; i <= VBUF_SIZE; i++) {
290 		buf[i] - vuidm4p_buf[vuidm4p_ptr];
291 		vuidm4p_ptr = ((vuidm4p_ptr + 1) & VBUF_SIZE);
292 	}
293 
294 	for (i = 0; i <= VBUF_SIZE; i++) {
295 		vuidm4p_buf[i] = buf[i];
296 	}
297 }
298 #endif
299