xref: /onnv-gate/usr/src/uts/common/io/usb/clients/usbinput/usbwcm/usbwcm.c (revision 11489:29bcdf3d8d8c)
1*11489SPengcheng.Chen@Sun.COM /*
2*11489SPengcheng.Chen@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3*11489SPengcheng.Chen@Sun.COM  * Use is subject to license terms.
4*11489SPengcheng.Chen@Sun.COM  */
5*11489SPengcheng.Chen@Sun.COM 
6*11489SPengcheng.Chen@Sun.COM /*
7*11489SPengcheng.Chen@Sun.COM  * Copyright (c) 2007, 2008 Bartosz Fabianowski <freebsd@chillt.de>
8*11489SPengcheng.Chen@Sun.COM  * All rights reserved.
9*11489SPengcheng.Chen@Sun.COM  *
10*11489SPengcheng.Chen@Sun.COM  * Financed by the "Irish Research Council for Science, Engineering and
11*11489SPengcheng.Chen@Sun.COM  * Technology: funded by the National Development Plan"
12*11489SPengcheng.Chen@Sun.COM  *
13*11489SPengcheng.Chen@Sun.COM  * Redistribution and use in source and binary forms, with or without
14*11489SPengcheng.Chen@Sun.COM  * modification, are permitted provided that the following conditions
15*11489SPengcheng.Chen@Sun.COM  * are met:
16*11489SPengcheng.Chen@Sun.COM  * 1. Redistributions of source code must retain the above copyright
17*11489SPengcheng.Chen@Sun.COM  *    notice, this list of conditions, and the following disclaimer.
18*11489SPengcheng.Chen@Sun.COM  * 2. Redistributions in binary form must reproduce the above copyright
19*11489SPengcheng.Chen@Sun.COM  *    notice, this list of conditions and the following disclaimer in the
20*11489SPengcheng.Chen@Sun.COM  *    documentation and/or other materials provided with the distribution.
21*11489SPengcheng.Chen@Sun.COM  *
22*11489SPengcheng.Chen@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23*11489SPengcheng.Chen@Sun.COM  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24*11489SPengcheng.Chen@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25*11489SPengcheng.Chen@Sun.COM  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
26*11489SPengcheng.Chen@Sun.COM  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27*11489SPengcheng.Chen@Sun.COM  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28*11489SPengcheng.Chen@Sun.COM  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29*11489SPengcheng.Chen@Sun.COM  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*11489SPengcheng.Chen@Sun.COM  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31*11489SPengcheng.Chen@Sun.COM  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*11489SPengcheng.Chen@Sun.COM  * SUCH DAMAGE.
33*11489SPengcheng.Chen@Sun.COM  */
34*11489SPengcheng.Chen@Sun.COM 
35*11489SPengcheng.Chen@Sun.COM /*
36*11489SPengcheng.Chen@Sun.COM  * Copyright (c) 1998 The NetBSD Foundation, Inc.
37*11489SPengcheng.Chen@Sun.COM  * All rights reserved.
38*11489SPengcheng.Chen@Sun.COM  *
39*11489SPengcheng.Chen@Sun.COM  * This code is derived from software contributed to The NetBSD Foundation
40*11489SPengcheng.Chen@Sun.COM  * by Lennart Augustsson (lennart@augustsson.net) at
41*11489SPengcheng.Chen@Sun.COM  * Carlstedt Research & Technology.
42*11489SPengcheng.Chen@Sun.COM  *
43*11489SPengcheng.Chen@Sun.COM  * Redistribution and use in source and binary forms, with or without
44*11489SPengcheng.Chen@Sun.COM  * modification, are permitted provided that the following conditions
45*11489SPengcheng.Chen@Sun.COM  * are met:
46*11489SPengcheng.Chen@Sun.COM  * 1. Redistributions of source code must retain the above copyright
47*11489SPengcheng.Chen@Sun.COM  *    notice, this list of conditions and the following disclaimer.
48*11489SPengcheng.Chen@Sun.COM  * 2. Redistributions in binary form must reproduce the above copyright
49*11489SPengcheng.Chen@Sun.COM  *    notice, this list of conditions and the following disclaimer in the
50*11489SPengcheng.Chen@Sun.COM  *    documentation and/or other materials provided with the distribution.
51*11489SPengcheng.Chen@Sun.COM  * 3. All advertising materials mentioning features or use of this software
52*11489SPengcheng.Chen@Sun.COM  *    must display the following acknowledgement:
53*11489SPengcheng.Chen@Sun.COM  *        This product includes software developed by the NetBSD
54*11489SPengcheng.Chen@Sun.COM  *        Foundation, Inc. and its contributors.
55*11489SPengcheng.Chen@Sun.COM  * 4. Neither the name of The NetBSD Foundation nor the names of its
56*11489SPengcheng.Chen@Sun.COM  *    contributors may be used to endorse or promote products derived
57*11489SPengcheng.Chen@Sun.COM  *    from this software without specific prior written permission.
58*11489SPengcheng.Chen@Sun.COM  *
59*11489SPengcheng.Chen@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
60*11489SPengcheng.Chen@Sun.COM  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61*11489SPengcheng.Chen@Sun.COM  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62*11489SPengcheng.Chen@Sun.COM  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
63*11489SPengcheng.Chen@Sun.COM  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64*11489SPengcheng.Chen@Sun.COM  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65*11489SPengcheng.Chen@Sun.COM  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66*11489SPengcheng.Chen@Sun.COM  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67*11489SPengcheng.Chen@Sun.COM  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68*11489SPengcheng.Chen@Sun.COM  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69*11489SPengcheng.Chen@Sun.COM  * POSSIBILITY OF SUCH DAMAGE.
70*11489SPengcheng.Chen@Sun.COM  */
71*11489SPengcheng.Chen@Sun.COM 
72*11489SPengcheng.Chen@Sun.COM #include <sys/stropts.h>
73*11489SPengcheng.Chen@Sun.COM #include <sys/strsun.h>
74*11489SPengcheng.Chen@Sun.COM #include <sys/termios.h>
75*11489SPengcheng.Chen@Sun.COM #include <sys/termio.h>
76*11489SPengcheng.Chen@Sun.COM #include <sys/strtty.h>
77*11489SPengcheng.Chen@Sun.COM #include <sys/systm.h>
78*11489SPengcheng.Chen@Sun.COM 
79*11489SPengcheng.Chen@Sun.COM #include <sys/usb/usba/usbai_version.h>
80*11489SPengcheng.Chen@Sun.COM #include <sys/usb/usba.h>
81*11489SPengcheng.Chen@Sun.COM #include <sys/usb/usba/usbai_private.h>
82*11489SPengcheng.Chen@Sun.COM #include <sys/usb/clients/hid/hid.h>
83*11489SPengcheng.Chen@Sun.COM #include <sys/usb/clients/usbinput/usbwcm/usbwcm.h>
84*11489SPengcheng.Chen@Sun.COM 
85*11489SPengcheng.Chen@Sun.COM /* debugging information */
86*11489SPengcheng.Chen@Sun.COM uint_t	usbwcm_errmask = (uint_t)PRINT_MASK_ALL;
87*11489SPengcheng.Chen@Sun.COM uint_t	usbwcm_errlevel = USB_LOG_L2;
88*11489SPengcheng.Chen@Sun.COM static usb_log_handle_t usbwcm_log_handle;
89*11489SPengcheng.Chen@Sun.COM 
90*11489SPengcheng.Chen@Sun.COM static void
uwacom_event(usbwcm_state_t * usbwcmp,uint_t type,uint_t idx,int val)91*11489SPengcheng.Chen@Sun.COM uwacom_event(usbwcm_state_t *usbwcmp, uint_t type, uint_t idx, int val)
92*11489SPengcheng.Chen@Sun.COM {
93*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
94*11489SPengcheng.Chen@Sun.COM 	mblk_t			*mp;
95*11489SPengcheng.Chen@Sun.COM 
96*11489SPengcheng.Chen@Sun.COM 	switch (type) {
97*11489SPengcheng.Chen@Sun.COM 	case EVT_SYN:
98*11489SPengcheng.Chen@Sun.COM 		if (sc->sc_sync)
99*11489SPengcheng.Chen@Sun.COM 			return;
100*11489SPengcheng.Chen@Sun.COM 		break;
101*11489SPengcheng.Chen@Sun.COM 
102*11489SPengcheng.Chen@Sun.COM 	case EVT_BTN:
103*11489SPengcheng.Chen@Sun.COM 		if (sc->sc_btn[idx] == val)
104*11489SPengcheng.Chen@Sun.COM 			return;
105*11489SPengcheng.Chen@Sun.COM 
106*11489SPengcheng.Chen@Sun.COM 		sc->sc_btn[idx] = val;
107*11489SPengcheng.Chen@Sun.COM 		break;
108*11489SPengcheng.Chen@Sun.COM 
109*11489SPengcheng.Chen@Sun.COM 	case EVT_ABS:
110*11489SPengcheng.Chen@Sun.COM 		if (sc->sc_abs[idx].fuzz) {
111*11489SPengcheng.Chen@Sun.COM 			int dist = abs(val - sc->sc_abs[idx].value);
112*11489SPengcheng.Chen@Sun.COM 
113*11489SPengcheng.Chen@Sun.COM 			if (dist < sc->sc_abs[idx].fuzz >> 1) {
114*11489SPengcheng.Chen@Sun.COM 				return;
115*11489SPengcheng.Chen@Sun.COM 			} else if (dist < sc->sc_abs[idx].fuzz) {
116*11489SPengcheng.Chen@Sun.COM 				val = (7 * sc->sc_abs[idx].value + val) >> 3;
117*11489SPengcheng.Chen@Sun.COM 			} else if (dist < sc->sc_abs[idx].fuzz << 1) {
118*11489SPengcheng.Chen@Sun.COM 				val = (sc->sc_abs[idx].value + val) >> 1;
119*11489SPengcheng.Chen@Sun.COM 			}
120*11489SPengcheng.Chen@Sun.COM 		}
121*11489SPengcheng.Chen@Sun.COM 		if (sc->sc_abs[idx].value == val) {
122*11489SPengcheng.Chen@Sun.COM 			return;
123*11489SPengcheng.Chen@Sun.COM 		}
124*11489SPengcheng.Chen@Sun.COM 
125*11489SPengcheng.Chen@Sun.COM 		sc->sc_abs[idx].value = val;
126*11489SPengcheng.Chen@Sun.COM 		break;
127*11489SPengcheng.Chen@Sun.COM 
128*11489SPengcheng.Chen@Sun.COM 	case EVT_REL:
129*11489SPengcheng.Chen@Sun.COM 		if (!val)
130*11489SPengcheng.Chen@Sun.COM 			return;
131*11489SPengcheng.Chen@Sun.COM 		break;
132*11489SPengcheng.Chen@Sun.COM 
133*11489SPengcheng.Chen@Sun.COM 	case EVT_MSC:
134*11489SPengcheng.Chen@Sun.COM 		break;
135*11489SPengcheng.Chen@Sun.COM 
136*11489SPengcheng.Chen@Sun.COM 	default:
137*11489SPengcheng.Chen@Sun.COM 		return;
138*11489SPengcheng.Chen@Sun.COM 	}
139*11489SPengcheng.Chen@Sun.COM 
140*11489SPengcheng.Chen@Sun.COM 	if ((mp = allocb(sizeof (struct event_input), BPRI_HI)) != NULL) {
141*11489SPengcheng.Chen@Sun.COM 		struct event_input *ev = (struct event_input *)mp->b_wptr;
142*11489SPengcheng.Chen@Sun.COM 
143*11489SPengcheng.Chen@Sun.COM 		ev->type = (uint16_t)type;
144*11489SPengcheng.Chen@Sun.COM 		ev->code = (uint16_t)idx;
145*11489SPengcheng.Chen@Sun.COM 		ev->value = (int32_t)val;
146*11489SPengcheng.Chen@Sun.COM 		uniqtime32(&ev->time);
147*11489SPengcheng.Chen@Sun.COM 
148*11489SPengcheng.Chen@Sun.COM 		mp->b_wptr += sizeof (struct event_input);
149*11489SPengcheng.Chen@Sun.COM 		putnext(usbwcmp->usbwcm_rq, mp);
150*11489SPengcheng.Chen@Sun.COM 	} else {
151*11489SPengcheng.Chen@Sun.COM 		return;
152*11489SPengcheng.Chen@Sun.COM 	}
153*11489SPengcheng.Chen@Sun.COM 
154*11489SPengcheng.Chen@Sun.COM 	sc->sc_sync = (type == EVT_SYN);
155*11489SPengcheng.Chen@Sun.COM }
156*11489SPengcheng.Chen@Sun.COM 
157*11489SPengcheng.Chen@Sun.COM static void
uwacom_pos_events_graphire(usbwcm_state_t * usbwcmp,int x,int y)158*11489SPengcheng.Chen@Sun.COM uwacom_pos_events_graphire(usbwcm_state_t *usbwcmp, int x, int y)
159*11489SPengcheng.Chen@Sun.COM {
160*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_X, x);
161*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_Y, y);
162*11489SPengcheng.Chen@Sun.COM }
163*11489SPengcheng.Chen@Sun.COM 
164*11489SPengcheng.Chen@Sun.COM static void
uwacom_pen_events_graphire(usbwcm_state_t * usbwcmp,int prs,int stl1,int stl2)165*11489SPengcheng.Chen@Sun.COM uwacom_pen_events_graphire(usbwcm_state_t *usbwcmp, int prs, int stl1, int stl2)
166*11489SPengcheng.Chen@Sun.COM {
167*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_PRESSURE, prs);
168*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_TIP, prs);
169*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_1, stl1);
170*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_2, stl2);
171*11489SPengcheng.Chen@Sun.COM }
172*11489SPengcheng.Chen@Sun.COM 
173*11489SPengcheng.Chen@Sun.COM static void
uwacom_mouse_events_graphire(usbwcm_state_t * usbwcmp,int left,int middle,int right,int wheel,int distance)174*11489SPengcheng.Chen@Sun.COM uwacom_mouse_events_graphire(usbwcm_state_t *usbwcmp, int left, int middle,
175*11489SPengcheng.Chen@Sun.COM     int right, int wheel, int distance)
176*11489SPengcheng.Chen@Sun.COM {
177*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_LEFT, left);
178*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_MIDDLE, middle);
179*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_RIGHT, right);
180*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_REL, REL_WHEEL, wheel);
181*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_DISTANCE, distance);
182*11489SPengcheng.Chen@Sun.COM }
183*11489SPengcheng.Chen@Sun.COM 
184*11489SPengcheng.Chen@Sun.COM static void
uwacom_tool_events_graphire(usbwcm_state_t * usbwcmp,int idx,int proximity)185*11489SPengcheng.Chen@Sun.COM uwacom_tool_events_graphire(usbwcm_state_t *usbwcmp, int idx, int proximity)
186*11489SPengcheng.Chen@Sun.COM {
187*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
188*11489SPengcheng.Chen@Sun.COM 
189*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, sc->sc_tool[idx], proximity);
190*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_MISC, sc->sc_tool_id[idx]);
191*11489SPengcheng.Chen@Sun.COM 	if (sc->sc_serial[idx]) {
192*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_MSC, MSC_SERIAL, sc->sc_serial[idx]);
193*11489SPengcheng.Chen@Sun.COM 	}
194*11489SPengcheng.Chen@Sun.COM 
195*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_SYN, SYN_REPORT, 0);
196*11489SPengcheng.Chen@Sun.COM }
197*11489SPengcheng.Chen@Sun.COM 
198*11489SPengcheng.Chen@Sun.COM static void
uwacom_pad_events_graphire4(usbwcm_state_t * usbwcmp,int b0,int b1,int b4,int b5,int rel,int abs)199*11489SPengcheng.Chen@Sun.COM uwacom_pad_events_graphire4(usbwcm_state_t *usbwcmp, int b0, int b1, int b4,
200*11489SPengcheng.Chen@Sun.COM     int b5, int rel, int abs)
201*11489SPengcheng.Chen@Sun.COM {
202*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_0, b0);
203*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_1, b1);
204*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_4, b4);
205*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_5, b5);
206*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_REL, REL_WHEEL, rel);
207*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_WHEEL, abs);
208*11489SPengcheng.Chen@Sun.COM 	uwacom_tool_events_graphire(usbwcmp, 1, b0 | b1 | b4 | b5 | rel | abs);
209*11489SPengcheng.Chen@Sun.COM }
210*11489SPengcheng.Chen@Sun.COM 
211*11489SPengcheng.Chen@Sun.COM static void
usbwcm_input_graphire(usbwcm_state_t * usbwcmp,mblk_t * mp)212*11489SPengcheng.Chen@Sun.COM usbwcm_input_graphire(usbwcm_state_t *usbwcmp, mblk_t *mp)
213*11489SPengcheng.Chen@Sun.COM {
214*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
215*11489SPengcheng.Chen@Sun.COM 	uint8_t *packet = mp->b_rptr;
216*11489SPengcheng.Chen@Sun.COM 
217*11489SPengcheng.Chen@Sun.COM 	if (PACKET_BITS(0, 0, 8) != 0x02) {
218*11489SPengcheng.Chen@Sun.COM 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
219*11489SPengcheng.Chen@Sun.COM 		    "unknown report type %02x received\n",
220*11489SPengcheng.Chen@Sun.COM 		    PACKET_BITS(0, 0, 8));
221*11489SPengcheng.Chen@Sun.COM 		return;
222*11489SPengcheng.Chen@Sun.COM 	}
223*11489SPengcheng.Chen@Sun.COM 
224*11489SPengcheng.Chen@Sun.COM 	/* Tool in proximity */
225*11489SPengcheng.Chen@Sun.COM 	if (PACKET_BIT(1, 7)) {
226*11489SPengcheng.Chen@Sun.COM 		uwacom_pos_events_graphire(usbwcmp,
227*11489SPengcheng.Chen@Sun.COM 		    (PACKET_BITS(3, 0, 8) << 8) | PACKET_BITS(2, 0, 8),
228*11489SPengcheng.Chen@Sun.COM 		    (PACKET_BITS(5, 0, 8) << 8) | PACKET_BITS(4, 0, 8));
229*11489SPengcheng.Chen@Sun.COM 
230*11489SPengcheng.Chen@Sun.COM 		if (!PACKET_BIT(1, 6)) {
231*11489SPengcheng.Chen@Sun.COM 			if (!PACKET_BIT(1, 5)) {
232*11489SPengcheng.Chen@Sun.COM 				sc->sc_tool[0] = BTN_TOOL_PEN;
233*11489SPengcheng.Chen@Sun.COM 				sc->sc_tool_id[0] = TOOL_ID_PEN;
234*11489SPengcheng.Chen@Sun.COM 			} else {
235*11489SPengcheng.Chen@Sun.COM 				sc->sc_tool[0] = BTN_TOOL_ERASER;
236*11489SPengcheng.Chen@Sun.COM 				sc->sc_tool_id[0] = TOOL_ID_ERASER;
237*11489SPengcheng.Chen@Sun.COM 			}
238*11489SPengcheng.Chen@Sun.COM 
239*11489SPengcheng.Chen@Sun.COM 			uwacom_pen_events_graphire(usbwcmp,
240*11489SPengcheng.Chen@Sun.COM 			    (PACKET_BIT(7, 0) << 8) | PACKET_BITS(6, 0, 8),
241*11489SPengcheng.Chen@Sun.COM 			    PACKET_BIT(1, 1), PACKET_BIT(1, 2));
242*11489SPengcheng.Chen@Sun.COM 		} else {
243*11489SPengcheng.Chen@Sun.COM 			int wheel, distance;
244*11489SPengcheng.Chen@Sun.COM 
245*11489SPengcheng.Chen@Sun.COM 			if (sc->sc_type->protocol == GRAPHIRE) {
246*11489SPengcheng.Chen@Sun.COM 				wheel = (PACKET_BIT(1, 5) ?
247*11489SPengcheng.Chen@Sun.COM 				    0 : -(int8_t)PACKET_BITS(6, 0, 8));
248*11489SPengcheng.Chen@Sun.COM 				distance = PACKET_BITS(7, 0, 6);
249*11489SPengcheng.Chen@Sun.COM 			} else {
250*11489SPengcheng.Chen@Sun.COM 				wheel = (PACKET_BIT(7, 2) << 2) -
251*11489SPengcheng.Chen@Sun.COM 				    PACKET_BITS(7, 0, 2);
252*11489SPengcheng.Chen@Sun.COM 				distance = PACKET_BITS(6, 0, 6);
253*11489SPengcheng.Chen@Sun.COM 			}
254*11489SPengcheng.Chen@Sun.COM 
255*11489SPengcheng.Chen@Sun.COM 			sc->sc_tool[0] = BTN_TOOL_MOUSE;
256*11489SPengcheng.Chen@Sun.COM 			sc->sc_tool_id[0] = TOOL_ID_MOUSE;
257*11489SPengcheng.Chen@Sun.COM 
258*11489SPengcheng.Chen@Sun.COM 			uwacom_mouse_events_graphire(usbwcmp, PACKET_BIT(1, 0),
259*11489SPengcheng.Chen@Sun.COM 			    PACKET_BIT(1, 2), PACKET_BIT(1, 1), wheel,
260*11489SPengcheng.Chen@Sun.COM 			    distance);
261*11489SPengcheng.Chen@Sun.COM 		}
262*11489SPengcheng.Chen@Sun.COM 
263*11489SPengcheng.Chen@Sun.COM 		uwacom_tool_events_graphire(usbwcmp, 0, 1);
264*11489SPengcheng.Chen@Sun.COM 
265*11489SPengcheng.Chen@Sun.COM 		/* Tool leaving proximity */
266*11489SPengcheng.Chen@Sun.COM 	} else if (sc->sc_tool_id[0]) {
267*11489SPengcheng.Chen@Sun.COM 		uwacom_pos_events_graphire(usbwcmp, 0, 0);
268*11489SPengcheng.Chen@Sun.COM 
269*11489SPengcheng.Chen@Sun.COM 		if (sc->sc_tool[0] == BTN_TOOL_MOUSE)
270*11489SPengcheng.Chen@Sun.COM 			uwacom_mouse_events_graphire(usbwcmp, 0, 0, 0, 0, 0);
271*11489SPengcheng.Chen@Sun.COM 		else
272*11489SPengcheng.Chen@Sun.COM 			uwacom_pen_events_graphire(usbwcmp, 0, 0, 0);
273*11489SPengcheng.Chen@Sun.COM 
274*11489SPengcheng.Chen@Sun.COM 		sc->sc_tool_id[0] = 0;
275*11489SPengcheng.Chen@Sun.COM 		uwacom_tool_events_graphire(usbwcmp, 0, 0);
276*11489SPengcheng.Chen@Sun.COM 	}
277*11489SPengcheng.Chen@Sun.COM 
278*11489SPengcheng.Chen@Sun.COM 	/* Finger on pad: Graphire4 */
279*11489SPengcheng.Chen@Sun.COM 	if ((sc->sc_type->protocol == GRAPHIRE4) && PACKET_BITS(7, 3, 5)) {
280*11489SPengcheng.Chen@Sun.COM 		sc->sc_tool_id[1] = TOOL_ID_PAD;
281*11489SPengcheng.Chen@Sun.COM 		uwacom_pad_events_graphire4(usbwcmp, PACKET_BIT(7, 6), 0,
282*11489SPengcheng.Chen@Sun.COM 		    PACKET_BIT(7, 7), 0,
283*11489SPengcheng.Chen@Sun.COM 		    PACKET_BITS(7, 3, 2) - (PACKET_BIT(7, 5) << 2), 0);
284*11489SPengcheng.Chen@Sun.COM 
285*11489SPengcheng.Chen@Sun.COM 	/* Finger on pad: MyOffice */
286*11489SPengcheng.Chen@Sun.COM 	} else if ((sc->sc_type->protocol == MYOFFICE) &&
287*11489SPengcheng.Chen@Sun.COM 	    (PACKET_BITS(7, 3, 4) || PACKET_BITS(8, 0, 8))) {
288*11489SPengcheng.Chen@Sun.COM 		sc->sc_tool_id[1] = TOOL_ID_PAD;
289*11489SPengcheng.Chen@Sun.COM 		uwacom_pad_events_graphire4(usbwcmp, PACKET_BIT(7, 3),
290*11489SPengcheng.Chen@Sun.COM 		    PACKET_BIT(7, 4), PACKET_BIT(7, 5), PACKET_BIT(7, 6), 0,
291*11489SPengcheng.Chen@Sun.COM 		    PACKET_BITS(8, 0, 7));
292*11489SPengcheng.Chen@Sun.COM 
293*11489SPengcheng.Chen@Sun.COM 	/* Finger leaving pad */
294*11489SPengcheng.Chen@Sun.COM 	} else if (sc->sc_tool_id[1]) {
295*11489SPengcheng.Chen@Sun.COM 		sc->sc_tool_id[1] = 0;
296*11489SPengcheng.Chen@Sun.COM 		uwacom_pad_events_graphire4(usbwcmp, 0, 0, 0, 0, 0, 0);
297*11489SPengcheng.Chen@Sun.COM 	}
298*11489SPengcheng.Chen@Sun.COM }
299*11489SPengcheng.Chen@Sun.COM 
300*11489SPengcheng.Chen@Sun.COM static void
uwacom_pos_events_intuos(usbwcm_state_t * usbwcmp,int x,int y,int distance)301*11489SPengcheng.Chen@Sun.COM uwacom_pos_events_intuos(usbwcm_state_t *usbwcmp, int x, int y, int distance)
302*11489SPengcheng.Chen@Sun.COM {
303*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_X, x);
304*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_Y, y);
305*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_DISTANCE, distance);
306*11489SPengcheng.Chen@Sun.COM }
307*11489SPengcheng.Chen@Sun.COM 
308*11489SPengcheng.Chen@Sun.COM static void
uwacom_pen_events_intuos(usbwcm_state_t * usbwcmp,uint8_t * packet)309*11489SPengcheng.Chen@Sun.COM uwacom_pen_events_intuos(usbwcm_state_t *usbwcmp, uint8_t *packet)
310*11489SPengcheng.Chen@Sun.COM {
311*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
312*11489SPengcheng.Chen@Sun.COM 	int press, tilt_x, tilt_y, stl1, stl2;
313*11489SPengcheng.Chen@Sun.COM 
314*11489SPengcheng.Chen@Sun.COM 	switch (sc->sc_type->protocol) {
315*11489SPengcheng.Chen@Sun.COM 	case INTUOS4S:
316*11489SPengcheng.Chen@Sun.COM 	case INTUOS4L:
317*11489SPengcheng.Chen@Sun.COM 		press = PACKET_BITS(7, 6, 10) << 1 | PACKET_BIT(1, 0);
318*11489SPengcheng.Chen@Sun.COM 		break;
319*11489SPengcheng.Chen@Sun.COM 	default:
320*11489SPengcheng.Chen@Sun.COM 		press = PACKET_BITS(7, 6, 10);
321*11489SPengcheng.Chen@Sun.COM 		break;
322*11489SPengcheng.Chen@Sun.COM 	}
323*11489SPengcheng.Chen@Sun.COM 
324*11489SPengcheng.Chen@Sun.COM 	tilt_x = PACKET_BITS(8, 7, 7);
325*11489SPengcheng.Chen@Sun.COM 	tilt_y = PACKET_BITS(8, 0, 7);
326*11489SPengcheng.Chen@Sun.COM 	stl1 = PACKET_BIT(1, 1);
327*11489SPengcheng.Chen@Sun.COM 	stl2 = PACKET_BIT(1, 2);
328*11489SPengcheng.Chen@Sun.COM 
329*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_PRESSURE, press);
330*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_TILT_X, tilt_x);
331*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_TILT_Y, tilt_y);
332*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_TIP, press);
333*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_1, stl1);
334*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_2, stl2);
335*11489SPengcheng.Chen@Sun.COM }
336*11489SPengcheng.Chen@Sun.COM 
337*11489SPengcheng.Chen@Sun.COM static void
uwacom_mouse_events_intuos(usbwcm_state_t * usbwcmp,uint8_t * packet)338*11489SPengcheng.Chen@Sun.COM uwacom_mouse_events_intuos(usbwcm_state_t *usbwcmp, uint8_t *packet)
339*11489SPengcheng.Chen@Sun.COM {
340*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
341*11489SPengcheng.Chen@Sun.COM 	int left, middle, right, extra, side, wheel;
342*11489SPengcheng.Chen@Sun.COM 
343*11489SPengcheng.Chen@Sun.COM 	switch (sc->sc_type->protocol) {
344*11489SPengcheng.Chen@Sun.COM 	case INTUOS4S:
345*11489SPengcheng.Chen@Sun.COM 	case INTUOS4L:
346*11489SPengcheng.Chen@Sun.COM 		left = PACKET_BIT(6, 0);
347*11489SPengcheng.Chen@Sun.COM 		middle = PACKET_BIT(6, 1);
348*11489SPengcheng.Chen@Sun.COM 		right = PACKET_BIT(6, 2);
349*11489SPengcheng.Chen@Sun.COM 		side = PACKET_BIT(6, 3);
350*11489SPengcheng.Chen@Sun.COM 		extra = PACKET_BIT(6, 4);
351*11489SPengcheng.Chen@Sun.COM 		wheel = PACKET_BIT(7, 7) - PACKET_BIT(7, 6);
352*11489SPengcheng.Chen@Sun.COM 		break;
353*11489SPengcheng.Chen@Sun.COM 
354*11489SPengcheng.Chen@Sun.COM 	default:
355*11489SPengcheng.Chen@Sun.COM 		left = PACKET_BIT(8, 2);
356*11489SPengcheng.Chen@Sun.COM 		middle = PACKET_BIT(8, 3);
357*11489SPengcheng.Chen@Sun.COM 		right = PACKET_BIT(8, 4);
358*11489SPengcheng.Chen@Sun.COM 		extra = PACKET_BIT(8, 5);
359*11489SPengcheng.Chen@Sun.COM 		side = PACKET_BIT(8, 6);
360*11489SPengcheng.Chen@Sun.COM 		wheel = PACKET_BIT(8, 0) - PACKET_BIT(8, 1);
361*11489SPengcheng.Chen@Sun.COM 		break;
362*11489SPengcheng.Chen@Sun.COM 	}
363*11489SPengcheng.Chen@Sun.COM 
364*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_LEFT, left);
365*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_MIDDLE, middle);
366*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_RIGHT, right);
367*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_EXTRA, extra);
368*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, BTN_SIDE, side);
369*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_REL, REL_WHEEL, wheel);
370*11489SPengcheng.Chen@Sun.COM }
371*11489SPengcheng.Chen@Sun.COM 
372*11489SPengcheng.Chen@Sun.COM static void
uwacom_tool_events_intuos(usbwcm_state_t * usbwcmp,int idx,int proximity)373*11489SPengcheng.Chen@Sun.COM uwacom_tool_events_intuos(usbwcm_state_t *usbwcmp, int idx, int proximity)
374*11489SPengcheng.Chen@Sun.COM {
375*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
376*11489SPengcheng.Chen@Sun.COM 
377*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_BTN, sc->sc_tool[idx], proximity);
378*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_ABS, ABS_MISC, sc->sc_tool_id[idx]);
379*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_MSC, MSC_SERIAL, sc->sc_serial[idx]);
380*11489SPengcheng.Chen@Sun.COM 	uwacom_event(usbwcmp, EVT_SYN, SYN_REPORT, 0);
381*11489SPengcheng.Chen@Sun.COM }
382*11489SPengcheng.Chen@Sun.COM 
383*11489SPengcheng.Chen@Sun.COM static void
uwacom_pad_events_intuos(usbwcm_state_t * usbwcmp,uint8_t * packet)384*11489SPengcheng.Chen@Sun.COM uwacom_pad_events_intuos(usbwcm_state_t *usbwcmp, uint8_t *packet)
385*11489SPengcheng.Chen@Sun.COM {
386*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
387*11489SPengcheng.Chen@Sun.COM 	int b0, b1, b2, b3, b4, b5, b6, b7;
388*11489SPengcheng.Chen@Sun.COM 	int rx, ry, prox;
389*11489SPengcheng.Chen@Sun.COM 	int b8, whl, rot;
390*11489SPengcheng.Chen@Sun.COM 
391*11489SPengcheng.Chen@Sun.COM 	switch (sc->sc_type->protocol) {
392*11489SPengcheng.Chen@Sun.COM 	case INTUOS4L:
393*11489SPengcheng.Chen@Sun.COM 		b7 = PACKET_BIT(3, 6);
394*11489SPengcheng.Chen@Sun.COM 		b8 = PACKET_BIT(3, 7);
395*11489SPengcheng.Chen@Sun.COM 
396*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_7, b7);
397*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_8, b8);
398*11489SPengcheng.Chen@Sun.COM 	/*FALLTHRU*/
399*11489SPengcheng.Chen@Sun.COM 	case INTUOS4S:
400*11489SPengcheng.Chen@Sun.COM 		b0 = PACKET_BIT(2, 0);
401*11489SPengcheng.Chen@Sun.COM 		b1 = PACKET_BIT(3, 0);
402*11489SPengcheng.Chen@Sun.COM 		b2 = PACKET_BIT(3, 1);
403*11489SPengcheng.Chen@Sun.COM 		b3 = PACKET_BIT(3, 2);
404*11489SPengcheng.Chen@Sun.COM 		b4 = PACKET_BIT(3, 3);
405*11489SPengcheng.Chen@Sun.COM 		b5 = PACKET_BIT(3, 4);
406*11489SPengcheng.Chen@Sun.COM 		b6 = PACKET_BIT(3, 5);
407*11489SPengcheng.Chen@Sun.COM 
408*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_0, b0);
409*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_1, b1);
410*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_2, b2);
411*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_3, b3);
412*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_4, b4);
413*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_5, b5);
414*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_6, b6);
415*11489SPengcheng.Chen@Sun.COM 
416*11489SPengcheng.Chen@Sun.COM 		whl = PACKET_BIT(1, 7);
417*11489SPengcheng.Chen@Sun.COM 		if (whl) {
418*11489SPengcheng.Chen@Sun.COM 			rot = PACKET_BITS(1, 0, 7);
419*11489SPengcheng.Chen@Sun.COM 			uwacom_event(usbwcmp, EVT_ABS, ABS_WHEEL, rot);
420*11489SPengcheng.Chen@Sun.COM 		}
421*11489SPengcheng.Chen@Sun.COM 
422*11489SPengcheng.Chen@Sun.COM 		prox = b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | whl;
423*11489SPengcheng.Chen@Sun.COM 		uwacom_tool_events_intuos(usbwcmp, 1, prox);
424*11489SPengcheng.Chen@Sun.COM 
425*11489SPengcheng.Chen@Sun.COM 		break;
426*11489SPengcheng.Chen@Sun.COM 
427*11489SPengcheng.Chen@Sun.COM 	default:
428*11489SPengcheng.Chen@Sun.COM 		b0 = PACKET_BIT(5, 0);
429*11489SPengcheng.Chen@Sun.COM 		b1 = PACKET_BIT(5, 1);
430*11489SPengcheng.Chen@Sun.COM 		b2 = PACKET_BIT(5, 2);
431*11489SPengcheng.Chen@Sun.COM 		b3 = PACKET_BIT(5, 3);
432*11489SPengcheng.Chen@Sun.COM 		b4 = PACKET_BIT(6, 0);
433*11489SPengcheng.Chen@Sun.COM 		b5 = PACKET_BIT(6, 1);
434*11489SPengcheng.Chen@Sun.COM 		b6 = PACKET_BIT(6, 2);
435*11489SPengcheng.Chen@Sun.COM 		b7 = PACKET_BIT(6, 3);
436*11489SPengcheng.Chen@Sun.COM 		rx = PACKET_BITS(2, 0, 13);
437*11489SPengcheng.Chen@Sun.COM 		ry = PACKET_BITS(4, 0, 13);
438*11489SPengcheng.Chen@Sun.COM 
439*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_0, b0);
440*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_1, b1);
441*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_2, b2);
442*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_3, b3);
443*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_4, b4);
444*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_5, b5);
445*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_6, b6);
446*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_7, b7);
447*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_ABS, ABS_RX, rx);
448*11489SPengcheng.Chen@Sun.COM 		uwacom_event(usbwcmp, EVT_ABS, ABS_RY, ry);
449*11489SPengcheng.Chen@Sun.COM 
450*11489SPengcheng.Chen@Sun.COM 		prox = b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | rx | ry;
451*11489SPengcheng.Chen@Sun.COM 		uwacom_tool_events_intuos(usbwcmp, 1, prox);
452*11489SPengcheng.Chen@Sun.COM 
453*11489SPengcheng.Chen@Sun.COM 		break;
454*11489SPengcheng.Chen@Sun.COM 	}
455*11489SPengcheng.Chen@Sun.COM }
456*11489SPengcheng.Chen@Sun.COM 
457*11489SPengcheng.Chen@Sun.COM static void
usbwcm_input_intuos(usbwcm_state_t * usbwcmp,mblk_t * mp)458*11489SPengcheng.Chen@Sun.COM usbwcm_input_intuos(usbwcm_state_t *usbwcmp, mblk_t *mp)
459*11489SPengcheng.Chen@Sun.COM {
460*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
461*11489SPengcheng.Chen@Sun.COM 	uint8_t *packet = mp->b_rptr;
462*11489SPengcheng.Chen@Sun.COM 
463*11489SPengcheng.Chen@Sun.COM 	switch (PACKET_BITS(0, 0, 8)) {
464*11489SPengcheng.Chen@Sun.COM 	case 0x02:
465*11489SPengcheng.Chen@Sun.COM 		switch (PACKET_BITS(1, 5, 2)) {
466*11489SPengcheng.Chen@Sun.COM 		/* Tool entering proximity */
467*11489SPengcheng.Chen@Sun.COM 		case 0x2:
468*11489SPengcheng.Chen@Sun.COM 			sc->sc_tool_id[0] = PACKET_BITS(3, 4, 12);
469*11489SPengcheng.Chen@Sun.COM 			sc->sc_serial[0] =
470*11489SPengcheng.Chen@Sun.COM 			    (PACKET_BIT(1, 1) ? PACKET_BITS(7, 4, 32) : 0);
471*11489SPengcheng.Chen@Sun.COM 
472*11489SPengcheng.Chen@Sun.COM 			switch (sc->sc_tool_id[0]) {
473*11489SPengcheng.Chen@Sun.COM 			case 0x802: /* Intuos4 Grip Pen */
474*11489SPengcheng.Chen@Sun.COM 			case 0x804: /* Intuos4 Art Marker */
475*11489SPengcheng.Chen@Sun.COM 			case 0x823: /* Intuos3 Grip Pen */
476*11489SPengcheng.Chen@Sun.COM 			case 0x885: /* Intuos3 Art Marker */
477*11489SPengcheng.Chen@Sun.COM 				sc->sc_tool[0] = BTN_TOOL_PEN;
478*11489SPengcheng.Chen@Sun.COM 				break;
479*11489SPengcheng.Chen@Sun.COM 			case 0x80a: /* Intuos4 Grip Pen eraser */
480*11489SPengcheng.Chen@Sun.COM 			case 0x82b: /* Intuos3 Grip Pen eraser */
481*11489SPengcheng.Chen@Sun.COM 				sc->sc_tool[0] = BTN_TOOL_ERASER;
482*11489SPengcheng.Chen@Sun.COM 				break;
483*11489SPengcheng.Chen@Sun.COM 			case 0x017: /* Intuos3 2D mouse */
484*11489SPengcheng.Chen@Sun.COM 			case 0x806: /* Intuos4 2D mouse */
485*11489SPengcheng.Chen@Sun.COM 				sc->sc_tool[0] = BTN_TOOL_MOUSE;
486*11489SPengcheng.Chen@Sun.COM 				break;
487*11489SPengcheng.Chen@Sun.COM 			default:
488*11489SPengcheng.Chen@Sun.COM 				USB_DPRINTF_L1(PRINT_MASK_ALL,
489*11489SPengcheng.Chen@Sun.COM 				    usbwcm_log_handle,
490*11489SPengcheng.Chen@Sun.COM 				    "unknown tool ID %03x seen\n",
491*11489SPengcheng.Chen@Sun.COM 				    sc->sc_tool_id[0]);
492*11489SPengcheng.Chen@Sun.COM 				sc->sc_tool[0] = BTN_TOOL_PEN;
493*11489SPengcheng.Chen@Sun.COM 			}
494*11489SPengcheng.Chen@Sun.COM 			break;
495*11489SPengcheng.Chen@Sun.COM 
496*11489SPengcheng.Chen@Sun.COM 		/* Tool leaving proximity */
497*11489SPengcheng.Chen@Sun.COM 		case 0x0:
498*11489SPengcheng.Chen@Sun.COM 			uwacom_pos_events_intuos(usbwcmp, 0, 0, 0);
499*11489SPengcheng.Chen@Sun.COM 
500*11489SPengcheng.Chen@Sun.COM 			if (sc->sc_tool[0] == BTN_TOOL_MOUSE)
501*11489SPengcheng.Chen@Sun.COM 				uwacom_mouse_events_intuos(usbwcmp, packet);
502*11489SPengcheng.Chen@Sun.COM 			else
503*11489SPengcheng.Chen@Sun.COM 				uwacom_pen_events_intuos(usbwcmp, packet);
504*11489SPengcheng.Chen@Sun.COM 
505*11489SPengcheng.Chen@Sun.COM 			sc->sc_tool_id[0] = 0;
506*11489SPengcheng.Chen@Sun.COM 			uwacom_tool_events_intuos(usbwcmp, 0, 0);
507*11489SPengcheng.Chen@Sun.COM 			break;
508*11489SPengcheng.Chen@Sun.COM 
509*11489SPengcheng.Chen@Sun.COM 		/* Tool motion, outbound */
510*11489SPengcheng.Chen@Sun.COM 		case 0x1:
511*11489SPengcheng.Chen@Sun.COM 		/* Outbound tracking is unreliable on the Cintiq */
512*11489SPengcheng.Chen@Sun.COM 			if (sc->sc_type->protocol == CINTIQ)
513*11489SPengcheng.Chen@Sun.COM 			break;
514*11489SPengcheng.Chen@Sun.COM 
515*11489SPengcheng.Chen@Sun.COM 		/* Tool motion */
516*11489SPengcheng.Chen@Sun.COM 		/*FALLTHRU*/
517*11489SPengcheng.Chen@Sun.COM 		case 0x3:
518*11489SPengcheng.Chen@Sun.COM 			uwacom_pos_events_intuos(usbwcmp,
519*11489SPengcheng.Chen@Sun.COM 			    (PACKET_BITS(3, 0, 16) << 1) | PACKET_BIT(9, 1),
520*11489SPengcheng.Chen@Sun.COM 			    (PACKET_BITS(5, 0, 16) << 1) | PACKET_BIT(9, 0),
521*11489SPengcheng.Chen@Sun.COM 			    PACKET_BITS(9, 2, 6));
522*11489SPengcheng.Chen@Sun.COM 
523*11489SPengcheng.Chen@Sun.COM 			if (PACKET_BITS(1, 3, 2) == 0) {
524*11489SPengcheng.Chen@Sun.COM 				uwacom_pen_events_intuos(usbwcmp, packet);
525*11489SPengcheng.Chen@Sun.COM 
526*11489SPengcheng.Chen@Sun.COM 			} else if (PACKET_BITS(1, 1, 4) == 0x5) {
527*11489SPengcheng.Chen@Sun.COM 				int angle = 450 - PACKET_BITS(7, 6, 10);
528*11489SPengcheng.Chen@Sun.COM 
529*11489SPengcheng.Chen@Sun.COM 				if (PACKET_BIT(7, 5)) {
530*11489SPengcheng.Chen@Sun.COM 					angle = (angle > 0 ? 900 : -900) -
531*11489SPengcheng.Chen@Sun.COM 					    angle;
532*11489SPengcheng.Chen@Sun.COM 				}
533*11489SPengcheng.Chen@Sun.COM 
534*11489SPengcheng.Chen@Sun.COM 				uwacom_event(usbwcmp, EVT_ABS, ABS_Z, angle);
535*11489SPengcheng.Chen@Sun.COM 				break;
536*11489SPengcheng.Chen@Sun.COM 			} else if (PACKET_BITS(1, 1, 4) == 0x8) {
537*11489SPengcheng.Chen@Sun.COM 				uwacom_mouse_events_intuos(usbwcmp, packet);
538*11489SPengcheng.Chen@Sun.COM 			} else {
539*11489SPengcheng.Chen@Sun.COM 				USB_DPRINTF_L1(PRINT_MASK_ALL,
540*11489SPengcheng.Chen@Sun.COM 				    usbwcm_log_handle,
541*11489SPengcheng.Chen@Sun.COM 				    "unsupported motion packet type %x "
542*11489SPengcheng.Chen@Sun.COM 				    "received\n", PACKET_BITS(1, 1, 4));
543*11489SPengcheng.Chen@Sun.COM 			}
544*11489SPengcheng.Chen@Sun.COM 
545*11489SPengcheng.Chen@Sun.COM 			uwacom_tool_events_intuos(usbwcmp, 0, 1);
546*11489SPengcheng.Chen@Sun.COM 			break;
547*11489SPengcheng.Chen@Sun.COM 		}
548*11489SPengcheng.Chen@Sun.COM 
549*11489SPengcheng.Chen@Sun.COM 		break;
550*11489SPengcheng.Chen@Sun.COM 
551*11489SPengcheng.Chen@Sun.COM 	case 0x0c:
552*11489SPengcheng.Chen@Sun.COM 		uwacom_pad_events_intuos(usbwcmp, packet);
553*11489SPengcheng.Chen@Sun.COM 		break;
554*11489SPengcheng.Chen@Sun.COM 
555*11489SPengcheng.Chen@Sun.COM 	default:
556*11489SPengcheng.Chen@Sun.COM 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
557*11489SPengcheng.Chen@Sun.COM 		    "unknown report type %02x received\n",
558*11489SPengcheng.Chen@Sun.COM 		    PACKET_BITS(0, 0, 8));
559*11489SPengcheng.Chen@Sun.COM 	}
560*11489SPengcheng.Chen@Sun.COM }
561*11489SPengcheng.Chen@Sun.COM 
562*11489SPengcheng.Chen@Sun.COM static void
uwacom_init_abs(usbwcm_state_t * usbwcmp,int axis,int32_t min,int32_t max,int32_t fuzz,int32_t flat)563*11489SPengcheng.Chen@Sun.COM uwacom_init_abs(usbwcm_state_t *usbwcmp, int axis, int32_t min, int32_t max,
564*11489SPengcheng.Chen@Sun.COM     int32_t fuzz, int32_t flat)
565*11489SPengcheng.Chen@Sun.COM {
566*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
567*11489SPengcheng.Chen@Sun.COM 
568*11489SPengcheng.Chen@Sun.COM 	sc->sc_abs[axis].min = min;
569*11489SPengcheng.Chen@Sun.COM 	sc->sc_abs[axis].max = max;
570*11489SPengcheng.Chen@Sun.COM 	sc->sc_abs[axis].fuzz = fuzz;
571*11489SPengcheng.Chen@Sun.COM 	sc->sc_abs[axis].flat = flat;
572*11489SPengcheng.Chen@Sun.COM }
573*11489SPengcheng.Chen@Sun.COM 
574*11489SPengcheng.Chen@Sun.COM static void
uwacom_init_graphire4(usbwcm_state_t * usbwcmp)575*11489SPengcheng.Chen@Sun.COM uwacom_init_graphire4(usbwcm_state_t *usbwcmp)
576*11489SPengcheng.Chen@Sun.COM {
577*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
578*11489SPengcheng.Chen@Sun.COM 
579*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[0], EVT_MSC);
580*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_0);
581*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_4);
582*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_PAD);
583*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[4], MSC_SERIAL);
584*11489SPengcheng.Chen@Sun.COM 
585*11489SPengcheng.Chen@Sun.COM 	sc->sc_tool[1] = BTN_TOOL_PAD;
586*11489SPengcheng.Chen@Sun.COM 	sc->sc_serial[1] = SERIAL_PAD_GRAPHIRE4;
587*11489SPengcheng.Chen@Sun.COM }
588*11489SPengcheng.Chen@Sun.COM 
589*11489SPengcheng.Chen@Sun.COM static void
uwacom_init_myoffice(usbwcm_state_t * usbwcmp)590*11489SPengcheng.Chen@Sun.COM uwacom_init_myoffice(usbwcm_state_t *usbwcmp)
591*11489SPengcheng.Chen@Sun.COM {
592*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
593*11489SPengcheng.Chen@Sun.COM 
594*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_1);
595*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_5);
596*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_WHEEL);
597*11489SPengcheng.Chen@Sun.COM 
598*11489SPengcheng.Chen@Sun.COM 	uwacom_init_abs(usbwcmp, ABS_WHEEL, 0, 71, 0, 0);
599*11489SPengcheng.Chen@Sun.COM }
600*11489SPengcheng.Chen@Sun.COM 
601*11489SPengcheng.Chen@Sun.COM static void
uwacom_init_intuos(usbwcm_state_t * usbwcmp)602*11489SPengcheng.Chen@Sun.COM uwacom_init_intuos(usbwcm_state_t *usbwcmp)
603*11489SPengcheng.Chen@Sun.COM {
604*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
605*11489SPengcheng.Chen@Sun.COM 
606*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[0], EVT_MSC);
607*11489SPengcheng.Chen@Sun.COM 
608*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_0);
609*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_1);
610*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_2);
611*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_3);
612*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_SIDE);
613*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_EXTRA);
614*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_PAD);
615*11489SPengcheng.Chen@Sun.COM 
616*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_TILT_X);
617*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_TILT_Y);
618*11489SPengcheng.Chen@Sun.COM 
619*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[4], MSC_SERIAL);
620*11489SPengcheng.Chen@Sun.COM 
621*11489SPengcheng.Chen@Sun.COM 	sc->sc_tool[1] = BTN_TOOL_PAD;
622*11489SPengcheng.Chen@Sun.COM 	sc->sc_tool_id[1] = TOOL_ID_PAD;
623*11489SPengcheng.Chen@Sun.COM 	sc->sc_serial[1] = SERIAL_PAD_INTUOS;
624*11489SPengcheng.Chen@Sun.COM }
625*11489SPengcheng.Chen@Sun.COM 
626*11489SPengcheng.Chen@Sun.COM static void
uwacom_init_intuos3(usbwcm_state_t * usbwcmp)627*11489SPengcheng.Chen@Sun.COM uwacom_init_intuos3(usbwcm_state_t *usbwcmp)
628*11489SPengcheng.Chen@Sun.COM {
629*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
630*11489SPengcheng.Chen@Sun.COM 
631*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_Z);
632*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_RX);
633*11489SPengcheng.Chen@Sun.COM 
634*11489SPengcheng.Chen@Sun.COM 	uwacom_init_abs(usbwcmp, ABS_Z, -900,  899, 0, 0);
635*11489SPengcheng.Chen@Sun.COM 	uwacom_init_abs(usbwcmp, ABS_RX, 0, 4096, 0, 0);
636*11489SPengcheng.Chen@Sun.COM }
637*11489SPengcheng.Chen@Sun.COM 
638*11489SPengcheng.Chen@Sun.COM static void
uwacom_init_intuos3_large(usbwcm_state_t * usbwcmp)639*11489SPengcheng.Chen@Sun.COM uwacom_init_intuos3_large(usbwcm_state_t *usbwcmp)
640*11489SPengcheng.Chen@Sun.COM {
641*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
642*11489SPengcheng.Chen@Sun.COM 
643*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_4);
644*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_5);
645*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_6);
646*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_7);
647*11489SPengcheng.Chen@Sun.COM 
648*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_RY);
649*11489SPengcheng.Chen@Sun.COM 
650*11489SPengcheng.Chen@Sun.COM 	uwacom_init_abs(usbwcmp, ABS_RY, 0, 4096, 0, 0);
651*11489SPengcheng.Chen@Sun.COM }
652*11489SPengcheng.Chen@Sun.COM 
653*11489SPengcheng.Chen@Sun.COM static void
uwacom_init_intuos4(usbwcm_state_t * usbwcmp)654*11489SPengcheng.Chen@Sun.COM uwacom_init_intuos4(usbwcm_state_t *usbwcmp)
655*11489SPengcheng.Chen@Sun.COM {
656*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
657*11489SPengcheng.Chen@Sun.COM 
658*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_4);
659*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_5);
660*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_6);
661*11489SPengcheng.Chen@Sun.COM 
662*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_Z);
663*11489SPengcheng.Chen@Sun.COM 
664*11489SPengcheng.Chen@Sun.COM 	uwacom_init_abs(usbwcmp, ABS_Z, -900,  899, 0, 0);
665*11489SPengcheng.Chen@Sun.COM }
666*11489SPengcheng.Chen@Sun.COM static void
uwacom_init_intuos4_large(usbwcm_state_t * usbwcmp)667*11489SPengcheng.Chen@Sun.COM uwacom_init_intuos4_large(usbwcm_state_t *usbwcmp)
668*11489SPengcheng.Chen@Sun.COM {
669*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
670*11489SPengcheng.Chen@Sun.COM 
671*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_7);
672*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_8);
673*11489SPengcheng.Chen@Sun.COM }
674*11489SPengcheng.Chen@Sun.COM 
675*11489SPengcheng.Chen@Sun.COM static int
uwacom_init(usbwcm_state_t * usbwcmp)676*11489SPengcheng.Chen@Sun.COM uwacom_init(usbwcm_state_t *usbwcmp)
677*11489SPengcheng.Chen@Sun.COM {
678*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
679*11489SPengcheng.Chen@Sun.COM 
680*11489SPengcheng.Chen@Sun.COM 	sc->sc_id.bus = ID_BUS_USB;
681*11489SPengcheng.Chen@Sun.COM 	sc->sc_id.vendor = usbwcmp->usbwcm_devid.VendorId;
682*11489SPengcheng.Chen@Sun.COM 	sc->sc_id.product = usbwcmp->usbwcm_devid.ProductId;
683*11489SPengcheng.Chen@Sun.COM 
684*11489SPengcheng.Chen@Sun.COM 	sc->sc_id.version = 0;
685*11489SPengcheng.Chen@Sun.COM 
686*11489SPengcheng.Chen@Sun.COM 	for (int i = 0; i < EVT_USED; ++i)
687*11489SPengcheng.Chen@Sun.COM 		sc->sc_bm[i] = kmem_zalloc(bm_size[i], KM_SLEEP);
688*11489SPengcheng.Chen@Sun.COM 
689*11489SPengcheng.Chen@Sun.COM 	sc->sc_btn = kmem_zalloc(BTN_USED * sizeof (int), KM_SLEEP);
690*11489SPengcheng.Chen@Sun.COM 	sc->sc_abs = kmem_zalloc(ABS_USED * sizeof (struct event_abs_axis),
691*11489SPengcheng.Chen@Sun.COM 	    KM_SLEEP);
692*11489SPengcheng.Chen@Sun.COM 
693*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[0], EVT_SYN);
694*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[0], EVT_BTN);
695*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[0], EVT_REL);
696*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[0], EVT_ABS);
697*11489SPengcheng.Chen@Sun.COM 
698*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_LEFT);
699*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_RIGHT);
700*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_MIDDLE);
701*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_PEN);
702*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_ERASER);
703*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_MOUSE);
704*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_TIP);
705*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_STYLUS_1);
706*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[1], BTN_STYLUS_2);
707*11489SPengcheng.Chen@Sun.COM 
708*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[2], REL_WHEEL);
709*11489SPengcheng.Chen@Sun.COM 
710*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_X);
711*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_Y);
712*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_PRESSURE);
713*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_DISTANCE);
714*11489SPengcheng.Chen@Sun.COM 	BM_SET_BIT(sc->sc_bm[3], ABS_MISC);
715*11489SPengcheng.Chen@Sun.COM 
716*11489SPengcheng.Chen@Sun.COM 	uwacom_init_abs(usbwcmp, ABS_X, 0, sc->sc_type->x_max, 4, 0);
717*11489SPengcheng.Chen@Sun.COM 	uwacom_init_abs(usbwcmp, ABS_Y, 0, sc->sc_type->y_max, 4, 0);
718*11489SPengcheng.Chen@Sun.COM 	uwacom_init_abs(usbwcmp, ABS_PRESSURE, 0, sc->sc_type->pressure_max,
719*11489SPengcheng.Chen@Sun.COM 	    0, 0);
720*11489SPengcheng.Chen@Sun.COM 	uwacom_init_abs(usbwcmp, ABS_DISTANCE, 0,
721*11489SPengcheng.Chen@Sun.COM 	    uwacom_protocols[sc->sc_type->protocol].distance_max, 0, 0);
722*11489SPengcheng.Chen@Sun.COM 
723*11489SPengcheng.Chen@Sun.COM 	switch (sc->sc_type->protocol) {
724*11489SPengcheng.Chen@Sun.COM 		case CINTIQ:
725*11489SPengcheng.Chen@Sun.COM 		case INTUOS3L:
726*11489SPengcheng.Chen@Sun.COM 			uwacom_init_intuos3_large(usbwcmp);
727*11489SPengcheng.Chen@Sun.COM 		/*FALLTHRU*/
728*11489SPengcheng.Chen@Sun.COM 		case INTUOS3S:
729*11489SPengcheng.Chen@Sun.COM 			uwacom_init_intuos3(usbwcmp);
730*11489SPengcheng.Chen@Sun.COM 			uwacom_init_intuos(usbwcmp);
731*11489SPengcheng.Chen@Sun.COM 			break;
732*11489SPengcheng.Chen@Sun.COM 
733*11489SPengcheng.Chen@Sun.COM 		case INTUOS4L:
734*11489SPengcheng.Chen@Sun.COM 			uwacom_init_intuos4_large(usbwcmp);
735*11489SPengcheng.Chen@Sun.COM 		/*FALLTHRU*/
736*11489SPengcheng.Chen@Sun.COM 		case INTUOS4S:
737*11489SPengcheng.Chen@Sun.COM 			uwacom_init_intuos4(usbwcmp);
738*11489SPengcheng.Chen@Sun.COM 			uwacom_init_intuos(usbwcmp);
739*11489SPengcheng.Chen@Sun.COM 			break;
740*11489SPengcheng.Chen@Sun.COM 		case MYOFFICE:
741*11489SPengcheng.Chen@Sun.COM 			uwacom_init_myoffice(usbwcmp);
742*11489SPengcheng.Chen@Sun.COM 		/*FALLTHRU*/
743*11489SPengcheng.Chen@Sun.COM 		case GRAPHIRE4:
744*11489SPengcheng.Chen@Sun.COM 			uwacom_init_graphire4(usbwcmp);
745*11489SPengcheng.Chen@Sun.COM 		/*FALLTHRU*/
746*11489SPengcheng.Chen@Sun.COM 		case GRAPHIRE:
747*11489SPengcheng.Chen@Sun.COM 			break;
748*11489SPengcheng.Chen@Sun.COM 	}
749*11489SPengcheng.Chen@Sun.COM 
750*11489SPengcheng.Chen@Sun.COM 	return (0);
751*11489SPengcheng.Chen@Sun.COM }
752*11489SPengcheng.Chen@Sun.COM 
753*11489SPengcheng.Chen@Sun.COM /*
754*11489SPengcheng.Chen@Sun.COM  * usbwcm_match() :
755*11489SPengcheng.Chen@Sun.COM  *	Match device with it's parameters.
756*11489SPengcheng.Chen@Sun.COM  */
757*11489SPengcheng.Chen@Sun.COM static const struct uwacom_type *
usbwcm_match(uint16_t vid,uint16_t pid)758*11489SPengcheng.Chen@Sun.COM usbwcm_match(uint16_t vid, uint16_t pid)
759*11489SPengcheng.Chen@Sun.COM {
760*11489SPengcheng.Chen@Sun.COM 	const struct uwacom_type *dev;
761*11489SPengcheng.Chen@Sun.COM 
762*11489SPengcheng.Chen@Sun.COM 	dev = uwacom_devs;
763*11489SPengcheng.Chen@Sun.COM 	while (dev->devno.vid != 0 && dev->devno.pid != 0) {
764*11489SPengcheng.Chen@Sun.COM 		if (dev->devno.vid == vid && dev->devno.pid == pid) {
765*11489SPengcheng.Chen@Sun.COM 			return (dev);
766*11489SPengcheng.Chen@Sun.COM 		}
767*11489SPengcheng.Chen@Sun.COM 		dev++;
768*11489SPengcheng.Chen@Sun.COM 	}
769*11489SPengcheng.Chen@Sun.COM 
770*11489SPengcheng.Chen@Sun.COM 	return (NULL);
771*11489SPengcheng.Chen@Sun.COM }
772*11489SPengcheng.Chen@Sun.COM 
773*11489SPengcheng.Chen@Sun.COM /*
774*11489SPengcheng.Chen@Sun.COM  * usbwcm_probe() :
775*11489SPengcheng.Chen@Sun.COM  *	Check the device type and protocol.
776*11489SPengcheng.Chen@Sun.COM  */
777*11489SPengcheng.Chen@Sun.COM static int
usbwcm_probe(usbwcm_state_t * usbwcmp)778*11489SPengcheng.Chen@Sun.COM usbwcm_probe(usbwcm_state_t *usbwcmp)
779*11489SPengcheng.Chen@Sun.COM {
780*11489SPengcheng.Chen@Sun.COM 	queue_t		*q = usbwcmp->usbwcm_rq;
781*11489SPengcheng.Chen@Sun.COM 	mblk_t		*mctl_ptr;
782*11489SPengcheng.Chen@Sun.COM 	struct iocblk	mctlmsg;
783*11489SPengcheng.Chen@Sun.COM 	hid_req_t	*featr;
784*11489SPengcheng.Chen@Sun.COM 
785*11489SPengcheng.Chen@Sun.COM 	/* check device IDs */
786*11489SPengcheng.Chen@Sun.COM 	mctlmsg.ioc_cmd = HID_GET_VID_PID;
787*11489SPengcheng.Chen@Sun.COM 	mctlmsg.ioc_count = 0;
788*11489SPengcheng.Chen@Sun.COM 
789*11489SPengcheng.Chen@Sun.COM 	mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
790*11489SPengcheng.Chen@Sun.COM 	if (mctl_ptr == NULL) {
791*11489SPengcheng.Chen@Sun.COM 		return (ENOMEM);
792*11489SPengcheng.Chen@Sun.COM 	}
793*11489SPengcheng.Chen@Sun.COM 
794*11489SPengcheng.Chen@Sun.COM 	putnext(usbwcmp->usbwcm_wq, mctl_ptr);
795*11489SPengcheng.Chen@Sun.COM 	usbwcmp->usbwcm_flags |= USBWCM_QWAIT;
796*11489SPengcheng.Chen@Sun.COM 
797*11489SPengcheng.Chen@Sun.COM 	while (usbwcmp->usbwcm_flags & USBWCM_QWAIT) {
798*11489SPengcheng.Chen@Sun.COM 		if (qwait_sig(q) == 0) {
799*11489SPengcheng.Chen@Sun.COM 			usbwcmp->usbwcm_flags = 0;
800*11489SPengcheng.Chen@Sun.COM 			return (EINTR);
801*11489SPengcheng.Chen@Sun.COM 		}
802*11489SPengcheng.Chen@Sun.COM 	}
803*11489SPengcheng.Chen@Sun.COM 
804*11489SPengcheng.Chen@Sun.COM 	usbwcmp->usbwcm_softc.sc_type =
805*11489SPengcheng.Chen@Sun.COM 	    usbwcm_match(usbwcmp->usbwcm_devid.VendorId,
806*11489SPengcheng.Chen@Sun.COM 	    usbwcmp->usbwcm_devid.ProductId);
807*11489SPengcheng.Chen@Sun.COM 	if (!usbwcmp->usbwcm_softc.sc_type) {
808*11489SPengcheng.Chen@Sun.COM 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
809*11489SPengcheng.Chen@Sun.COM 		    "unsupported tablet model\n");
810*11489SPengcheng.Chen@Sun.COM 		return (ENXIO);
811*11489SPengcheng.Chen@Sun.COM 	}
812*11489SPengcheng.Chen@Sun.COM 
813*11489SPengcheng.Chen@Sun.COM 	if (uwacom_init(usbwcmp) != 0) {
814*11489SPengcheng.Chen@Sun.COM 		return (ENXIO);
815*11489SPengcheng.Chen@Sun.COM 	}
816*11489SPengcheng.Chen@Sun.COM 
817*11489SPengcheng.Chen@Sun.COM 	/* set feature: tablet mode */
818*11489SPengcheng.Chen@Sun.COM 	featr = kmem_zalloc(sizeof (hid_req_t), KM_SLEEP);
819*11489SPengcheng.Chen@Sun.COM 	featr->hid_req_version_no = HID_VERSION_V_0;
820*11489SPengcheng.Chen@Sun.COM 	featr->hid_req_wValue = REPORT_TYPE_FEATURE | 2;
821*11489SPengcheng.Chen@Sun.COM 	featr->hid_req_wLength = sizeof (uint8_t) * 2;
822*11489SPengcheng.Chen@Sun.COM 	featr->hid_req_data[0] = 2;
823*11489SPengcheng.Chen@Sun.COM 	featr->hid_req_data[1] = 2;
824*11489SPengcheng.Chen@Sun.COM 
825*11489SPengcheng.Chen@Sun.COM 	mctlmsg.ioc_cmd = HID_SET_REPORT;
826*11489SPengcheng.Chen@Sun.COM 	mctlmsg.ioc_count = sizeof (featr);
827*11489SPengcheng.Chen@Sun.COM 	mctl_ptr = usba_mk_mctl(mctlmsg, featr, sizeof (hid_req_t));
828*11489SPengcheng.Chen@Sun.COM 	if (mctl_ptr != NULL) {
829*11489SPengcheng.Chen@Sun.COM 		putnext(usbwcmp->usbwcm_wq, mctl_ptr);
830*11489SPengcheng.Chen@Sun.COM 
831*11489SPengcheng.Chen@Sun.COM 		/*
832*11489SPengcheng.Chen@Sun.COM 		 * Waiting for response of HID_SET_REPORT
833*11489SPengcheng.Chen@Sun.COM 		 * mctl for setting the feature.
834*11489SPengcheng.Chen@Sun.COM 		 */
835*11489SPengcheng.Chen@Sun.COM 		usbwcmp->usbwcm_flags |= USBWCM_QWAIT;
836*11489SPengcheng.Chen@Sun.COM 		while (usbwcmp->usbwcm_flags & USBWCM_QWAIT) {
837*11489SPengcheng.Chen@Sun.COM 			qwait(q);
838*11489SPengcheng.Chen@Sun.COM 		}
839*11489SPengcheng.Chen@Sun.COM 	} else {
840*11489SPengcheng.Chen@Sun.COM 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
841*11489SPengcheng.Chen@Sun.COM 		    "enable tablet mode failed\n");
842*11489SPengcheng.Chen@Sun.COM 	}
843*11489SPengcheng.Chen@Sun.COM 
844*11489SPengcheng.Chen@Sun.COM 	kmem_free(featr, sizeof (hid_req_t));
845*11489SPengcheng.Chen@Sun.COM 
846*11489SPengcheng.Chen@Sun.COM 	return (0);
847*11489SPengcheng.Chen@Sun.COM }
848*11489SPengcheng.Chen@Sun.COM 
849*11489SPengcheng.Chen@Sun.COM /*
850*11489SPengcheng.Chen@Sun.COM  * usbwcm_copyreq() :
851*11489SPengcheng.Chen@Sun.COM  *	helper function for usbwcm ioctls
852*11489SPengcheng.Chen@Sun.COM  */
853*11489SPengcheng.Chen@Sun.COM static int
usbwcm_copyreq(mblk_t * mp,uint_t pvtsize,uint_t state,uint_t reqsize,uint_t contsize,uint_t copytype)854*11489SPengcheng.Chen@Sun.COM usbwcm_copyreq(mblk_t *mp, uint_t pvtsize, uint_t state, uint_t reqsize,
855*11489SPengcheng.Chen@Sun.COM     uint_t contsize, uint_t copytype)
856*11489SPengcheng.Chen@Sun.COM {
857*11489SPengcheng.Chen@Sun.COM 	usbwcm_copyin_t	*copystat;
858*11489SPengcheng.Chen@Sun.COM 	mblk_t		*iocmp, *contmp;
859*11489SPengcheng.Chen@Sun.COM 	struct copyreq	*cq;
860*11489SPengcheng.Chen@Sun.COM 	struct copyresp	*cr;
861*11489SPengcheng.Chen@Sun.COM 
862*11489SPengcheng.Chen@Sun.COM 	if ((pvtsize == 0) && (state != 0)) {
863*11489SPengcheng.Chen@Sun.COM 		cr = (struct copyresp *)mp->b_rptr;
864*11489SPengcheng.Chen@Sun.COM 		iocmp = cr->cp_private;
865*11489SPengcheng.Chen@Sun.COM 	}
866*11489SPengcheng.Chen@Sun.COM 
867*11489SPengcheng.Chen@Sun.COM 	cq = (struct copyreq *)mp->b_rptr;
868*11489SPengcheng.Chen@Sun.COM 	if (mp->b_cont == NULL) {
869*11489SPengcheng.Chen@Sun.COM 
870*11489SPengcheng.Chen@Sun.COM 		return (EINVAL);
871*11489SPengcheng.Chen@Sun.COM 	}
872*11489SPengcheng.Chen@Sun.COM 
873*11489SPengcheng.Chen@Sun.COM 	cq->cq_addr = *((caddr_t *)mp->b_cont->b_rptr);
874*11489SPengcheng.Chen@Sun.COM 	cq->cq_size = reqsize;
875*11489SPengcheng.Chen@Sun.COM 	cq->cq_flag = 0;
876*11489SPengcheng.Chen@Sun.COM 
877*11489SPengcheng.Chen@Sun.COM 	if (pvtsize) {
878*11489SPengcheng.Chen@Sun.COM 		iocmp = (mblk_t *)allocb(pvtsize, BPRI_MED);
879*11489SPengcheng.Chen@Sun.COM 		if (iocmp == NULL) {
880*11489SPengcheng.Chen@Sun.COM 
881*11489SPengcheng.Chen@Sun.COM 			return (EAGAIN);
882*11489SPengcheng.Chen@Sun.COM 		}
883*11489SPengcheng.Chen@Sun.COM 		cq->cq_private = iocmp;
884*11489SPengcheng.Chen@Sun.COM 		iocmp = cq->cq_private;
885*11489SPengcheng.Chen@Sun.COM 	} else {
886*11489SPengcheng.Chen@Sun.COM 		/*
887*11489SPengcheng.Chen@Sun.COM 		 * Here we need to set cq_private even if there's
888*11489SPengcheng.Chen@Sun.COM 		 * no private data, otherwise its value will be
889*11489SPengcheng.Chen@Sun.COM 		 * TRANSPARENT (-1) on 64bit systems because it
890*11489SPengcheng.Chen@Sun.COM 		 * overlaps iocp->ioc_count. If user address (cq_addr)
891*11489SPengcheng.Chen@Sun.COM 		 * is invalid, it would cause panic later in
892*11489SPengcheng.Chen@Sun.COM 		 * usbwcm_copyin:
893*11489SPengcheng.Chen@Sun.COM 		 * 	freemsg((mblk_t *)copyresp->cp_private);
894*11489SPengcheng.Chen@Sun.COM 		 */
895*11489SPengcheng.Chen@Sun.COM 		cq->cq_private = NULL;
896*11489SPengcheng.Chen@Sun.COM 	}
897*11489SPengcheng.Chen@Sun.COM 
898*11489SPengcheng.Chen@Sun.COM 	if (state) {
899*11489SPengcheng.Chen@Sun.COM 		copystat = (usbwcm_copyin_t *)iocmp->b_rptr;
900*11489SPengcheng.Chen@Sun.COM 		copystat->state = state;
901*11489SPengcheng.Chen@Sun.COM 		if (pvtsize) {  /* M_COPYIN */
902*11489SPengcheng.Chen@Sun.COM 			copystat->addr = cq->cq_addr;
903*11489SPengcheng.Chen@Sun.COM 		} else {
904*11489SPengcheng.Chen@Sun.COM 			cq->cq_addr = copystat->addr;
905*11489SPengcheng.Chen@Sun.COM 			cq->cq_private = iocmp;
906*11489SPengcheng.Chen@Sun.COM 		}
907*11489SPengcheng.Chen@Sun.COM 		iocmp->b_wptr = iocmp->b_rptr + sizeof (usbwcm_copyin_t);
908*11489SPengcheng.Chen@Sun.COM 	}
909*11489SPengcheng.Chen@Sun.COM 
910*11489SPengcheng.Chen@Sun.COM 	if (contsize) {
911*11489SPengcheng.Chen@Sun.COM 		contmp = (mblk_t *)allocb(contsize, BPRI_MED);
912*11489SPengcheng.Chen@Sun.COM 		if (contmp == NULL) {
913*11489SPengcheng.Chen@Sun.COM 
914*11489SPengcheng.Chen@Sun.COM 			return (EAGAIN);
915*11489SPengcheng.Chen@Sun.COM 		}
916*11489SPengcheng.Chen@Sun.COM 		if (mp->b_cont) {
917*11489SPengcheng.Chen@Sun.COM 			freemsg(mp->b_cont);
918*11489SPengcheng.Chen@Sun.COM 			mp->b_cont = contmp;
919*11489SPengcheng.Chen@Sun.COM 		}
920*11489SPengcheng.Chen@Sun.COM 	}
921*11489SPengcheng.Chen@Sun.COM 
922*11489SPengcheng.Chen@Sun.COM 	mp->b_datap->db_type = (unsigned char)copytype;
923*11489SPengcheng.Chen@Sun.COM 	mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
924*11489SPengcheng.Chen@Sun.COM 
925*11489SPengcheng.Chen@Sun.COM 	return (0);
926*11489SPengcheng.Chen@Sun.COM }
927*11489SPengcheng.Chen@Sun.COM 
928*11489SPengcheng.Chen@Sun.COM static void
usbwcm_miocack(queue_t * q,mblk_t * mp,int rval)929*11489SPengcheng.Chen@Sun.COM usbwcm_miocack(queue_t *q, mblk_t *mp, int rval)
930*11489SPengcheng.Chen@Sun.COM {
931*11489SPengcheng.Chen@Sun.COM 	struct iocblk	*iocbp = (struct iocblk *)mp->b_rptr;
932*11489SPengcheng.Chen@Sun.COM 
933*11489SPengcheng.Chen@Sun.COM 	mp->b_datap->db_type = M_IOCACK;
934*11489SPengcheng.Chen@Sun.COM 	mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
935*11489SPengcheng.Chen@Sun.COM 
936*11489SPengcheng.Chen@Sun.COM 	iocbp->ioc_error = 0;
937*11489SPengcheng.Chen@Sun.COM 	iocbp->ioc_count = 0;
938*11489SPengcheng.Chen@Sun.COM 	iocbp->ioc_rval = rval;
939*11489SPengcheng.Chen@Sun.COM 
940*11489SPengcheng.Chen@Sun.COM 	if (mp->b_cont != NULL) {
941*11489SPengcheng.Chen@Sun.COM 		freemsg(mp->b_cont);
942*11489SPengcheng.Chen@Sun.COM 		mp->b_cont = NULL;
943*11489SPengcheng.Chen@Sun.COM 	}
944*11489SPengcheng.Chen@Sun.COM 
945*11489SPengcheng.Chen@Sun.COM 	qreply(q, mp);
946*11489SPengcheng.Chen@Sun.COM }
947*11489SPengcheng.Chen@Sun.COM 
948*11489SPengcheng.Chen@Sun.COM /*
949*11489SPengcheng.Chen@Sun.COM  * usbwcm_iocpy() :
950*11489SPengcheng.Chen@Sun.COM  * M_IOCDATA processing for IOCTL's
951*11489SPengcheng.Chen@Sun.COM  */
952*11489SPengcheng.Chen@Sun.COM static void
usbwcm_iocpy(queue_t * q,mblk_t * mp)953*11489SPengcheng.Chen@Sun.COM usbwcm_iocpy(queue_t *q, mblk_t *mp)
954*11489SPengcheng.Chen@Sun.COM {
955*11489SPengcheng.Chen@Sun.COM 	usbwcm_state_t		*usbwcmp = (usbwcm_state_t *)q->q_ptr;
956*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
957*11489SPengcheng.Chen@Sun.COM 	struct copyresp		*copyresp;
958*11489SPengcheng.Chen@Sun.COM 	usbwcm_copyin_t 	*copystat;
959*11489SPengcheng.Chen@Sun.COM 	mblk_t			*datap, *ioctmp;
960*11489SPengcheng.Chen@Sun.COM 	struct iocblk		*iocbp;
961*11489SPengcheng.Chen@Sun.COM 	int			err = 0;
962*11489SPengcheng.Chen@Sun.COM 
963*11489SPengcheng.Chen@Sun.COM 	copyresp = (struct copyresp *)mp->b_rptr;
964*11489SPengcheng.Chen@Sun.COM 	iocbp = (struct iocblk *)mp->b_rptr;
965*11489SPengcheng.Chen@Sun.COM 	if (copyresp->cp_rval) {
966*11489SPengcheng.Chen@Sun.COM 		err = EAGAIN;
967*11489SPengcheng.Chen@Sun.COM 
968*11489SPengcheng.Chen@Sun.COM 		goto out;
969*11489SPengcheng.Chen@Sun.COM 	}
970*11489SPengcheng.Chen@Sun.COM 
971*11489SPengcheng.Chen@Sun.COM 	switch (copyresp->cp_cmd) {
972*11489SPengcheng.Chen@Sun.COM 	default: {
973*11489SPengcheng.Chen@Sun.COM 		int num = copyresp->cp_cmd & 0xff;
974*11489SPengcheng.Chen@Sun.COM 		int len = IOCPARM_MASK & (copyresp->cp_cmd >> 16);
975*11489SPengcheng.Chen@Sun.COM 
976*11489SPengcheng.Chen@Sun.COM 		if (((copyresp->cp_cmd >> 8) & 0xFF) != 'E') {
977*11489SPengcheng.Chen@Sun.COM 			putnext(q, mp); /* pass it down the line */
978*11489SPengcheng.Chen@Sun.COM 			return;
979*11489SPengcheng.Chen@Sun.COM 
980*11489SPengcheng.Chen@Sun.COM 		} else if ((copyresp->cp_cmd & IOC_INOUT) != IOC_OUT) {
981*11489SPengcheng.Chen@Sun.COM 			err = EINVAL;
982*11489SPengcheng.Chen@Sun.COM 			break;
983*11489SPengcheng.Chen@Sun.COM 		}
984*11489SPengcheng.Chen@Sun.COM 
985*11489SPengcheng.Chen@Sun.COM 		switch (num) {
986*11489SPengcheng.Chen@Sun.COM 		case EUWACOMGETVERSION:
987*11489SPengcheng.Chen@Sun.COM 			ioctmp = copyresp->cp_private;
988*11489SPengcheng.Chen@Sun.COM 			copystat = (usbwcm_copyin_t *)ioctmp->b_rptr;
989*11489SPengcheng.Chen@Sun.COM 			if (copystat->state == USBWCM_GETSTRUCT) {
990*11489SPengcheng.Chen@Sun.COM 				if (mp->b_cont == NULL) {
991*11489SPengcheng.Chen@Sun.COM 					err = EINVAL;
992*11489SPengcheng.Chen@Sun.COM 
993*11489SPengcheng.Chen@Sun.COM 					break;
994*11489SPengcheng.Chen@Sun.COM 				}
995*11489SPengcheng.Chen@Sun.COM 				datap = (mblk_t *)mp->b_cont;
996*11489SPengcheng.Chen@Sun.COM 
997*11489SPengcheng.Chen@Sun.COM 				*(int *)datap->b_rptr = 0x00010000;
998*11489SPengcheng.Chen@Sun.COM 
999*11489SPengcheng.Chen@Sun.COM 				if (err = usbwcm_copyreq(mp, 0,
1000*11489SPengcheng.Chen@Sun.COM 				    USBWCM_GETRESULT, sizeof (int), 0,
1001*11489SPengcheng.Chen@Sun.COM 				    M_COPYOUT)) {
1002*11489SPengcheng.Chen@Sun.COM 
1003*11489SPengcheng.Chen@Sun.COM 					goto out;
1004*11489SPengcheng.Chen@Sun.COM 				}
1005*11489SPengcheng.Chen@Sun.COM 			} else if (copystat->state == USBWCM_GETRESULT) {
1006*11489SPengcheng.Chen@Sun.COM 				freemsg(ioctmp);
1007*11489SPengcheng.Chen@Sun.COM 				usbwcm_miocack(q, mp, 0);
1008*11489SPengcheng.Chen@Sun.COM 				return;
1009*11489SPengcheng.Chen@Sun.COM 			}
1010*11489SPengcheng.Chen@Sun.COM 			break;
1011*11489SPengcheng.Chen@Sun.COM 
1012*11489SPengcheng.Chen@Sun.COM 		case EUWACOMGETID:
1013*11489SPengcheng.Chen@Sun.COM 			ioctmp = copyresp->cp_private;
1014*11489SPengcheng.Chen@Sun.COM 			copystat = (usbwcm_copyin_t *)ioctmp->b_rptr;
1015*11489SPengcheng.Chen@Sun.COM 			if (copystat->state == USBWCM_GETSTRUCT) {
1016*11489SPengcheng.Chen@Sun.COM 				if (mp->b_cont == NULL) {
1017*11489SPengcheng.Chen@Sun.COM 					err = EINVAL;
1018*11489SPengcheng.Chen@Sun.COM 
1019*11489SPengcheng.Chen@Sun.COM 					break;
1020*11489SPengcheng.Chen@Sun.COM 				}
1021*11489SPengcheng.Chen@Sun.COM 				datap = (mblk_t *)mp->b_cont;
1022*11489SPengcheng.Chen@Sun.COM 
1023*11489SPengcheng.Chen@Sun.COM 				bcopy(&sc->sc_id, datap->b_rptr,
1024*11489SPengcheng.Chen@Sun.COM 				    sizeof (struct event_dev_id));
1025*11489SPengcheng.Chen@Sun.COM 
1026*11489SPengcheng.Chen@Sun.COM 				if (err = usbwcm_copyreq(mp, 0,
1027*11489SPengcheng.Chen@Sun.COM 				    USBWCM_GETRESULT,
1028*11489SPengcheng.Chen@Sun.COM 				    sizeof (struct event_dev_id), 0,
1029*11489SPengcheng.Chen@Sun.COM 				    M_COPYOUT)) {
1030*11489SPengcheng.Chen@Sun.COM 
1031*11489SPengcheng.Chen@Sun.COM 					goto out;
1032*11489SPengcheng.Chen@Sun.COM 				}
1033*11489SPengcheng.Chen@Sun.COM 			} else if (copystat->state == USBWCM_GETRESULT) {
1034*11489SPengcheng.Chen@Sun.COM 				freemsg(ioctmp);
1035*11489SPengcheng.Chen@Sun.COM 				usbwcm_miocack(q, mp, 0);
1036*11489SPengcheng.Chen@Sun.COM 				return;
1037*11489SPengcheng.Chen@Sun.COM 			}
1038*11489SPengcheng.Chen@Sun.COM 			break;
1039*11489SPengcheng.Chen@Sun.COM 
1040*11489SPengcheng.Chen@Sun.COM 		default:
1041*11489SPengcheng.Chen@Sun.COM 			if (num >= EUWACOMGETBM &&
1042*11489SPengcheng.Chen@Sun.COM 			    num < EUWACOMGETBM + EVT_USED) {
1043*11489SPengcheng.Chen@Sun.COM 				int idx = num - EUWACOMGETBM;
1044*11489SPengcheng.Chen@Sun.COM 				size_t length = min(bm_size[idx], len);
1045*11489SPengcheng.Chen@Sun.COM 
1046*11489SPengcheng.Chen@Sun.COM 				ioctmp = copyresp->cp_private;
1047*11489SPengcheng.Chen@Sun.COM 				copystat = (usbwcm_copyin_t *)ioctmp->b_rptr;
1048*11489SPengcheng.Chen@Sun.COM 				if (copystat->state == USBWCM_GETSTRUCT) {
1049*11489SPengcheng.Chen@Sun.COM 					if (mp->b_cont == NULL) {
1050*11489SPengcheng.Chen@Sun.COM 						err = EINVAL;
1051*11489SPengcheng.Chen@Sun.COM 
1052*11489SPengcheng.Chen@Sun.COM 						break;
1053*11489SPengcheng.Chen@Sun.COM 					}
1054*11489SPengcheng.Chen@Sun.COM 					datap = (mblk_t *)mp->b_cont;
1055*11489SPengcheng.Chen@Sun.COM 
1056*11489SPengcheng.Chen@Sun.COM 					bcopy(sc->sc_bm[idx], datap->b_rptr,
1057*11489SPengcheng.Chen@Sun.COM 					    length);
1058*11489SPengcheng.Chen@Sun.COM 
1059*11489SPengcheng.Chen@Sun.COM 					if (err = usbwcm_copyreq(mp, 0,
1060*11489SPengcheng.Chen@Sun.COM 					    USBWCM_GETRESULT, length, 0,
1061*11489SPengcheng.Chen@Sun.COM 					    M_COPYOUT)) {
1062*11489SPengcheng.Chen@Sun.COM 
1063*11489SPengcheng.Chen@Sun.COM 						goto out;
1064*11489SPengcheng.Chen@Sun.COM 					}
1065*11489SPengcheng.Chen@Sun.COM 
1066*11489SPengcheng.Chen@Sun.COM 				} else if (copystat->state ==
1067*11489SPengcheng.Chen@Sun.COM 				    USBWCM_GETRESULT) {
1068*11489SPengcheng.Chen@Sun.COM 					freemsg(ioctmp);
1069*11489SPengcheng.Chen@Sun.COM 					usbwcm_miocack(q, mp, length);
1070*11489SPengcheng.Chen@Sun.COM 					return;
1071*11489SPengcheng.Chen@Sun.COM 				}
1072*11489SPengcheng.Chen@Sun.COM 				break;
1073*11489SPengcheng.Chen@Sun.COM 
1074*11489SPengcheng.Chen@Sun.COM 			} else if (num >= EUWACOMGETABS &&
1075*11489SPengcheng.Chen@Sun.COM 			    num < EUWACOMGETABS + ABS_USED) {
1076*11489SPengcheng.Chen@Sun.COM 				int idx = num - EUWACOMGETABS;
1077*11489SPengcheng.Chen@Sun.COM 
1078*11489SPengcheng.Chen@Sun.COM 				ioctmp = copyresp->cp_private;
1079*11489SPengcheng.Chen@Sun.COM 				copystat = (usbwcm_copyin_t *)ioctmp->b_rptr;
1080*11489SPengcheng.Chen@Sun.COM 				if (copystat->state == USBWCM_GETSTRUCT) {
1081*11489SPengcheng.Chen@Sun.COM 					if (mp->b_cont == NULL) {
1082*11489SPengcheng.Chen@Sun.COM 						err = EINVAL;
1083*11489SPengcheng.Chen@Sun.COM 
1084*11489SPengcheng.Chen@Sun.COM 						break;
1085*11489SPengcheng.Chen@Sun.COM 					}
1086*11489SPengcheng.Chen@Sun.COM 					datap = (mblk_t *)mp->b_cont;
1087*11489SPengcheng.Chen@Sun.COM 
1088*11489SPengcheng.Chen@Sun.COM 					bcopy(&sc->sc_abs[idx], datap->b_rptr,
1089*11489SPengcheng.Chen@Sun.COM 					    sizeof (struct event_abs_axis));
1090*11489SPengcheng.Chen@Sun.COM 
1091*11489SPengcheng.Chen@Sun.COM 					if (err = usbwcm_copyreq(mp, 0,
1092*11489SPengcheng.Chen@Sun.COM 					    USBWCM_GETRESULT,
1093*11489SPengcheng.Chen@Sun.COM 					    sizeof (struct event_abs_axis), 0,
1094*11489SPengcheng.Chen@Sun.COM 					    M_COPYOUT)) {
1095*11489SPengcheng.Chen@Sun.COM 
1096*11489SPengcheng.Chen@Sun.COM 						goto out;
1097*11489SPengcheng.Chen@Sun.COM 					}
1098*11489SPengcheng.Chen@Sun.COM 
1099*11489SPengcheng.Chen@Sun.COM 				} else if (copystat->state ==
1100*11489SPengcheng.Chen@Sun.COM 				    USBWCM_GETRESULT) {
1101*11489SPengcheng.Chen@Sun.COM 					freemsg(ioctmp);
1102*11489SPengcheng.Chen@Sun.COM 					usbwcm_miocack(q, mp, 0);
1103*11489SPengcheng.Chen@Sun.COM 					return;
1104*11489SPengcheng.Chen@Sun.COM 				}
1105*11489SPengcheng.Chen@Sun.COM 				break;
1106*11489SPengcheng.Chen@Sun.COM 
1107*11489SPengcheng.Chen@Sun.COM 			} else {
1108*11489SPengcheng.Chen@Sun.COM 				err = EINVAL;
1109*11489SPengcheng.Chen@Sun.COM 				break;
1110*11489SPengcheng.Chen@Sun.COM 			}
1111*11489SPengcheng.Chen@Sun.COM 		}
1112*11489SPengcheng.Chen@Sun.COM 	}
1113*11489SPengcheng.Chen@Sun.COM 	}
1114*11489SPengcheng.Chen@Sun.COM 
1115*11489SPengcheng.Chen@Sun.COM out:
1116*11489SPengcheng.Chen@Sun.COM 	if (err) {
1117*11489SPengcheng.Chen@Sun.COM 		mp->b_datap->db_type = M_IOCNAK;
1118*11489SPengcheng.Chen@Sun.COM 		if (mp->b_cont) {
1119*11489SPengcheng.Chen@Sun.COM 			freemsg(mp->b_cont);
1120*11489SPengcheng.Chen@Sun.COM 			mp->b_cont = (mblk_t *)NULL;
1121*11489SPengcheng.Chen@Sun.COM 		}
1122*11489SPengcheng.Chen@Sun.COM 		if (copyresp->cp_private) {
1123*11489SPengcheng.Chen@Sun.COM 			freemsg((mblk_t *)copyresp->cp_private);
1124*11489SPengcheng.Chen@Sun.COM 			copyresp->cp_private = (mblk_t *)NULL;
1125*11489SPengcheng.Chen@Sun.COM 		}
1126*11489SPengcheng.Chen@Sun.COM 		iocbp->ioc_count = 0;
1127*11489SPengcheng.Chen@Sun.COM 		iocbp->ioc_error = err;
1128*11489SPengcheng.Chen@Sun.COM 	}
1129*11489SPengcheng.Chen@Sun.COM 
1130*11489SPengcheng.Chen@Sun.COM 	qreply(q, mp);
1131*11489SPengcheng.Chen@Sun.COM }
1132*11489SPengcheng.Chen@Sun.COM 
1133*11489SPengcheng.Chen@Sun.COM /*
1134*11489SPengcheng.Chen@Sun.COM  * usbwcm_ioctl() :
1135*11489SPengcheng.Chen@Sun.COM  *	Process ioctls we recognize and own.  Otherwise, NAK.
1136*11489SPengcheng.Chen@Sun.COM  */
1137*11489SPengcheng.Chen@Sun.COM static void
usbwcm_ioctl(queue_t * q,mblk_t * mp)1138*11489SPengcheng.Chen@Sun.COM usbwcm_ioctl(queue_t *q, mblk_t *mp)
1139*11489SPengcheng.Chen@Sun.COM {
1140*11489SPengcheng.Chen@Sun.COM 	usbwcm_state_t		*usbwcmp = (usbwcm_state_t *)q->q_ptr;
1141*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc	*sc;
1142*11489SPengcheng.Chen@Sun.COM 	mblk_t			*datap;
1143*11489SPengcheng.Chen@Sun.COM 	struct iocblk		*iocp;
1144*11489SPengcheng.Chen@Sun.COM 	int			err = 0;
1145*11489SPengcheng.Chen@Sun.COM 
1146*11489SPengcheng.Chen@Sun.COM 	if (usbwcmp == NULL) {
1147*11489SPengcheng.Chen@Sun.COM 		miocnak(q, mp, 0, EINVAL);
1148*11489SPengcheng.Chen@Sun.COM 		return;
1149*11489SPengcheng.Chen@Sun.COM 	}
1150*11489SPengcheng.Chen@Sun.COM 
1151*11489SPengcheng.Chen@Sun.COM 	sc = &usbwcmp->usbwcm_softc;
1152*11489SPengcheng.Chen@Sun.COM 	iocp = (struct iocblk *)mp->b_rptr;
1153*11489SPengcheng.Chen@Sun.COM 
1154*11489SPengcheng.Chen@Sun.COM 	switch (iocp->ioc_cmd) {
1155*11489SPengcheng.Chen@Sun.COM 	default: {
1156*11489SPengcheng.Chen@Sun.COM 		int num = iocp->ioc_cmd & 0xff;
1157*11489SPengcheng.Chen@Sun.COM 		int len = IOCPARM_MASK & (iocp->ioc_cmd >> 16);
1158*11489SPengcheng.Chen@Sun.COM 
1159*11489SPengcheng.Chen@Sun.COM 		if (((iocp->ioc_cmd >> 8) & 0xFF) != 'E') {
1160*11489SPengcheng.Chen@Sun.COM 			putnext(q, mp); /* pass it down the line */
1161*11489SPengcheng.Chen@Sun.COM 			return;
1162*11489SPengcheng.Chen@Sun.COM 
1163*11489SPengcheng.Chen@Sun.COM 		} else if ((iocp->ioc_cmd & IOC_INOUT) != IOC_OUT) {
1164*11489SPengcheng.Chen@Sun.COM 			err = EINVAL;
1165*11489SPengcheng.Chen@Sun.COM 			break;
1166*11489SPengcheng.Chen@Sun.COM 		}
1167*11489SPengcheng.Chen@Sun.COM 
1168*11489SPengcheng.Chen@Sun.COM 		switch (num) {
1169*11489SPengcheng.Chen@Sun.COM 		case EUWACOMGETVERSION:
1170*11489SPengcheng.Chen@Sun.COM 			if (iocp->ioc_count == TRANSPARENT) {
1171*11489SPengcheng.Chen@Sun.COM 				if (err = usbwcm_copyreq(mp,
1172*11489SPengcheng.Chen@Sun.COM 				    sizeof (usbwcm_copyin_t), USBWCM_GETSTRUCT,
1173*11489SPengcheng.Chen@Sun.COM 				    sizeof (int), 0, M_COPYIN)) {
1174*11489SPengcheng.Chen@Sun.COM 					break;
1175*11489SPengcheng.Chen@Sun.COM 				}
1176*11489SPengcheng.Chen@Sun.COM 				freemsg(mp->b_cont);
1177*11489SPengcheng.Chen@Sun.COM 				mp->b_cont = (mblk_t *)NULL;
1178*11489SPengcheng.Chen@Sun.COM 
1179*11489SPengcheng.Chen@Sun.COM 				qreply(q, mp);
1180*11489SPengcheng.Chen@Sun.COM 				return;
1181*11489SPengcheng.Chen@Sun.COM 			}
1182*11489SPengcheng.Chen@Sun.COM 
1183*11489SPengcheng.Chen@Sun.COM 			if (mp->b_cont == NULL ||
1184*11489SPengcheng.Chen@Sun.COM 			    iocp->ioc_count != sizeof (int)) {
1185*11489SPengcheng.Chen@Sun.COM 				err = EINVAL;
1186*11489SPengcheng.Chen@Sun.COM 				break;
1187*11489SPengcheng.Chen@Sun.COM 			}
1188*11489SPengcheng.Chen@Sun.COM 			datap = mp->b_cont;
1189*11489SPengcheng.Chen@Sun.COM 
1190*11489SPengcheng.Chen@Sun.COM 			*(int *)datap->b_rptr = 0x00010000;
1191*11489SPengcheng.Chen@Sun.COM 
1192*11489SPengcheng.Chen@Sun.COM 			break;
1193*11489SPengcheng.Chen@Sun.COM 
1194*11489SPengcheng.Chen@Sun.COM 		case EUWACOMGETID:
1195*11489SPengcheng.Chen@Sun.COM 			if (iocp->ioc_count == TRANSPARENT) {
1196*11489SPengcheng.Chen@Sun.COM 				if (err = usbwcm_copyreq(mp,
1197*11489SPengcheng.Chen@Sun.COM 				    sizeof (usbwcm_copyin_t), USBWCM_GETSTRUCT,
1198*11489SPengcheng.Chen@Sun.COM 				    sizeof (struct event_dev_id), 0,
1199*11489SPengcheng.Chen@Sun.COM 				    M_COPYIN)) {
1200*11489SPengcheng.Chen@Sun.COM 					break;
1201*11489SPengcheng.Chen@Sun.COM 				}
1202*11489SPengcheng.Chen@Sun.COM 				freemsg(mp->b_cont);
1203*11489SPengcheng.Chen@Sun.COM 				mp->b_cont = (mblk_t *)NULL;
1204*11489SPengcheng.Chen@Sun.COM 
1205*11489SPengcheng.Chen@Sun.COM 				qreply(q, mp);
1206*11489SPengcheng.Chen@Sun.COM 				return;
1207*11489SPengcheng.Chen@Sun.COM 			}
1208*11489SPengcheng.Chen@Sun.COM 
1209*11489SPengcheng.Chen@Sun.COM 			if (mp->b_cont == NULL ||
1210*11489SPengcheng.Chen@Sun.COM 			    iocp->ioc_count != sizeof (struct event_dev_id)) {
1211*11489SPengcheng.Chen@Sun.COM 				err = EINVAL;
1212*11489SPengcheng.Chen@Sun.COM 				break;
1213*11489SPengcheng.Chen@Sun.COM 			}
1214*11489SPengcheng.Chen@Sun.COM 			datap = mp->b_cont;
1215*11489SPengcheng.Chen@Sun.COM 
1216*11489SPengcheng.Chen@Sun.COM 			bcopy(&sc->sc_id, datap->b_rptr,
1217*11489SPengcheng.Chen@Sun.COM 			    sizeof (struct event_dev_id));
1218*11489SPengcheng.Chen@Sun.COM 
1219*11489SPengcheng.Chen@Sun.COM 			break;
1220*11489SPengcheng.Chen@Sun.COM 
1221*11489SPengcheng.Chen@Sun.COM 		default:
1222*11489SPengcheng.Chen@Sun.COM 			if (num >= EUWACOMGETBM &&
1223*11489SPengcheng.Chen@Sun.COM 			    num < EUWACOMGETBM + EVT_USED) {
1224*11489SPengcheng.Chen@Sun.COM 				int idx = num - EUWACOMGETBM;
1225*11489SPengcheng.Chen@Sun.COM 				size_t length = min(bm_size[idx], len);
1226*11489SPengcheng.Chen@Sun.COM 
1227*11489SPengcheng.Chen@Sun.COM 				if (iocp->ioc_count == TRANSPARENT) {
1228*11489SPengcheng.Chen@Sun.COM 					if (err = usbwcm_copyreq(mp,
1229*11489SPengcheng.Chen@Sun.COM 					    sizeof (usbwcm_copyin_t),
1230*11489SPengcheng.Chen@Sun.COM 					    USBWCM_GETSTRUCT, length, 0,
1231*11489SPengcheng.Chen@Sun.COM 					    M_COPYIN)) {
1232*11489SPengcheng.Chen@Sun.COM 						break;
1233*11489SPengcheng.Chen@Sun.COM 					}
1234*11489SPengcheng.Chen@Sun.COM 					freemsg(mp->b_cont);
1235*11489SPengcheng.Chen@Sun.COM 					mp->b_cont = (mblk_t *)NULL;
1236*11489SPengcheng.Chen@Sun.COM 
1237*11489SPengcheng.Chen@Sun.COM 					qreply(q, mp);
1238*11489SPengcheng.Chen@Sun.COM 					return;
1239*11489SPengcheng.Chen@Sun.COM 				}
1240*11489SPengcheng.Chen@Sun.COM 
1241*11489SPengcheng.Chen@Sun.COM 				if (mp->b_cont == NULL ||
1242*11489SPengcheng.Chen@Sun.COM 				    iocp->ioc_count != length) {
1243*11489SPengcheng.Chen@Sun.COM 					err = EINVAL;
1244*11489SPengcheng.Chen@Sun.COM 					break;
1245*11489SPengcheng.Chen@Sun.COM 				}
1246*11489SPengcheng.Chen@Sun.COM 				datap = mp->b_cont;
1247*11489SPengcheng.Chen@Sun.COM 
1248*11489SPengcheng.Chen@Sun.COM 				bcopy(sc->sc_bm[idx], datap->b_rptr, length);
1249*11489SPengcheng.Chen@Sun.COM 
1250*11489SPengcheng.Chen@Sun.COM 				break;
1251*11489SPengcheng.Chen@Sun.COM 
1252*11489SPengcheng.Chen@Sun.COM 			} else if (num >= EUWACOMGETABS &&
1253*11489SPengcheng.Chen@Sun.COM 			    num < EUWACOMGETABS + ABS_USED) {
1254*11489SPengcheng.Chen@Sun.COM 				int idx = num - EUWACOMGETABS;
1255*11489SPengcheng.Chen@Sun.COM 
1256*11489SPengcheng.Chen@Sun.COM 				if (iocp->ioc_count == TRANSPARENT) {
1257*11489SPengcheng.Chen@Sun.COM 					if (err = usbwcm_copyreq(mp,
1258*11489SPengcheng.Chen@Sun.COM 					    sizeof (usbwcm_copyin_t),
1259*11489SPengcheng.Chen@Sun.COM 					    USBWCM_GETSTRUCT,
1260*11489SPengcheng.Chen@Sun.COM 					    sizeof (struct event_abs_axis), 0,
1261*11489SPengcheng.Chen@Sun.COM 					    M_COPYIN)) {
1262*11489SPengcheng.Chen@Sun.COM 						break;
1263*11489SPengcheng.Chen@Sun.COM 					}
1264*11489SPengcheng.Chen@Sun.COM 					freemsg(mp->b_cont);
1265*11489SPengcheng.Chen@Sun.COM 					mp->b_cont = (mblk_t *)NULL;
1266*11489SPengcheng.Chen@Sun.COM 
1267*11489SPengcheng.Chen@Sun.COM 					qreply(q, mp);
1268*11489SPengcheng.Chen@Sun.COM 					return;
1269*11489SPengcheng.Chen@Sun.COM 				}
1270*11489SPengcheng.Chen@Sun.COM 
1271*11489SPengcheng.Chen@Sun.COM 				if (mp->b_cont == NULL ||
1272*11489SPengcheng.Chen@Sun.COM 				    iocp->ioc_count !=
1273*11489SPengcheng.Chen@Sun.COM 				    sizeof (struct event_abs_axis)) {
1274*11489SPengcheng.Chen@Sun.COM 					err = EINVAL;
1275*11489SPengcheng.Chen@Sun.COM 					break;
1276*11489SPengcheng.Chen@Sun.COM 				}
1277*11489SPengcheng.Chen@Sun.COM 				datap = mp->b_cont;
1278*11489SPengcheng.Chen@Sun.COM 
1279*11489SPengcheng.Chen@Sun.COM 				bcopy(&sc->sc_abs[idx], datap->b_rptr,
1280*11489SPengcheng.Chen@Sun.COM 				    sizeof (struct event_abs_axis));
1281*11489SPengcheng.Chen@Sun.COM 
1282*11489SPengcheng.Chen@Sun.COM 				break;
1283*11489SPengcheng.Chen@Sun.COM 
1284*11489SPengcheng.Chen@Sun.COM 			} else {
1285*11489SPengcheng.Chen@Sun.COM 				err = EINVAL;
1286*11489SPengcheng.Chen@Sun.COM 				break;
1287*11489SPengcheng.Chen@Sun.COM 			}
1288*11489SPengcheng.Chen@Sun.COM 		}
1289*11489SPengcheng.Chen@Sun.COM 	}
1290*11489SPengcheng.Chen@Sun.COM 	}
1291*11489SPengcheng.Chen@Sun.COM 
1292*11489SPengcheng.Chen@Sun.COM 	if (err != 0)
1293*11489SPengcheng.Chen@Sun.COM 		miocnak(q, mp, 0, err);
1294*11489SPengcheng.Chen@Sun.COM 	else {
1295*11489SPengcheng.Chen@Sun.COM 		iocp->ioc_rval = 0;
1296*11489SPengcheng.Chen@Sun.COM 		iocp->ioc_error = 0;
1297*11489SPengcheng.Chen@Sun.COM 		mp->b_datap->db_type = M_IOCACK;
1298*11489SPengcheng.Chen@Sun.COM 		qreply(q, mp);
1299*11489SPengcheng.Chen@Sun.COM 		/* REMOVE */
1300*11489SPengcheng.Chen@Sun.COM 	}
1301*11489SPengcheng.Chen@Sun.COM 
1302*11489SPengcheng.Chen@Sun.COM 	return;
1303*11489SPengcheng.Chen@Sun.COM 
1304*11489SPengcheng.Chen@Sun.COM }
1305*11489SPengcheng.Chen@Sun.COM 
1306*11489SPengcheng.Chen@Sun.COM /*
1307*11489SPengcheng.Chen@Sun.COM  * usbwcm_input() :
1308*11489SPengcheng.Chen@Sun.COM  *
1309*11489SPengcheng.Chen@Sun.COM  *	Wacom input routine; process data received from a device and
1310*11489SPengcheng.Chen@Sun.COM  *	assemble into a input event for the window system.
1311*11489SPengcheng.Chen@Sun.COM  *
1312*11489SPengcheng.Chen@Sun.COM  *	Watch out for overflow!
1313*11489SPengcheng.Chen@Sun.COM  */
1314*11489SPengcheng.Chen@Sun.COM static void
usbwcm_input(usbwcm_state_t * usbwcmp,mblk_t * mp)1315*11489SPengcheng.Chen@Sun.COM usbwcm_input(usbwcm_state_t *usbwcmp, mblk_t *mp)
1316*11489SPengcheng.Chen@Sun.COM {
1317*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
1318*11489SPengcheng.Chen@Sun.COM 
1319*11489SPengcheng.Chen@Sun.COM 	switch (sc->sc_type->protocol) {
1320*11489SPengcheng.Chen@Sun.COM 	case GRAPHIRE:
1321*11489SPengcheng.Chen@Sun.COM 	case GRAPHIRE4:
1322*11489SPengcheng.Chen@Sun.COM 	case MYOFFICE:
1323*11489SPengcheng.Chen@Sun.COM 		usbwcm_input_graphire(usbwcmp, mp);
1324*11489SPengcheng.Chen@Sun.COM 		break;
1325*11489SPengcheng.Chen@Sun.COM 
1326*11489SPengcheng.Chen@Sun.COM 	case INTUOS3S:
1327*11489SPengcheng.Chen@Sun.COM 	case INTUOS3L:
1328*11489SPengcheng.Chen@Sun.COM 	case INTUOS4S:
1329*11489SPengcheng.Chen@Sun.COM 	case INTUOS4L:
1330*11489SPengcheng.Chen@Sun.COM 	case CINTIQ:
1331*11489SPengcheng.Chen@Sun.COM 		usbwcm_input_intuos(usbwcmp, mp);
1332*11489SPengcheng.Chen@Sun.COM 		break;
1333*11489SPengcheng.Chen@Sun.COM 	}
1334*11489SPengcheng.Chen@Sun.COM }
1335*11489SPengcheng.Chen@Sun.COM 
1336*11489SPengcheng.Chen@Sun.COM /*
1337*11489SPengcheng.Chen@Sun.COM  * usbwcm_flush() :
1338*11489SPengcheng.Chen@Sun.COM  *	Resets the soft state to default values
1339*11489SPengcheng.Chen@Sun.COM  *	and sends M_FLUSH above.
1340*11489SPengcheng.Chen@Sun.COM  */
1341*11489SPengcheng.Chen@Sun.COM static void
usbwcm_flush(usbwcm_state_t * usbwcmp)1342*11489SPengcheng.Chen@Sun.COM usbwcm_flush(usbwcm_state_t *usbwcmp)
1343*11489SPengcheng.Chen@Sun.COM {
1344*11489SPengcheng.Chen@Sun.COM 	queue_t			*q;
1345*11489SPengcheng.Chen@Sun.COM 
1346*11489SPengcheng.Chen@Sun.COM 	if ((q = usbwcmp->usbwcm_rq) != NULL && q->q_next != NULL) {
1347*11489SPengcheng.Chen@Sun.COM 		(void) putnextctl1(q, M_FLUSH, FLUSHR);
1348*11489SPengcheng.Chen@Sun.COM 	}
1349*11489SPengcheng.Chen@Sun.COM }
1350*11489SPengcheng.Chen@Sun.COM 
1351*11489SPengcheng.Chen@Sun.COM /*
1352*11489SPengcheng.Chen@Sun.COM  * usbwcm_mctl() :
1353*11489SPengcheng.Chen@Sun.COM  *	Handle M_CTL messages from hid.  If
1354*11489SPengcheng.Chen@Sun.COM  *	we don't understand the command, free message.
1355*11489SPengcheng.Chen@Sun.COM  */
1356*11489SPengcheng.Chen@Sun.COM static void
usbwcm_mctl(queue_t * q,mblk_t * mp)1357*11489SPengcheng.Chen@Sun.COM usbwcm_mctl(queue_t *q, mblk_t *mp)
1358*11489SPengcheng.Chen@Sun.COM {
1359*11489SPengcheng.Chen@Sun.COM 	usbwcm_state_t	*usbwcmp = (usbwcm_state_t *)q->q_ptr;
1360*11489SPengcheng.Chen@Sun.COM 	struct iocblk	*iocp;
1361*11489SPengcheng.Chen@Sun.COM 	caddr_t		data = NULL;
1362*11489SPengcheng.Chen@Sun.COM 	struct iocblk	mctlmsg;
1363*11489SPengcheng.Chen@Sun.COM 	mblk_t		*mctl_ptr;
1364*11489SPengcheng.Chen@Sun.COM 	hid_req_t	*featr;
1365*11489SPengcheng.Chen@Sun.COM 
1366*11489SPengcheng.Chen@Sun.COM 	iocp = (struct iocblk *)mp->b_rptr;
1367*11489SPengcheng.Chen@Sun.COM 	if (mp->b_cont != NULL)
1368*11489SPengcheng.Chen@Sun.COM 		data = (caddr_t)mp->b_cont->b_rptr;
1369*11489SPengcheng.Chen@Sun.COM 
1370*11489SPengcheng.Chen@Sun.COM 	switch (iocp->ioc_cmd) {
1371*11489SPengcheng.Chen@Sun.COM 	case HID_GET_VID_PID:
1372*11489SPengcheng.Chen@Sun.COM 		if ((data != NULL) &&
1373*11489SPengcheng.Chen@Sun.COM 		    (iocp->ioc_count == sizeof (hid_vid_pid_t)) &&
1374*11489SPengcheng.Chen@Sun.COM 		    (MBLKL(mp->b_cont) == iocp->ioc_count)) {
1375*11489SPengcheng.Chen@Sun.COM 			bcopy(data, &usbwcmp->usbwcm_devid, iocp->ioc_count);
1376*11489SPengcheng.Chen@Sun.COM 		}
1377*11489SPengcheng.Chen@Sun.COM 
1378*11489SPengcheng.Chen@Sun.COM 		freemsg(mp);
1379*11489SPengcheng.Chen@Sun.COM 		usbwcmp->usbwcm_flags &= ~USBWCM_QWAIT;
1380*11489SPengcheng.Chen@Sun.COM 		break;
1381*11489SPengcheng.Chen@Sun.COM 
1382*11489SPengcheng.Chen@Sun.COM 	case HID_CONNECT_EVENT:
1383*11489SPengcheng.Chen@Sun.COM 		/* set feature: tablet mode */
1384*11489SPengcheng.Chen@Sun.COM 		featr = kmem_zalloc(sizeof (hid_req_t), KM_SLEEP);
1385*11489SPengcheng.Chen@Sun.COM 		featr->hid_req_version_no = HID_VERSION_V_0;
1386*11489SPengcheng.Chen@Sun.COM 		featr->hid_req_wValue = REPORT_TYPE_FEATURE | 2;
1387*11489SPengcheng.Chen@Sun.COM 		featr->hid_req_wLength = sizeof (uint8_t) * 2;
1388*11489SPengcheng.Chen@Sun.COM 		featr->hid_req_data[0] = 2;
1389*11489SPengcheng.Chen@Sun.COM 		featr->hid_req_data[1] = 2;
1390*11489SPengcheng.Chen@Sun.COM 
1391*11489SPengcheng.Chen@Sun.COM 		mctlmsg.ioc_cmd = HID_SET_REPORT;
1392*11489SPengcheng.Chen@Sun.COM 		mctlmsg.ioc_count = sizeof (featr);
1393*11489SPengcheng.Chen@Sun.COM 		mctl_ptr = usba_mk_mctl(mctlmsg, featr, sizeof (hid_req_t));
1394*11489SPengcheng.Chen@Sun.COM 		if (mctl_ptr != NULL) {
1395*11489SPengcheng.Chen@Sun.COM 			putnext(usbwcmp->usbwcm_wq, mctl_ptr);
1396*11489SPengcheng.Chen@Sun.COM 		} else {
1397*11489SPengcheng.Chen@Sun.COM 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
1398*11489SPengcheng.Chen@Sun.COM 		    "enable tablet mode failed\n");
1399*11489SPengcheng.Chen@Sun.COM 		}
1400*11489SPengcheng.Chen@Sun.COM 
1401*11489SPengcheng.Chen@Sun.COM 		kmem_free(featr, sizeof (hid_req_t));
1402*11489SPengcheng.Chen@Sun.COM 		freemsg(mp);
1403*11489SPengcheng.Chen@Sun.COM 		break;
1404*11489SPengcheng.Chen@Sun.COM 
1405*11489SPengcheng.Chen@Sun.COM 	case HID_SET_REPORT:
1406*11489SPengcheng.Chen@Sun.COM 		/* FALLTHRU */
1407*11489SPengcheng.Chen@Sun.COM 
1408*11489SPengcheng.Chen@Sun.COM 	case HID_SET_PROTOCOL:
1409*11489SPengcheng.Chen@Sun.COM 		usbwcmp->usbwcm_flags &= ~USBWCM_QWAIT;
1410*11489SPengcheng.Chen@Sun.COM 		/* FALLTHRU */
1411*11489SPengcheng.Chen@Sun.COM 
1412*11489SPengcheng.Chen@Sun.COM 	default:
1413*11489SPengcheng.Chen@Sun.COM 		freemsg(mp);
1414*11489SPengcheng.Chen@Sun.COM 	}
1415*11489SPengcheng.Chen@Sun.COM }
1416*11489SPengcheng.Chen@Sun.COM 
1417*11489SPengcheng.Chen@Sun.COM /*
1418*11489SPengcheng.Chen@Sun.COM  * usbwcm_open() :
1419*11489SPengcheng.Chen@Sun.COM  *	open() entry point for the USB wacom module.
1420*11489SPengcheng.Chen@Sun.COM  */
1421*11489SPengcheng.Chen@Sun.COM /*ARGSUSED*/
1422*11489SPengcheng.Chen@Sun.COM static int
usbwcm_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)1423*11489SPengcheng.Chen@Sun.COM usbwcm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
1424*11489SPengcheng.Chen@Sun.COM {
1425*11489SPengcheng.Chen@Sun.COM 	usbwcm_state_t	*usbwcmp;
1426*11489SPengcheng.Chen@Sun.COM 
1427*11489SPengcheng.Chen@Sun.COM 	/* Clone opens are not allowed */
1428*11489SPengcheng.Chen@Sun.COM 	if (sflag != MODOPEN)
1429*11489SPengcheng.Chen@Sun.COM 		return (EINVAL);
1430*11489SPengcheng.Chen@Sun.COM 
1431*11489SPengcheng.Chen@Sun.COM 	/* If the module is already open, just return */
1432*11489SPengcheng.Chen@Sun.COM 	if (q->q_ptr) {
1433*11489SPengcheng.Chen@Sun.COM 		return (0);
1434*11489SPengcheng.Chen@Sun.COM 	}
1435*11489SPengcheng.Chen@Sun.COM 
1436*11489SPengcheng.Chen@Sun.COM 	/* allocate usbwcm state structure */
1437*11489SPengcheng.Chen@Sun.COM 	usbwcmp = kmem_zalloc(sizeof (usbwcm_state_t), KM_SLEEP);
1438*11489SPengcheng.Chen@Sun.COM 
1439*11489SPengcheng.Chen@Sun.COM 	q->q_ptr = usbwcmp;
1440*11489SPengcheng.Chen@Sun.COM 	WR(q)->q_ptr = usbwcmp;
1441*11489SPengcheng.Chen@Sun.COM 
1442*11489SPengcheng.Chen@Sun.COM 	usbwcmp->usbwcm_rq = q;
1443*11489SPengcheng.Chen@Sun.COM 	usbwcmp->usbwcm_wq = WR(q);
1444*11489SPengcheng.Chen@Sun.COM 
1445*11489SPengcheng.Chen@Sun.COM 	qprocson(q);
1446*11489SPengcheng.Chen@Sun.COM 
1447*11489SPengcheng.Chen@Sun.COM 	if (usbwcm_probe(usbwcmp) != 0) {
1448*11489SPengcheng.Chen@Sun.COM 
1449*11489SPengcheng.Chen@Sun.COM 		qprocsoff(q);
1450*11489SPengcheng.Chen@Sun.COM 		kmem_free(usbwcmp, sizeof (usbwcm_state_t));
1451*11489SPengcheng.Chen@Sun.COM 
1452*11489SPengcheng.Chen@Sun.COM 		return (EINVAL);
1453*11489SPengcheng.Chen@Sun.COM 	}
1454*11489SPengcheng.Chen@Sun.COM 
1455*11489SPengcheng.Chen@Sun.COM 	usbwcm_flush(usbwcmp);
1456*11489SPengcheng.Chen@Sun.COM 
1457*11489SPengcheng.Chen@Sun.COM 	usbwcmp->usbwcm_flags |= USBWCM_OPEN;
1458*11489SPengcheng.Chen@Sun.COM 	return (0);
1459*11489SPengcheng.Chen@Sun.COM }
1460*11489SPengcheng.Chen@Sun.COM 
1461*11489SPengcheng.Chen@Sun.COM 
1462*11489SPengcheng.Chen@Sun.COM /*
1463*11489SPengcheng.Chen@Sun.COM  * usbwcm_close() :
1464*11489SPengcheng.Chen@Sun.COM  *	close() entry point for the USB wacom module.
1465*11489SPengcheng.Chen@Sun.COM  */
1466*11489SPengcheng.Chen@Sun.COM /*ARGSUSED*/
1467*11489SPengcheng.Chen@Sun.COM static int
usbwcm_close(queue_t * q,int flag,cred_t * credp)1468*11489SPengcheng.Chen@Sun.COM usbwcm_close(queue_t *q, int flag, cred_t *credp)
1469*11489SPengcheng.Chen@Sun.COM {
1470*11489SPengcheng.Chen@Sun.COM 	usbwcm_state_t		*usbwcmp = q->q_ptr;
1471*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
1472*11489SPengcheng.Chen@Sun.COM 
1473*11489SPengcheng.Chen@Sun.COM 	qprocsoff(q);
1474*11489SPengcheng.Chen@Sun.COM 
1475*11489SPengcheng.Chen@Sun.COM 	if (usbwcmp->usbwcm_bufcall) {
1476*11489SPengcheng.Chen@Sun.COM 		qunbufcall(q, (bufcall_id_t)(long)usbwcmp->usbwcm_bufcall);
1477*11489SPengcheng.Chen@Sun.COM 		usbwcmp->usbwcm_bufcall = 0;
1478*11489SPengcheng.Chen@Sun.COM 	}
1479*11489SPengcheng.Chen@Sun.COM 
1480*11489SPengcheng.Chen@Sun.COM 	if (usbwcmp->usbwcm_mioctl != NULL) {
1481*11489SPengcheng.Chen@Sun.COM 		/*
1482*11489SPengcheng.Chen@Sun.COM 		 * We were holding an "ioctl" response pending the
1483*11489SPengcheng.Chen@Sun.COM 		 * availability of an "mblk" to hold data to be passed up;
1484*11489SPengcheng.Chen@Sun.COM 		 * another "ioctl" came through, which means that "ioctl"
1485*11489SPengcheng.Chen@Sun.COM 		 * must have timed out or been aborted.
1486*11489SPengcheng.Chen@Sun.COM 		 */
1487*11489SPengcheng.Chen@Sun.COM 		freemsg(usbwcmp->usbwcm_mioctl);
1488*11489SPengcheng.Chen@Sun.COM 		usbwcmp->usbwcm_mioctl = NULL;
1489*11489SPengcheng.Chen@Sun.COM 	}
1490*11489SPengcheng.Chen@Sun.COM 
1491*11489SPengcheng.Chen@Sun.COM 	for (int i = 0; i < EVT_USED; i++)
1492*11489SPengcheng.Chen@Sun.COM 		kmem_free(sc->sc_bm[i], bm_size[i]);
1493*11489SPengcheng.Chen@Sun.COM 
1494*11489SPengcheng.Chen@Sun.COM 	kmem_free(sc->sc_btn, BTN_USED * sizeof (int));
1495*11489SPengcheng.Chen@Sun.COM 	kmem_free(sc->sc_abs, ABS_USED * sizeof (struct event_abs_axis));
1496*11489SPengcheng.Chen@Sun.COM 	kmem_free(usbwcmp, sizeof (usbwcm_state_t));
1497*11489SPengcheng.Chen@Sun.COM 
1498*11489SPengcheng.Chen@Sun.COM 	q->q_ptr = WR(q)->q_ptr = NULL;
1499*11489SPengcheng.Chen@Sun.COM 	return (0);
1500*11489SPengcheng.Chen@Sun.COM }
1501*11489SPengcheng.Chen@Sun.COM 
1502*11489SPengcheng.Chen@Sun.COM /*
1503*11489SPengcheng.Chen@Sun.COM  * usbwcm_wput() :
1504*11489SPengcheng.Chen@Sun.COM  *	wput() routine for the wacom module.
1505*11489SPengcheng.Chen@Sun.COM  *	Module below : hid, module above : consms
1506*11489SPengcheng.Chen@Sun.COM  */
1507*11489SPengcheng.Chen@Sun.COM static int
usbwcm_wput(queue_t * q,mblk_t * mp)1508*11489SPengcheng.Chen@Sun.COM usbwcm_wput(queue_t *q, mblk_t *mp)
1509*11489SPengcheng.Chen@Sun.COM {
1510*11489SPengcheng.Chen@Sun.COM 	switch (mp->b_datap->db_type) {
1511*11489SPengcheng.Chen@Sun.COM 
1512*11489SPengcheng.Chen@Sun.COM 	case M_FLUSH:  /* Canonical flush handling */
1513*11489SPengcheng.Chen@Sun.COM 		if (*mp->b_rptr & FLUSHW) {
1514*11489SPengcheng.Chen@Sun.COM 			flushq(q, FLUSHDATA);
1515*11489SPengcheng.Chen@Sun.COM 		}
1516*11489SPengcheng.Chen@Sun.COM 		if (*mp->b_rptr & FLUSHR) {
1517*11489SPengcheng.Chen@Sun.COM 			flushq(RD(q), FLUSHDATA);
1518*11489SPengcheng.Chen@Sun.COM 		}
1519*11489SPengcheng.Chen@Sun.COM 		putnext(q, mp); /* pass it down the line. */
1520*11489SPengcheng.Chen@Sun.COM 		break;
1521*11489SPengcheng.Chen@Sun.COM 
1522*11489SPengcheng.Chen@Sun.COM 	case M_IOCTL:
1523*11489SPengcheng.Chen@Sun.COM 		usbwcm_ioctl(q, mp);
1524*11489SPengcheng.Chen@Sun.COM 		break;
1525*11489SPengcheng.Chen@Sun.COM 
1526*11489SPengcheng.Chen@Sun.COM 	case M_IOCDATA:
1527*11489SPengcheng.Chen@Sun.COM 		usbwcm_iocpy(q, mp);
1528*11489SPengcheng.Chen@Sun.COM 		break;
1529*11489SPengcheng.Chen@Sun.COM 
1530*11489SPengcheng.Chen@Sun.COM 	default:
1531*11489SPengcheng.Chen@Sun.COM 		putnext(q, mp); /* pass it down the line. */
1532*11489SPengcheng.Chen@Sun.COM 	}
1533*11489SPengcheng.Chen@Sun.COM 
1534*11489SPengcheng.Chen@Sun.COM 	return (0);
1535*11489SPengcheng.Chen@Sun.COM }
1536*11489SPengcheng.Chen@Sun.COM 
1537*11489SPengcheng.Chen@Sun.COM /*
1538*11489SPengcheng.Chen@Sun.COM  * usbwcm_rput() :
1539*11489SPengcheng.Chen@Sun.COM  *	Put procedure for input from driver end of stream (read queue).
1540*11489SPengcheng.Chen@Sun.COM  */
1541*11489SPengcheng.Chen@Sun.COM static void
usbwcm_rput(queue_t * q,mblk_t * mp)1542*11489SPengcheng.Chen@Sun.COM usbwcm_rput(queue_t *q, mblk_t *mp)
1543*11489SPengcheng.Chen@Sun.COM {
1544*11489SPengcheng.Chen@Sun.COM 	usbwcm_state_t		*usbwcmp = q->q_ptr;
1545*11489SPengcheng.Chen@Sun.COM 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
1546*11489SPengcheng.Chen@Sun.COM 	mblk_t			*mp0 = mp;
1547*11489SPengcheng.Chen@Sun.COM 	int			limit;
1548*11489SPengcheng.Chen@Sun.COM 
1549*11489SPengcheng.Chen@Sun.COM 	if (usbwcmp == 0) {
1550*11489SPengcheng.Chen@Sun.COM 		freemsg(mp);	/* nobody's listening */
1551*11489SPengcheng.Chen@Sun.COM 		return;
1552*11489SPengcheng.Chen@Sun.COM 	}
1553*11489SPengcheng.Chen@Sun.COM 
1554*11489SPengcheng.Chen@Sun.COM 	switch (mp->b_datap->db_type) {
1555*11489SPengcheng.Chen@Sun.COM 	case M_FLUSH:
1556*11489SPengcheng.Chen@Sun.COM 		if (*mp->b_rptr & FLUSHW)
1557*11489SPengcheng.Chen@Sun.COM 			flushq(WR(q), FLUSHDATA);
1558*11489SPengcheng.Chen@Sun.COM 
1559*11489SPengcheng.Chen@Sun.COM 		if (*mp->b_rptr & FLUSHR)
1560*11489SPengcheng.Chen@Sun.COM 			flushq(q, FLUSHDATA);
1561*11489SPengcheng.Chen@Sun.COM 
1562*11489SPengcheng.Chen@Sun.COM 		freemsg(mp);
1563*11489SPengcheng.Chen@Sun.COM 		return;
1564*11489SPengcheng.Chen@Sun.COM 
1565*11489SPengcheng.Chen@Sun.COM 	case M_BREAK:
1566*11489SPengcheng.Chen@Sun.COM 		/*
1567*11489SPengcheng.Chen@Sun.COM 		 * We don't have to handle this
1568*11489SPengcheng.Chen@Sun.COM 		 * because nothing is sent from the downstream
1569*11489SPengcheng.Chen@Sun.COM 		 */
1570*11489SPengcheng.Chen@Sun.COM 		freemsg(mp);
1571*11489SPengcheng.Chen@Sun.COM 		return;
1572*11489SPengcheng.Chen@Sun.COM 
1573*11489SPengcheng.Chen@Sun.COM 	case M_DATA:
1574*11489SPengcheng.Chen@Sun.COM 		if (!(usbwcmp->usbwcm_flags & USBWCM_OPEN)) {
1575*11489SPengcheng.Chen@Sun.COM 			freemsg(mp);	/* not ready to listen */
1576*11489SPengcheng.Chen@Sun.COM 
1577*11489SPengcheng.Chen@Sun.COM 			return;
1578*11489SPengcheng.Chen@Sun.COM 		}
1579*11489SPengcheng.Chen@Sun.COM 
1580*11489SPengcheng.Chen@Sun.COM 		/*
1581*11489SPengcheng.Chen@Sun.COM 		 * Make sure there are at least "limit" number of bytes.
1582*11489SPengcheng.Chen@Sun.COM 		 */
1583*11489SPengcheng.Chen@Sun.COM 		limit = uwacom_protocols[sc->sc_type->protocol].packet_size;
1584*11489SPengcheng.Chen@Sun.COM 		if (MBLKL(mp0) == limit) {	/* REMOVE */
1585*11489SPengcheng.Chen@Sun.COM 			do {
1586*11489SPengcheng.Chen@Sun.COM 				/* REMOVE */
1587*11489SPengcheng.Chen@Sun.COM 				usbwcm_input(usbwcmp, mp0);
1588*11489SPengcheng.Chen@Sun.COM 				mp0 = mp0->b_cont;
1589*11489SPengcheng.Chen@Sun.COM 			} while (mp0 != NULL);   /* next block, if any */
1590*11489SPengcheng.Chen@Sun.COM 		}
1591*11489SPengcheng.Chen@Sun.COM 
1592*11489SPengcheng.Chen@Sun.COM 		freemsg(mp);
1593*11489SPengcheng.Chen@Sun.COM 		break;
1594*11489SPengcheng.Chen@Sun.COM 
1595*11489SPengcheng.Chen@Sun.COM 	case M_CTL:
1596*11489SPengcheng.Chen@Sun.COM 		usbwcm_mctl(q, mp);
1597*11489SPengcheng.Chen@Sun.COM 		return;
1598*11489SPengcheng.Chen@Sun.COM 
1599*11489SPengcheng.Chen@Sun.COM 	case M_ERROR:
1600*11489SPengcheng.Chen@Sun.COM 		/* REMOVE */
1601*11489SPengcheng.Chen@Sun.COM 		usbwcmp->usbwcm_flags &= ~USBWCM_QWAIT;
1602*11489SPengcheng.Chen@Sun.COM 
1603*11489SPengcheng.Chen@Sun.COM 		freemsg(mp);
1604*11489SPengcheng.Chen@Sun.COM 		return;
1605*11489SPengcheng.Chen@Sun.COM 	default:
1606*11489SPengcheng.Chen@Sun.COM 		putnext(q, mp);
1607*11489SPengcheng.Chen@Sun.COM 		return;
1608*11489SPengcheng.Chen@Sun.COM 	}
1609*11489SPengcheng.Chen@Sun.COM }
1610*11489SPengcheng.Chen@Sun.COM 
1611*11489SPengcheng.Chen@Sun.COM 
1612*11489SPengcheng.Chen@Sun.COM static struct module_info modinfo;
1613*11489SPengcheng.Chen@Sun.COM 
1614*11489SPengcheng.Chen@Sun.COM /* STREAMS entry points */
1615*11489SPengcheng.Chen@Sun.COM 
1616*11489SPengcheng.Chen@Sun.COM /* read side queue */
1617*11489SPengcheng.Chen@Sun.COM static struct qinit rinit = {
1618*11489SPengcheng.Chen@Sun.COM 	(int (*)())usbwcm_rput,	/* put procedure not needed */
1619*11489SPengcheng.Chen@Sun.COM 	NULL, 			/* service procedure */
1620*11489SPengcheng.Chen@Sun.COM 	usbwcm_open,		/* called on startup */
1621*11489SPengcheng.Chen@Sun.COM 	usbwcm_close,		/* called on finish */
1622*11489SPengcheng.Chen@Sun.COM 	NULL,			/* for future use */
1623*11489SPengcheng.Chen@Sun.COM 	&modinfo,		/* module information structure */
1624*11489SPengcheng.Chen@Sun.COM 	NULL			/* module statistics structure */
1625*11489SPengcheng.Chen@Sun.COM };
1626*11489SPengcheng.Chen@Sun.COM 
1627*11489SPengcheng.Chen@Sun.COM /* write side queue */
1628*11489SPengcheng.Chen@Sun.COM static struct qinit winit = {
1629*11489SPengcheng.Chen@Sun.COM 	usbwcm_wput,		/* put procedure */
1630*11489SPengcheng.Chen@Sun.COM 	NULL,			/* no service proecedure needed */
1631*11489SPengcheng.Chen@Sun.COM 	NULL,			/* open not used on write side */
1632*11489SPengcheng.Chen@Sun.COM 	NULL,			/* close not used on write side */
1633*11489SPengcheng.Chen@Sun.COM 	NULL,			/* for future use */
1634*11489SPengcheng.Chen@Sun.COM 	&modinfo,		/* module information structure */
1635*11489SPengcheng.Chen@Sun.COM 	NULL			/* module statistics structure */
1636*11489SPengcheng.Chen@Sun.COM };
1637*11489SPengcheng.Chen@Sun.COM 
1638*11489SPengcheng.Chen@Sun.COM /* STREAMS table */
1639*11489SPengcheng.Chen@Sun.COM static struct streamtab strtab = {
1640*11489SPengcheng.Chen@Sun.COM 	&rinit,
1641*11489SPengcheng.Chen@Sun.COM 	&winit,
1642*11489SPengcheng.Chen@Sun.COM 	NULL,			/* not a MUX */
1643*11489SPengcheng.Chen@Sun.COM 	NULL			/* not a MUX */
1644*11489SPengcheng.Chen@Sun.COM };
1645*11489SPengcheng.Chen@Sun.COM 
1646*11489SPengcheng.Chen@Sun.COM /* Module linkage information */
1647*11489SPengcheng.Chen@Sun.COM 
1648*11489SPengcheng.Chen@Sun.COM static struct fmodsw modsw = {
1649*11489SPengcheng.Chen@Sun.COM 	"usbwcm",
1650*11489SPengcheng.Chen@Sun.COM 	&strtab,
1651*11489SPengcheng.Chen@Sun.COM 	D_MP | D_MTPERMOD
1652*11489SPengcheng.Chen@Sun.COM };
1653*11489SPengcheng.Chen@Sun.COM 
1654*11489SPengcheng.Chen@Sun.COM 
1655*11489SPengcheng.Chen@Sun.COM static struct modlstrmod modlstr = {
1656*11489SPengcheng.Chen@Sun.COM 	&mod_strmodops,
1657*11489SPengcheng.Chen@Sun.COM 	"USB Wacom STRMOD",
1658*11489SPengcheng.Chen@Sun.COM 	&modsw
1659*11489SPengcheng.Chen@Sun.COM };
1660*11489SPengcheng.Chen@Sun.COM 
1661*11489SPengcheng.Chen@Sun.COM static struct modlinkage modlink = {
1662*11489SPengcheng.Chen@Sun.COM 	MODREV_1,
1663*11489SPengcheng.Chen@Sun.COM 	(void *)&modlstr,
1664*11489SPengcheng.Chen@Sun.COM 	NULL
1665*11489SPengcheng.Chen@Sun.COM };
1666*11489SPengcheng.Chen@Sun.COM 
1667*11489SPengcheng.Chen@Sun.COM static struct module_info modinfo = {
1668*11489SPengcheng.Chen@Sun.COM 	0x0ffff,		/* module id number */
1669*11489SPengcheng.Chen@Sun.COM 	"usbwcm",		/* module name */
1670*11489SPengcheng.Chen@Sun.COM 	0,			/* min packet size accepted */
1671*11489SPengcheng.Chen@Sun.COM 	INFPSZ,			/* max packet size accepted */
1672*11489SPengcheng.Chen@Sun.COM 	512,			/* hi-water mark */
1673*11489SPengcheng.Chen@Sun.COM 	128			/* lo-water mark */
1674*11489SPengcheng.Chen@Sun.COM };
1675*11489SPengcheng.Chen@Sun.COM 
1676*11489SPengcheng.Chen@Sun.COM 
1677*11489SPengcheng.Chen@Sun.COM /* Module entry points */
1678*11489SPengcheng.Chen@Sun.COM 
1679*11489SPengcheng.Chen@Sun.COM int
_init(void)1680*11489SPengcheng.Chen@Sun.COM _init(void)
1681*11489SPengcheng.Chen@Sun.COM {
1682*11489SPengcheng.Chen@Sun.COM 	int rval = mod_install(&modlink);
1683*11489SPengcheng.Chen@Sun.COM 
1684*11489SPengcheng.Chen@Sun.COM 	if (rval == 0) {
1685*11489SPengcheng.Chen@Sun.COM 		usbwcm_log_handle = usb_alloc_log_hdl(NULL, "usbwcm",
1686*11489SPengcheng.Chen@Sun.COM 		    &usbwcm_errlevel, &usbwcm_errmask, NULL, 0);
1687*11489SPengcheng.Chen@Sun.COM 	}
1688*11489SPengcheng.Chen@Sun.COM 
1689*11489SPengcheng.Chen@Sun.COM 	return (rval);
1690*11489SPengcheng.Chen@Sun.COM }
1691*11489SPengcheng.Chen@Sun.COM 
1692*11489SPengcheng.Chen@Sun.COM int
_fini(void)1693*11489SPengcheng.Chen@Sun.COM _fini(void)
1694*11489SPengcheng.Chen@Sun.COM {
1695*11489SPengcheng.Chen@Sun.COM 	int rval = mod_remove(&modlink);
1696*11489SPengcheng.Chen@Sun.COM 
1697*11489SPengcheng.Chen@Sun.COM 	if (rval == 0) {
1698*11489SPengcheng.Chen@Sun.COM 		usb_free_log_hdl(usbwcm_log_handle);
1699*11489SPengcheng.Chen@Sun.COM 	}
1700*11489SPengcheng.Chen@Sun.COM 
1701*11489SPengcheng.Chen@Sun.COM 	return (rval);
1702*11489SPengcheng.Chen@Sun.COM }
1703*11489SPengcheng.Chen@Sun.COM 
1704*11489SPengcheng.Chen@Sun.COM int
_info(struct modinfo * modinfop)1705*11489SPengcheng.Chen@Sun.COM _info(struct modinfo *modinfop)
1706*11489SPengcheng.Chen@Sun.COM {
1707*11489SPengcheng.Chen@Sun.COM 
1708*11489SPengcheng.Chen@Sun.COM 	return (mod_info(&modlink, modinfop));
1709*11489SPengcheng.Chen@Sun.COM }
1710