1 // SPDX-License-Identifier: GPL-2.0+
2 // Driver for Xbox DVD Movie Playback Kit
3 // Copyright (c) 2018 by Benjamin Valentin <benpicco@googlemail.com>
6 * Xbox DVD Movie Playback Kit USB IR dongle support
8 * The driver was derived from the ati_remote driver 2.2.1
9 * and used information from lirc_xbox.c
11 * Copyright (c) 2011, 2012 Anssi Hannula <anssi.hannula@iki.fi>
12 * Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
13 * Copyright (c) 2002 Vladimir Dergachev
14 * Copyright (c) 2003-2004 Paul Miller <pmiller9@users.sourceforge.net>
17 #include <linux/slab.h>
18 #include <linux/module.h>
19 #include <linux/usb/input.h>
20 #include <media/rc-core.h>
23 * Module and Version Information
25 #define DRIVER_VERSION "1.0.0"
26 #define DRIVER_AUTHOR "Benjamin Valentin <benpicco@googlemail.com>"
27 #define DRIVER_DESC "Xbox DVD USB Remote Control"
29 #define NAME_BUFSIZE 80 /* size of product name, path buffers */
30 #define DATA_BUFSIZE 8 /* size of URB data buffers */
33 * USB vendor ids for XBOX DVD Dongles
35 #define VENDOR_GAMESTER 0x040b
36 #define VENDOR_MICROSOFT 0x045e
38 static const struct usb_device_id xbox_remote_table
[] = {
39 /* Gamester Xbox DVD Movie Playback Kit IR */
41 USB_DEVICE(VENDOR_GAMESTER
, 0x6521),
43 /* Microsoft Xbox DVD Movie Playback Kit IR */
45 USB_DEVICE(VENDOR_MICROSOFT
, 0x0284),
47 {} /* Terminating entry */
50 MODULE_DEVICE_TABLE(usb
, xbox_remote_table
);
54 struct usb_device
*udev
;
55 struct usb_interface
*interface
;
58 unsigned char inbuf
[DATA_BUFSIZE
] __aligned(sizeof(u16
));
60 char rc_name
[NAME_BUFSIZE
];
61 char rc_phys
[NAME_BUFSIZE
];
64 static int xbox_remote_rc_open(struct rc_dev
*rdev
)
66 struct xbox_remote
*xbox_remote
= rdev
->priv
;
68 /* On first open, submit the read urb which was set up previously. */
69 xbox_remote
->irq_urb
->dev
= xbox_remote
->udev
;
70 if (usb_submit_urb(xbox_remote
->irq_urb
, GFP_KERNEL
)) {
71 dev_err(&xbox_remote
->interface
->dev
,
72 "%s: usb_submit_urb failed!\n", __func__
);
79 static void xbox_remote_rc_close(struct rc_dev
*rdev
)
81 struct xbox_remote
*xbox_remote
= rdev
->priv
;
83 usb_kill_urb(xbox_remote
->irq_urb
);
87 * xbox_remote_report_input
89 static void xbox_remote_input_report(struct urb
*urb
)
91 struct xbox_remote
*xbox_remote
= urb
->context
;
92 unsigned char *data
= xbox_remote
->inbuf
;
96 * data[1] = length - always 0x06
97 * data[2] = the key code
98 * data[3] = high part of key code
99 * data[4] = last_press_ms (low)
100 * data[5] = last_press_ms (high)
103 /* Deal with strange looking inputs */
104 if (urb
->actual_length
!= 6 || urb
->actual_length
!= data
[1]) {
105 dev_warn(&urb
->dev
->dev
, "Weird data, len=%d: %*ph\n",
106 urb
->actual_length
, urb
->actual_length
, data
);
110 rc_keydown(xbox_remote
->rdev
, RC_PROTO_UNKNOWN
,
111 le16_to_cpup((__le16
*)(data
+ 2)), 0);
117 static void xbox_remote_irq_in(struct urb
*urb
)
119 struct xbox_remote
*xbox_remote
= urb
->context
;
122 switch (urb
->status
) {
123 case 0: /* success */
124 xbox_remote_input_report(urb
);
126 case -ECONNRESET
: /* unlink */
129 dev_dbg(&xbox_remote
->interface
->dev
,
130 "%s: urb error status, unlink?\n",
134 dev_dbg(&xbox_remote
->interface
->dev
,
135 "%s: Nonzero urb status %d\n",
136 __func__
, urb
->status
);
139 retval
= usb_submit_urb(urb
, GFP_ATOMIC
);
141 dev_err(&xbox_remote
->interface
->dev
,
142 "%s: usb_submit_urb()=%d\n",
146 static void xbox_remote_rc_init(struct xbox_remote
*xbox_remote
)
148 struct rc_dev
*rdev
= xbox_remote
->rdev
;
150 rdev
->priv
= xbox_remote
;
151 rdev
->allowed_protocols
= RC_PROTO_BIT_UNKNOWN
;
152 rdev
->driver_name
= "xbox_remote";
154 rdev
->open
= xbox_remote_rc_open
;
155 rdev
->close
= xbox_remote_rc_close
;
157 rdev
->device_name
= xbox_remote
->rc_name
;
158 rdev
->input_phys
= xbox_remote
->rc_phys
;
160 usb_to_input_id(xbox_remote
->udev
, &rdev
->input_id
);
161 rdev
->dev
.parent
= &xbox_remote
->interface
->dev
;
164 static int xbox_remote_initialize(struct xbox_remote
*xbox_remote
,
165 struct usb_endpoint_descriptor
*endpoint_in
)
167 struct usb_device
*udev
= xbox_remote
->udev
;
171 pipe
= usb_rcvintpipe(udev
, endpoint_in
->bEndpointAddress
);
172 maxp
= usb_maxpacket(udev
, pipe
, usb_pipeout(pipe
));
173 maxp
= (maxp
> DATA_BUFSIZE
) ? DATA_BUFSIZE
: maxp
;
175 usb_fill_int_urb(xbox_remote
->irq_urb
, udev
, pipe
, xbox_remote
->inbuf
,
176 maxp
, xbox_remote_irq_in
, xbox_remote
,
177 endpoint_in
->bInterval
);
185 static int xbox_remote_probe(struct usb_interface
*interface
,
186 const struct usb_device_id
*id
)
188 struct usb_device
*udev
= interface_to_usbdev(interface
);
189 struct usb_host_interface
*iface_host
= interface
->cur_altsetting
;
190 struct usb_endpoint_descriptor
*endpoint_in
;
191 struct xbox_remote
*xbox_remote
;
192 struct rc_dev
*rc_dev
;
195 // why is there also a device with no endpoints?
196 if (iface_host
->desc
.bNumEndpoints
== 0)
199 if (iface_host
->desc
.bNumEndpoints
!= 1) {
200 pr_err("%s: Unexpected desc.bNumEndpoints: %d\n",
201 __func__
, iface_host
->desc
.bNumEndpoints
);
205 endpoint_in
= &iface_host
->endpoint
[0].desc
;
207 if (!usb_endpoint_is_int_in(endpoint_in
)) {
208 pr_err("%s: Unexpected endpoint_in\n", __func__
);
211 if (le16_to_cpu(endpoint_in
->wMaxPacketSize
) == 0) {
212 pr_err("%s: endpoint_in message size==0?\n", __func__
);
216 xbox_remote
= kzalloc(sizeof(*xbox_remote
), GFP_KERNEL
);
217 rc_dev
= rc_allocate_device(RC_DRIVER_SCANCODE
);
218 if (!xbox_remote
|| !rc_dev
)
219 goto exit_free_dev_rdev
;
221 /* Allocate URB buffer */
222 xbox_remote
->irq_urb
= usb_alloc_urb(0, GFP_KERNEL
);
223 if (!xbox_remote
->irq_urb
)
224 goto exit_free_buffers
;
226 xbox_remote
->udev
= udev
;
227 xbox_remote
->rdev
= rc_dev
;
228 xbox_remote
->interface
= interface
;
230 usb_make_path(udev
, xbox_remote
->rc_phys
, sizeof(xbox_remote
->rc_phys
));
232 strlcat(xbox_remote
->rc_phys
, "/input0", sizeof(xbox_remote
->rc_phys
));
234 snprintf(xbox_remote
->rc_name
, sizeof(xbox_remote
->rc_name
), "%s%s%s",
235 udev
->manufacturer
?: "",
236 udev
->manufacturer
&& udev
->product
? " " : "",
237 udev
->product
?: "");
239 if (!strlen(xbox_remote
->rc_name
))
240 snprintf(xbox_remote
->rc_name
, sizeof(xbox_remote
->rc_name
),
241 DRIVER_DESC
"(%04x,%04x)",
242 le16_to_cpu(xbox_remote
->udev
->descriptor
.idVendor
),
243 le16_to_cpu(xbox_remote
->udev
->descriptor
.idProduct
));
245 rc_dev
->map_name
= RC_MAP_XBOX_DVD
; /* default map */
247 xbox_remote_rc_init(xbox_remote
);
249 /* Device Hardware Initialization */
250 err
= xbox_remote_initialize(xbox_remote
, endpoint_in
);
254 /* Set up and register rc device */
255 err
= rc_register_device(xbox_remote
->rdev
);
259 usb_set_intfdata(interface
, xbox_remote
);
264 usb_kill_urb(xbox_remote
->irq_urb
);
266 usb_free_urb(xbox_remote
->irq_urb
);
268 rc_free_device(rc_dev
);
275 * xbox_remote_disconnect
277 static void xbox_remote_disconnect(struct usb_interface
*interface
)
279 struct xbox_remote
*xbox_remote
;
281 xbox_remote
= usb_get_intfdata(interface
);
282 usb_set_intfdata(interface
, NULL
);
284 dev_warn(&interface
->dev
, "%s - null device?\n", __func__
);
288 usb_kill_urb(xbox_remote
->irq_urb
);
289 rc_unregister_device(xbox_remote
->rdev
);
290 usb_free_urb(xbox_remote
->irq_urb
);
294 /* usb specific object to register with the usb subsystem */
295 static struct usb_driver xbox_remote_driver
= {
296 .name
= "xbox_remote",
297 .probe
= xbox_remote_probe
,
298 .disconnect
= xbox_remote_disconnect
,
299 .id_table
= xbox_remote_table
,
302 module_usb_driver(xbox_remote_driver
);
304 MODULE_AUTHOR(DRIVER_AUTHOR
);
305 MODULE_DESCRIPTION(DRIVER_DESC
);
306 MODULE_LICENSE("GPL");