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