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

pxrc.c (6663B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Driver for Phoenix RC Flight Controller Adapter
      4 *
      5 * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/errno.h>
     10#include <linux/slab.h>
     11#include <linux/module.h>
     12#include <linux/uaccess.h>
     13#include <linux/usb.h>
     14#include <linux/usb/input.h>
     15#include <linux/mutex.h>
     16#include <linux/input.h>
     17
     18#define PXRC_VENDOR_ID		0x1781
     19#define PXRC_PRODUCT_ID		0x0898
     20
     21struct pxrc {
     22	struct input_dev	*input;
     23	struct usb_interface	*intf;
     24	struct urb		*urb;
     25	struct mutex		pm_mutex;
     26	bool			is_open;
     27	char			phys[64];
     28};
     29
     30static void pxrc_usb_irq(struct urb *urb)
     31{
     32	struct pxrc *pxrc = urb->context;
     33	u8 *data = urb->transfer_buffer;
     34	int error;
     35
     36	switch (urb->status) {
     37	case 0:
     38		/* success */
     39		break;
     40	case -ETIME:
     41		/* this urb is timing out */
     42		dev_dbg(&pxrc->intf->dev,
     43			"%s - urb timed out - was the device unplugged?\n",
     44			__func__);
     45		return;
     46	case -ECONNRESET:
     47	case -ENOENT:
     48	case -ESHUTDOWN:
     49	case -EPIPE:
     50		/* this urb is terminated, clean up */
     51		dev_dbg(&pxrc->intf->dev, "%s - urb shutting down with status: %d\n",
     52			__func__, urb->status);
     53		return;
     54	default:
     55		dev_dbg(&pxrc->intf->dev, "%s - nonzero urb status received: %d\n",
     56			__func__, urb->status);
     57		goto exit;
     58	}
     59
     60	if (urb->actual_length == 8) {
     61		input_report_abs(pxrc->input, ABS_X, data[0]);
     62		input_report_abs(pxrc->input, ABS_Y, data[2]);
     63		input_report_abs(pxrc->input, ABS_RX, data[3]);
     64		input_report_abs(pxrc->input, ABS_RY, data[4]);
     65		input_report_abs(pxrc->input, ABS_RUDDER, data[5]);
     66		input_report_abs(pxrc->input, ABS_THROTTLE, data[6]);
     67		input_report_abs(pxrc->input, ABS_MISC, data[7]);
     68
     69		input_report_key(pxrc->input, BTN_A, data[1]);
     70	}
     71
     72exit:
     73	/* Resubmit to fetch new fresh URBs */
     74	error = usb_submit_urb(urb, GFP_ATOMIC);
     75	if (error && error != -EPERM)
     76		dev_err(&pxrc->intf->dev,
     77			"%s - usb_submit_urb failed with result: %d",
     78			__func__, error);
     79}
     80
     81static int pxrc_open(struct input_dev *input)
     82{
     83	struct pxrc *pxrc = input_get_drvdata(input);
     84	int retval;
     85
     86	mutex_lock(&pxrc->pm_mutex);
     87	retval = usb_submit_urb(pxrc->urb, GFP_KERNEL);
     88	if (retval) {
     89		dev_err(&pxrc->intf->dev,
     90			"%s - usb_submit_urb failed, error: %d\n",
     91			__func__, retval);
     92		retval = -EIO;
     93		goto out;
     94	}
     95
     96	pxrc->is_open = true;
     97
     98out:
     99	mutex_unlock(&pxrc->pm_mutex);
    100	return retval;
    101}
    102
    103static void pxrc_close(struct input_dev *input)
    104{
    105	struct pxrc *pxrc = input_get_drvdata(input);
    106
    107	mutex_lock(&pxrc->pm_mutex);
    108	usb_kill_urb(pxrc->urb);
    109	pxrc->is_open = false;
    110	mutex_unlock(&pxrc->pm_mutex);
    111}
    112
    113static void pxrc_free_urb(void *_pxrc)
    114{
    115	struct pxrc *pxrc = _pxrc;
    116
    117	usb_free_urb(pxrc->urb);
    118}
    119
    120static int pxrc_probe(struct usb_interface *intf,
    121		      const struct usb_device_id *id)
    122{
    123	struct usb_device *udev = interface_to_usbdev(intf);
    124	struct pxrc *pxrc;
    125	struct usb_endpoint_descriptor *epirq;
    126	size_t xfer_size;
    127	void *xfer_buf;
    128	int error;
    129
    130	/*
    131	 * Locate the endpoint information. This device only has an
    132	 * interrupt endpoint.
    133	 */
    134	error = usb_find_common_endpoints(intf->cur_altsetting,
    135					  NULL, NULL, &epirq, NULL);
    136	if (error) {
    137		dev_err(&intf->dev, "Could not find endpoint\n");
    138		return error;
    139	}
    140
    141	pxrc = devm_kzalloc(&intf->dev, sizeof(*pxrc), GFP_KERNEL);
    142	if (!pxrc)
    143		return -ENOMEM;
    144
    145	mutex_init(&pxrc->pm_mutex);
    146	pxrc->intf = intf;
    147
    148	usb_set_intfdata(pxrc->intf, pxrc);
    149
    150	xfer_size = usb_endpoint_maxp(epirq);
    151	xfer_buf = devm_kmalloc(&intf->dev, xfer_size, GFP_KERNEL);
    152	if (!xfer_buf)
    153		return -ENOMEM;
    154
    155	pxrc->urb = usb_alloc_urb(0, GFP_KERNEL);
    156	if (!pxrc->urb)
    157		return -ENOMEM;
    158
    159	error = devm_add_action_or_reset(&intf->dev, pxrc_free_urb, pxrc);
    160	if (error)
    161		return error;
    162
    163	usb_fill_int_urb(pxrc->urb, udev,
    164			 usb_rcvintpipe(udev, epirq->bEndpointAddress),
    165			 xfer_buf, xfer_size, pxrc_usb_irq, pxrc, 1);
    166
    167	pxrc->input = devm_input_allocate_device(&intf->dev);
    168	if (!pxrc->input) {
    169		dev_err(&intf->dev, "couldn't allocate input device\n");
    170		return -ENOMEM;
    171	}
    172
    173	pxrc->input->name = "PXRC Flight Controller Adapter";
    174
    175	usb_make_path(udev, pxrc->phys, sizeof(pxrc->phys));
    176	strlcat(pxrc->phys, "/input0", sizeof(pxrc->phys));
    177	pxrc->input->phys = pxrc->phys;
    178
    179	usb_to_input_id(udev, &pxrc->input->id);
    180
    181	pxrc->input->open = pxrc_open;
    182	pxrc->input->close = pxrc_close;
    183
    184	input_set_capability(pxrc->input, EV_KEY, BTN_A);
    185	input_set_abs_params(pxrc->input, ABS_X, 0, 255, 0, 0);
    186	input_set_abs_params(pxrc->input, ABS_Y, 0, 255, 0, 0);
    187	input_set_abs_params(pxrc->input, ABS_RX, 0, 255, 0, 0);
    188	input_set_abs_params(pxrc->input, ABS_RY, 0, 255, 0, 0);
    189	input_set_abs_params(pxrc->input, ABS_RUDDER, 0, 255, 0, 0);
    190	input_set_abs_params(pxrc->input, ABS_THROTTLE, 0, 255, 0, 0);
    191	input_set_abs_params(pxrc->input, ABS_MISC, 0, 255, 0, 0);
    192
    193	input_set_drvdata(pxrc->input, pxrc);
    194
    195	error = input_register_device(pxrc->input);
    196	if (error)
    197		return error;
    198
    199	return 0;
    200}
    201
    202static void pxrc_disconnect(struct usb_interface *intf)
    203{
    204	/* All driver resources are devm-managed. */
    205}
    206
    207static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)
    208{
    209	struct pxrc *pxrc = usb_get_intfdata(intf);
    210
    211	mutex_lock(&pxrc->pm_mutex);
    212	if (pxrc->is_open)
    213		usb_kill_urb(pxrc->urb);
    214	mutex_unlock(&pxrc->pm_mutex);
    215
    216	return 0;
    217}
    218
    219static int pxrc_resume(struct usb_interface *intf)
    220{
    221	struct pxrc *pxrc = usb_get_intfdata(intf);
    222	int retval = 0;
    223
    224	mutex_lock(&pxrc->pm_mutex);
    225	if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
    226		retval = -EIO;
    227
    228	mutex_unlock(&pxrc->pm_mutex);
    229	return retval;
    230}
    231
    232static int pxrc_pre_reset(struct usb_interface *intf)
    233{
    234	struct pxrc *pxrc = usb_get_intfdata(intf);
    235
    236	mutex_lock(&pxrc->pm_mutex);
    237	usb_kill_urb(pxrc->urb);
    238	return 0;
    239}
    240
    241static int pxrc_post_reset(struct usb_interface *intf)
    242{
    243	struct pxrc *pxrc = usb_get_intfdata(intf);
    244	int retval = 0;
    245
    246	if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
    247		retval = -EIO;
    248
    249	mutex_unlock(&pxrc->pm_mutex);
    250
    251	return retval;
    252}
    253
    254static int pxrc_reset_resume(struct usb_interface *intf)
    255{
    256	return pxrc_resume(intf);
    257}
    258
    259static const struct usb_device_id pxrc_table[] = {
    260	{ USB_DEVICE(PXRC_VENDOR_ID, PXRC_PRODUCT_ID) },
    261	{ }
    262};
    263MODULE_DEVICE_TABLE(usb, pxrc_table);
    264
    265static struct usb_driver pxrc_driver = {
    266	.name =		"pxrc",
    267	.probe =	pxrc_probe,
    268	.disconnect =	pxrc_disconnect,
    269	.id_table =	pxrc_table,
    270	.suspend	= pxrc_suspend,
    271	.resume		= pxrc_resume,
    272	.pre_reset	= pxrc_pre_reset,
    273	.post_reset	= pxrc_post_reset,
    274	.reset_resume	= pxrc_reset_resume,
    275};
    276
    277module_usb_driver(pxrc_driver);
    278
    279MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
    280MODULE_DESCRIPTION("PhoenixRC Flight Controller Adapter");
    281MODULE_LICENSE("GPL v2");