Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for Phoenix RC Flight Controller Adapter
0004  *
0005  * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/errno.h>
0010 #include <linux/slab.h>
0011 #include <linux/module.h>
0012 #include <linux/uaccess.h>
0013 #include <linux/usb.h>
0014 #include <linux/usb/input.h>
0015 #include <linux/mutex.h>
0016 #include <linux/input.h>
0017 
0018 #define PXRC_VENDOR_ID      0x1781
0019 #define PXRC_PRODUCT_ID     0x0898
0020 
0021 struct pxrc {
0022     struct input_dev    *input;
0023     struct usb_interface    *intf;
0024     struct urb      *urb;
0025     struct mutex        pm_mutex;
0026     bool            is_open;
0027     char            phys[64];
0028 };
0029 
0030 static void pxrc_usb_irq(struct urb *urb)
0031 {
0032     struct pxrc *pxrc = urb->context;
0033     u8 *data = urb->transfer_buffer;
0034     int error;
0035 
0036     switch (urb->status) {
0037     case 0:
0038         /* success */
0039         break;
0040     case -ETIME:
0041         /* this urb is timing out */
0042         dev_dbg(&pxrc->intf->dev,
0043             "%s - urb timed out - was the device unplugged?\n",
0044             __func__);
0045         return;
0046     case -ECONNRESET:
0047     case -ENOENT:
0048     case -ESHUTDOWN:
0049     case -EPIPE:
0050         /* this urb is terminated, clean up */
0051         dev_dbg(&pxrc->intf->dev, "%s - urb shutting down with status: %d\n",
0052             __func__, urb->status);
0053         return;
0054     default:
0055         dev_dbg(&pxrc->intf->dev, "%s - nonzero urb status received: %d\n",
0056             __func__, urb->status);
0057         goto exit;
0058     }
0059 
0060     if (urb->actual_length == 8) {
0061         input_report_abs(pxrc->input, ABS_X, data[0]);
0062         input_report_abs(pxrc->input, ABS_Y, data[2]);
0063         input_report_abs(pxrc->input, ABS_RX, data[3]);
0064         input_report_abs(pxrc->input, ABS_RY, data[4]);
0065         input_report_abs(pxrc->input, ABS_RUDDER, data[5]);
0066         input_report_abs(pxrc->input, ABS_THROTTLE, data[6]);
0067         input_report_abs(pxrc->input, ABS_MISC, data[7]);
0068 
0069         input_report_key(pxrc->input, BTN_A, data[1]);
0070     }
0071 
0072 exit:
0073     /* Resubmit to fetch new fresh URBs */
0074     error = usb_submit_urb(urb, GFP_ATOMIC);
0075     if (error && error != -EPERM)
0076         dev_err(&pxrc->intf->dev,
0077             "%s - usb_submit_urb failed with result: %d",
0078             __func__, error);
0079 }
0080 
0081 static int pxrc_open(struct input_dev *input)
0082 {
0083     struct pxrc *pxrc = input_get_drvdata(input);
0084     int retval;
0085 
0086     mutex_lock(&pxrc->pm_mutex);
0087     retval = usb_submit_urb(pxrc->urb, GFP_KERNEL);
0088     if (retval) {
0089         dev_err(&pxrc->intf->dev,
0090             "%s - usb_submit_urb failed, error: %d\n",
0091             __func__, retval);
0092         retval = -EIO;
0093         goto out;
0094     }
0095 
0096     pxrc->is_open = true;
0097 
0098 out:
0099     mutex_unlock(&pxrc->pm_mutex);
0100     return retval;
0101 }
0102 
0103 static void pxrc_close(struct input_dev *input)
0104 {
0105     struct pxrc *pxrc = input_get_drvdata(input);
0106 
0107     mutex_lock(&pxrc->pm_mutex);
0108     usb_kill_urb(pxrc->urb);
0109     pxrc->is_open = false;
0110     mutex_unlock(&pxrc->pm_mutex);
0111 }
0112 
0113 static void pxrc_free_urb(void *_pxrc)
0114 {
0115     struct pxrc *pxrc = _pxrc;
0116 
0117     usb_free_urb(pxrc->urb);
0118 }
0119 
0120 static int pxrc_probe(struct usb_interface *intf,
0121               const struct usb_device_id *id)
0122 {
0123     struct usb_device *udev = interface_to_usbdev(intf);
0124     struct pxrc *pxrc;
0125     struct usb_endpoint_descriptor *epirq;
0126     size_t xfer_size;
0127     void *xfer_buf;
0128     int error;
0129 
0130     /*
0131      * Locate the endpoint information. This device only has an
0132      * interrupt endpoint.
0133      */
0134     error = usb_find_common_endpoints(intf->cur_altsetting,
0135                       NULL, NULL, &epirq, NULL);
0136     if (error) {
0137         dev_err(&intf->dev, "Could not find endpoint\n");
0138         return error;
0139     }
0140 
0141     pxrc = devm_kzalloc(&intf->dev, sizeof(*pxrc), GFP_KERNEL);
0142     if (!pxrc)
0143         return -ENOMEM;
0144 
0145     mutex_init(&pxrc->pm_mutex);
0146     pxrc->intf = intf;
0147 
0148     usb_set_intfdata(pxrc->intf, pxrc);
0149 
0150     xfer_size = usb_endpoint_maxp(epirq);
0151     xfer_buf = devm_kmalloc(&intf->dev, xfer_size, GFP_KERNEL);
0152     if (!xfer_buf)
0153         return -ENOMEM;
0154 
0155     pxrc->urb = usb_alloc_urb(0, GFP_KERNEL);
0156     if (!pxrc->urb)
0157         return -ENOMEM;
0158 
0159     error = devm_add_action_or_reset(&intf->dev, pxrc_free_urb, pxrc);
0160     if (error)
0161         return error;
0162 
0163     usb_fill_int_urb(pxrc->urb, udev,
0164              usb_rcvintpipe(udev, epirq->bEndpointAddress),
0165              xfer_buf, xfer_size, pxrc_usb_irq, pxrc, 1);
0166 
0167     pxrc->input = devm_input_allocate_device(&intf->dev);
0168     if (!pxrc->input) {
0169         dev_err(&intf->dev, "couldn't allocate input device\n");
0170         return -ENOMEM;
0171     }
0172 
0173     pxrc->input->name = "PXRC Flight Controller Adapter";
0174 
0175     usb_make_path(udev, pxrc->phys, sizeof(pxrc->phys));
0176     strlcat(pxrc->phys, "/input0", sizeof(pxrc->phys));
0177     pxrc->input->phys = pxrc->phys;
0178 
0179     usb_to_input_id(udev, &pxrc->input->id);
0180 
0181     pxrc->input->open = pxrc_open;
0182     pxrc->input->close = pxrc_close;
0183 
0184     input_set_capability(pxrc->input, EV_KEY, BTN_A);
0185     input_set_abs_params(pxrc->input, ABS_X, 0, 255, 0, 0);
0186     input_set_abs_params(pxrc->input, ABS_Y, 0, 255, 0, 0);
0187     input_set_abs_params(pxrc->input, ABS_RX, 0, 255, 0, 0);
0188     input_set_abs_params(pxrc->input, ABS_RY, 0, 255, 0, 0);
0189     input_set_abs_params(pxrc->input, ABS_RUDDER, 0, 255, 0, 0);
0190     input_set_abs_params(pxrc->input, ABS_THROTTLE, 0, 255, 0, 0);
0191     input_set_abs_params(pxrc->input, ABS_MISC, 0, 255, 0, 0);
0192 
0193     input_set_drvdata(pxrc->input, pxrc);
0194 
0195     error = input_register_device(pxrc->input);
0196     if (error)
0197         return error;
0198 
0199     return 0;
0200 }
0201 
0202 static void pxrc_disconnect(struct usb_interface *intf)
0203 {
0204     /* All driver resources are devm-managed. */
0205 }
0206 
0207 static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)
0208 {
0209     struct pxrc *pxrc = usb_get_intfdata(intf);
0210 
0211     mutex_lock(&pxrc->pm_mutex);
0212     if (pxrc->is_open)
0213         usb_kill_urb(pxrc->urb);
0214     mutex_unlock(&pxrc->pm_mutex);
0215 
0216     return 0;
0217 }
0218 
0219 static int pxrc_resume(struct usb_interface *intf)
0220 {
0221     struct pxrc *pxrc = usb_get_intfdata(intf);
0222     int retval = 0;
0223 
0224     mutex_lock(&pxrc->pm_mutex);
0225     if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
0226         retval = -EIO;
0227 
0228     mutex_unlock(&pxrc->pm_mutex);
0229     return retval;
0230 }
0231 
0232 static int pxrc_pre_reset(struct usb_interface *intf)
0233 {
0234     struct pxrc *pxrc = usb_get_intfdata(intf);
0235 
0236     mutex_lock(&pxrc->pm_mutex);
0237     usb_kill_urb(pxrc->urb);
0238     return 0;
0239 }
0240 
0241 static int pxrc_post_reset(struct usb_interface *intf)
0242 {
0243     struct pxrc *pxrc = usb_get_intfdata(intf);
0244     int retval = 0;
0245 
0246     if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
0247         retval = -EIO;
0248 
0249     mutex_unlock(&pxrc->pm_mutex);
0250 
0251     return retval;
0252 }
0253 
0254 static int pxrc_reset_resume(struct usb_interface *intf)
0255 {
0256     return pxrc_resume(intf);
0257 }
0258 
0259 static const struct usb_device_id pxrc_table[] = {
0260     { USB_DEVICE(PXRC_VENDOR_ID, PXRC_PRODUCT_ID) },
0261     { }
0262 };
0263 MODULE_DEVICE_TABLE(usb, pxrc_table);
0264 
0265 static struct usb_driver pxrc_driver = {
0266     .name =     "pxrc",
0267     .probe =    pxrc_probe,
0268     .disconnect =   pxrc_disconnect,
0269     .id_table = pxrc_table,
0270     .suspend    = pxrc_suspend,
0271     .resume     = pxrc_resume,
0272     .pre_reset  = pxrc_pre_reset,
0273     .post_reset = pxrc_post_reset,
0274     .reset_resume   = pxrc_reset_resume,
0275 };
0276 
0277 module_usb_driver(pxrc_driver);
0278 
0279 MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
0280 MODULE_DESCRIPTION("PhoenixRC Flight Controller Adapter");
0281 MODULE_LICENSE("GPL v2");