1 /* $NetBSD: xboxcontroller.c,v 1.11 2009/09/23 19:07:19 plunky Exp $ */
4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: xboxcontroller.c,v 1.11 2009/09/23 19:07:19 plunky Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
35 #include <sys/malloc.h>
39 #include <dev/wscons/wsconsio.h>
40 #include <dev/wscons/wsmousevar.h>
42 #include <dev/usb/usb.h>
43 #include <dev/usb/usbdi.h>
44 #include <dev/usb/usbdi_util.h>
45 #include <dev/usb/usbdevs.h>
47 #define XBOX_CONTROLLER_BUFSZ 32
49 struct xboxcontroller_softc
{
52 usbd_device_handle sc_udev
;
53 usbd_interface_handle sc_iface
;
55 usbd_pipe_handle sc_ep
;
56 unsigned char *sc_buf
;
59 #define XBOX_CONTROLLER_MODE_MOUSE 1
60 #define XBOX_CONTROLLER_MODE_JOYSTICK 2
62 device_t sc_wsmousedev
;
67 static void xboxcontroller_intr(usbd_xfer_handle
, usbd_private_handle
,
70 static int xboxcontroller_wsmouse_enable(void *);
71 static int xboxcontroller_wsmouse_ioctl(void *, u_long
, void *, int,
73 static void xboxcontroller_wsmouse_disable(void *);
75 static const struct wsmouse_accessops xboxcontroller_accessops
= {
76 xboxcontroller_wsmouse_enable
,
77 xboxcontroller_wsmouse_ioctl
,
78 xboxcontroller_wsmouse_disable
81 int xboxcontroller_match(device_t
, cfdata_t
, void *);
82 void xboxcontroller_attach(device_t
, device_t
, void *);
83 void xboxcontroller_childdet(device_t
, device_t
);
84 int xboxcontroller_detach(device_t
, int);
85 int xboxcontroller_activate(device_t
, enum devact
);
86 extern struct cfdriver xboxcontroller_cd
;
87 CFATTACH_DECL2_NEW(xboxcontroller
, sizeof(struct xboxcontroller_softc
),
88 xboxcontroller_match
, xboxcontroller_attach
, xboxcontroller_detach
,
89 xboxcontroller_activate
, NULL
, xboxcontroller_childdet
);
91 USB_MATCH(xboxcontroller
)
93 USB_MATCH_START(xboxcontroller
, uaa
);
95 if (uaa
->vendor
== USB_VENDOR_MICROSOFT
) {
96 switch (uaa
->product
) {
97 case USB_PRODUCT_MICROSOFT_XBOX_CONTROLLER_S10
:
98 case USB_PRODUCT_MICROSOFT_XBOX_CONTROLLER_S12
:
99 return UMATCH_VENDOR_PRODUCT
;
106 USB_ATTACH(xboxcontroller
)
108 USB_ATTACH_START(xboxcontroller
, sc
, uaa
);
109 usbd_device_handle dev
= uaa
->device
;
111 struct wsmousedev_attach_args waa
;
112 usb_endpoint_descriptor_t
*ed
;
120 devinfo
= usbd_devinfo_alloc(dev
, 0);
121 aprint_normal_dev(self
, "%s\n", devinfo
);
122 usbd_devinfo_free(devinfo
);
124 sc
->sc_drvmode
= XBOX_CONTROLLER_MODE_MOUSE
;
126 sc
->sc_enabled
= sc
->sc_dying
= 0;
129 err
= usbd_set_config_no(dev
, 1, 1);
131 aprint_error_dev(self
, "setting config no failed: %s\n",
134 USB_ATTACH_ERROR_RETURN
;
136 err
= usbd_device2interface_handle(dev
, 0, &sc
->sc_iface
);
138 aprint_error_dev(self
, "failed to get interface: %s\n",
141 USB_ATTACH_ERROR_RETURN
;
144 ed
= usbd_interface2endpoint_descriptor(sc
->sc_iface
, 0);
146 aprint_error_dev(sc
->sc_dev
, "couldn't get ep 0\n");
148 USB_ATTACH_ERROR_RETURN
;
150 sc
->sc_ed
= ed
->bEndpointAddress
;
152 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH
, sc
->sc_udev
,
155 waa
.accessops
= &xboxcontroller_accessops
;
156 waa
.accesscookie
= sc
;
158 sc
->sc_wsmousedev
= config_found_ia(self
, "wsmousedev", &waa
,
161 USB_ATTACH_SUCCESS_RETURN
;
165 xboxcontroller_childdet(device_t self
, device_t child
)
167 struct xboxcontroller_softc
*sc
= device_private(self
);
169 KASSERT(sc
->sc_wsmousedev
== child
);
170 sc
->sc_wsmousedev
= NULL
;
173 USB_DETACH(xboxcontroller
)
175 USB_DETACH_START(xboxcontroller
, sc
);
180 if (sc
->sc_ep
!= NULL
) {
181 usbd_abort_pipe(sc
->sc_ep
);
182 usbd_close_pipe(sc
->sc_ep
);
188 if (sc
->sc_wsmousedev
!= NULL
)
189 rv
= config_detach(sc
->sc_wsmousedev
, flags
);
195 xboxcontroller_activate(device_ptr_t self
, enum devact act
)
197 struct xboxcontroller_softc
*sc
= device_private(self
);
200 case DVACT_DEACTIVATE
:
209 xboxcontroller_intr(usbd_xfer_handle xfer
, usbd_private_handle priv
,
212 struct xboxcontroller_softc
*sc
;
219 sc
= (struct xboxcontroller_softc
*)priv
;
222 usbd_get_xfer_status(xfer
, NULL
, NULL
, &len
, NULL
);
223 if (status
== USBD_CANCELLED
)
226 x
= (int16_t)(((int16_t)data
[13] << 8) | data
[12]);
227 y
= (int16_t)(((int16_t)data
[15] << 8) | data
[14]);
228 /* z = (int16_t)(((int16_t)data[17] << 8) | data[16]); */
229 /* w = (int16_t)(((int16_t)data[19] << 8) | data[18]); */
232 if (x
< 8192 && x
> -8192)
234 if (y
< 8192 && y
> -8192)
237 switch (sc
->sc_drvmode
) {
238 case XBOX_CONTROLLER_MODE_MOUSE
:
239 if (sc
->sc_wsmousedev
== NULL
)
242 if (data
[2] & 0x40) btnmask
|= 0x01; /* thumb press left */
243 if (data
[2] & 0x80) btnmask
|= 0x04; /* thumb press right */
244 if (data
[2] & 0x10) btnmask
|= 0x02; /* start button */
247 wsmouse_input(sc
->sc_wsmousedev
, btnmask
,
249 0, 0, /* z / 4096, w / 4096, */
250 WSMOUSE_INPUT_DELTA
);
253 case XBOX_CONTROLLER_MODE_JOYSTICK
:
254 /* XXX not implemented */
264 xboxcontroller_wsmouse_enable(void *opaque
)
266 struct xboxcontroller_softc
*sc
;
269 sc
= (struct xboxcontroller_softc
*)opaque
;
276 sc
->sc_buf
= malloc(XBOX_CONTROLLER_BUFSZ
, M_USBDEV
, M_WAITOK
);
277 err
= usbd_open_pipe_intr(sc
->sc_iface
, sc
->sc_ed
,
278 USBD_SHORT_XFER_OK
, &sc
->sc_ep
, sc
, sc
->sc_buf
,
279 XBOX_CONTROLLER_BUFSZ
, xboxcontroller_intr
,
280 USBD_DEFAULT_INTERVAL
);
282 aprint_error_dev(sc
->sc_dev
, "open pipe failed: %s\n",
284 free(sc
->sc_buf
, M_USBDEV
);
296 xboxcontroller_wsmouse_disable(void *opaque
)
298 struct xboxcontroller_softc
*sc
;
300 sc
= (struct xboxcontroller_softc
*)opaque
;
302 if (!sc
->sc_enabled
) {
303 aprint_error_dev(sc
->sc_dev
, "already disabled!\n");
307 if (sc
->sc_ep
!= NULL
) {
308 usbd_abort_pipe(sc
->sc_ep
);
309 usbd_close_pipe(sc
->sc_ep
);
313 if (sc
->sc_buf
!= NULL
) {
314 free(sc
->sc_buf
, M_USBDEV
);
324 xboxcontroller_wsmouse_ioctl(void *opaque
, u_long cmd
, void *data
, int flag
,
329 case WSMOUSEIO_GTYPE
:
330 *(u_int
*)data
= WSMOUSE_TYPE_USB
; /* XXX not really... */