linux/drivers/media/rc/xbox_remote.c
<<
>>
Prefs
   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>
   4
   5/*
   6 *  Xbox DVD Movie Playback Kit USB IR dongle support
   7 *
   8 *  The driver was derived from the ati_remote driver 2.2.1
   9 *          and used information from lirc_xbox.c
  10 *
  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>
  15 */
  16
  17#include <linux/slab.h>
  18#include <linux/module.h>
  19#include <linux/usb/input.h>
  20#include <media/rc-core.h>
  21
  22/*
  23 * Module and Version Information
  24 */
  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"
  28
  29#define NAME_BUFSIZE      80    /* size of product name, path buffers */
  30#define DATA_BUFSIZE      8     /* size of URB data buffers */
  31
  32/*
  33 * USB vendor ids for XBOX DVD Dongles
  34 */
  35#define VENDOR_GAMESTER     0x040b
  36#define VENDOR_MICROSOFT    0x045e
  37
  38static const struct usb_device_id xbox_remote_table[] = {
  39        /* Gamester Xbox DVD Movie Playback Kit IR */
  40        {
  41                USB_DEVICE(VENDOR_GAMESTER, 0x6521),
  42        },
  43        /* Microsoft Xbox DVD Movie Playback Kit IR */
  44        {
  45                USB_DEVICE(VENDOR_MICROSOFT, 0x0284),
  46        },
  47        {}      /* Terminating entry */
  48};
  49
  50MODULE_DEVICE_TABLE(usb, xbox_remote_table);
  51
  52struct xbox_remote {
  53        struct rc_dev *rdev;
  54        struct usb_device *udev;
  55        struct usb_interface *interface;
  56
  57        struct urb *irq_urb;
  58        unsigned char inbuf[DATA_BUFSIZE] __aligned(sizeof(u16));
  59
  60        char rc_name[NAME_BUFSIZE];
  61        char rc_phys[NAME_BUFSIZE];
  62};
  63
  64static int xbox_remote_rc_open(struct rc_dev *rdev)
  65{
  66        struct xbox_remote *xbox_remote = rdev->priv;
  67
  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__);
  73                return -EIO;
  74        }
  75
  76        return 0;
  77}
  78
  79static void xbox_remote_rc_close(struct rc_dev *rdev)
  80{
  81        struct xbox_remote *xbox_remote = rdev->priv;
  82
  83        usb_kill_urb(xbox_remote->irq_urb);
  84}
  85
  86/*
  87 * xbox_remote_report_input
  88 */
  89static void xbox_remote_input_report(struct urb *urb)
  90{
  91        struct xbox_remote *xbox_remote = urb->context;
  92        unsigned char *data = xbox_remote->inbuf;
  93
  94        /*
  95         * data[0] = 0x00
  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)
 101         */
 102
 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);
 107                return;
 108        }
 109
 110        rc_keydown(xbox_remote->rdev, RC_PROTO_XBOX_DVD,
 111                   le16_to_cpup((__le16 *)(data + 2)), 0);
 112}
 113
 114/*
 115 * xbox_remote_irq_in
 116 */
 117static void xbox_remote_irq_in(struct urb *urb)
 118{
 119        struct xbox_remote *xbox_remote = urb->context;
 120        int retval;
 121
 122        switch (urb->status) {
 123        case 0:                 /* success */
 124                xbox_remote_input_report(urb);
 125                break;
 126        case -ECONNRESET:       /* unlink */
 127        case -ENOENT:
 128        case -ESHUTDOWN:
 129                dev_dbg(&xbox_remote->interface->dev,
 130                        "%s: urb error status, unlink?\n",
 131                        __func__);
 132                return;
 133        default:                /* error */
 134                dev_dbg(&xbox_remote->interface->dev,
 135                        "%s: Nonzero urb status %d\n",
 136                        __func__, urb->status);
 137        }
 138
 139        retval = usb_submit_urb(urb, GFP_ATOMIC);
 140        if (retval)
 141                dev_err(&xbox_remote->interface->dev,
 142                        "%s: usb_submit_urb()=%d\n",
 143                        __func__, retval);
 144}
 145
 146static void xbox_remote_rc_init(struct xbox_remote *xbox_remote)
 147{
 148        struct rc_dev *rdev = xbox_remote->rdev;
 149
 150        rdev->priv = xbox_remote;
 151        rdev->allowed_protocols = RC_PROTO_BIT_XBOX_DVD;
 152        rdev->driver_name = "xbox_remote";
 153
 154        rdev->open = xbox_remote_rc_open;
 155        rdev->close = xbox_remote_rc_close;
 156
 157        rdev->device_name = xbox_remote->rc_name;
 158        rdev->input_phys = xbox_remote->rc_phys;
 159
 160        rdev->timeout = MS_TO_NS(10);
 161
 162        usb_to_input_id(xbox_remote->udev, &rdev->input_id);
 163        rdev->dev.parent = &xbox_remote->interface->dev;
 164}
 165
 166static int xbox_remote_initialize(struct xbox_remote *xbox_remote,
 167                                  struct usb_endpoint_descriptor *endpoint_in)
 168{
 169        struct usb_device *udev = xbox_remote->udev;
 170        int pipe, maxp;
 171
 172        /* Set up irq_urb */
 173        pipe = usb_rcvintpipe(udev, endpoint_in->bEndpointAddress);
 174        maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
 175        maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
 176
 177        usb_fill_int_urb(xbox_remote->irq_urb, udev, pipe, xbox_remote->inbuf,
 178                         maxp, xbox_remote_irq_in, xbox_remote,
 179                         endpoint_in->bInterval);
 180
 181        return 0;
 182}
 183
 184/*
 185 * xbox_remote_probe
 186 */
 187static int xbox_remote_probe(struct usb_interface *interface,
 188                             const struct usb_device_id *id)
 189{
 190        struct usb_device *udev = interface_to_usbdev(interface);
 191        struct usb_host_interface *iface_host = interface->cur_altsetting;
 192        struct usb_endpoint_descriptor *endpoint_in;
 193        struct xbox_remote *xbox_remote;
 194        struct rc_dev *rc_dev;
 195        int err = -ENOMEM;
 196
 197        // why is there also a device with no endpoints?
 198        if (iface_host->desc.bNumEndpoints == 0)
 199                return -ENODEV;
 200
 201        if (iface_host->desc.bNumEndpoints != 1) {
 202                pr_err("%s: Unexpected desc.bNumEndpoints: %d\n",
 203                       __func__, iface_host->desc.bNumEndpoints);
 204                return -ENODEV;
 205        }
 206
 207        endpoint_in = &iface_host->endpoint[0].desc;
 208
 209        if (!usb_endpoint_is_int_in(endpoint_in)) {
 210                pr_err("%s: Unexpected endpoint_in\n", __func__);
 211                return -ENODEV;
 212        }
 213        if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
 214                pr_err("%s: endpoint_in message size==0?\n", __func__);
 215                return -ENODEV;
 216        }
 217
 218        xbox_remote = kzalloc(sizeof(*xbox_remote), GFP_KERNEL);
 219        rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
 220        if (!xbox_remote || !rc_dev)
 221                goto exit_free_dev_rdev;
 222
 223        /* Allocate URB buffer */
 224        xbox_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
 225        if (!xbox_remote->irq_urb)
 226                goto exit_free_buffers;
 227
 228        xbox_remote->udev = udev;
 229        xbox_remote->rdev = rc_dev;
 230        xbox_remote->interface = interface;
 231
 232        usb_make_path(udev, xbox_remote->rc_phys, sizeof(xbox_remote->rc_phys));
 233
 234        strlcat(xbox_remote->rc_phys, "/input0", sizeof(xbox_remote->rc_phys));
 235
 236        snprintf(xbox_remote->rc_name, sizeof(xbox_remote->rc_name), "%s%s%s",
 237                 udev->manufacturer ?: "",
 238                 udev->manufacturer && udev->product ? " " : "",
 239                 udev->product ?: "");
 240
 241        if (!strlen(xbox_remote->rc_name))
 242                snprintf(xbox_remote->rc_name, sizeof(xbox_remote->rc_name),
 243                         DRIVER_DESC "(%04x,%04x)",
 244                         le16_to_cpu(xbox_remote->udev->descriptor.idVendor),
 245                         le16_to_cpu(xbox_remote->udev->descriptor.idProduct));
 246
 247        rc_dev->map_name = RC_MAP_XBOX_DVD; /* default map */
 248
 249        xbox_remote_rc_init(xbox_remote);
 250
 251        /* Device Hardware Initialization */
 252        err = xbox_remote_initialize(xbox_remote, endpoint_in);
 253        if (err)
 254                goto exit_kill_urbs;
 255
 256        /* Set up and register rc device */
 257        err = rc_register_device(xbox_remote->rdev);
 258        if (err)
 259                goto exit_kill_urbs;
 260
 261        usb_set_intfdata(interface, xbox_remote);
 262
 263        return 0;
 264
 265exit_kill_urbs:
 266        usb_kill_urb(xbox_remote->irq_urb);
 267exit_free_buffers:
 268        usb_free_urb(xbox_remote->irq_urb);
 269exit_free_dev_rdev:
 270        rc_free_device(rc_dev);
 271        kfree(xbox_remote);
 272
 273        return err;
 274}
 275
 276/*
 277 * xbox_remote_disconnect
 278 */
 279static void xbox_remote_disconnect(struct usb_interface *interface)
 280{
 281        struct xbox_remote *xbox_remote;
 282
 283        xbox_remote = usb_get_intfdata(interface);
 284        usb_set_intfdata(interface, NULL);
 285        if (!xbox_remote) {
 286                dev_warn(&interface->dev, "%s - null device?\n", __func__);
 287                return;
 288        }
 289
 290        usb_kill_urb(xbox_remote->irq_urb);
 291        rc_unregister_device(xbox_remote->rdev);
 292        usb_free_urb(xbox_remote->irq_urb);
 293        kfree(xbox_remote);
 294}
 295
 296/* usb specific object to register with the usb subsystem */
 297static struct usb_driver xbox_remote_driver = {
 298        .name         = "xbox_remote",
 299        .probe        = xbox_remote_probe,
 300        .disconnect   = xbox_remote_disconnect,
 301        .id_table     = xbox_remote_table,
 302};
 303
 304module_usb_driver(xbox_remote_driver);
 305
 306MODULE_AUTHOR(DRIVER_AUTHOR);
 307MODULE_DESCRIPTION(DRIVER_DESC);
 308MODULE_LICENSE("GPL");
 309