root/drivers/media/rc/xbox_remote.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xbox_remote_rc_open
  2. xbox_remote_rc_close
  3. xbox_remote_input_report
  4. xbox_remote_irq_in
  5. xbox_remote_rc_init
  6. xbox_remote_initialize
  7. xbox_remote_probe
  8. xbox_remote_disconnect

   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 
  38 static 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 
  50 MODULE_DEVICE_TABLE(usb, xbox_remote_table);
  51 
  52 struct 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 
  64 static 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 
  79 static 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  */
  89 static 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  */
 117 static 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 
 146 static 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 
 166 static 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  */
 187 static 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 
 265 exit_kill_urbs:
 266         usb_kill_urb(xbox_remote->irq_urb);
 267 exit_free_buffers:
 268         usb_free_urb(xbox_remote->irq_urb);
 269 exit_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  */
 279 static 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 */
 297 static 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 
 304 module_usb_driver(xbox_remote_driver);
 305 
 306 MODULE_AUTHOR(DRIVER_AUTHOR);
 307 MODULE_DESCRIPTION(DRIVER_DESC);
 308 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */