cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xbox_remote.c (8047B)


      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_US(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);
    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");