Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // Copyright (C) 2018 Sean Young <sean@mess.org>
0004 
0005 #include <linux/module.h>
0006 #include <linux/usb.h>
0007 #include <linux/usb/input.h>
0008 #include <media/rc-core.h>
0009 
0010 /* Each bit is 250us */
0011 #define BIT_DURATION 250
0012 
0013 struct imon {
0014     struct device *dev;
0015     struct urb *ir_urb;
0016     struct rc_dev *rcdev;
0017     __be64 *ir_buf;
0018     char phys[64];
0019 };
0020 
0021 /*
0022  * The first 5 bytes of data represent IR pulse or space. Each bit, starting
0023  * from highest bit in the first byte, represents 250µs of data. It is 1
0024  * for space and 0 for pulse.
0025  *
0026  * The station sends 10 packets, and the 7th byte will be number 1 to 10, so
0027  * when we receive 10 we assume all the data has arrived.
0028  */
0029 static void imon_ir_data(struct imon *imon)
0030 {
0031     struct ir_raw_event rawir = {};
0032     u64 data = be64_to_cpup(imon->ir_buf);
0033     u8 packet_no = data & 0xff;
0034     int offset = 40;
0035     int bit;
0036 
0037     if (packet_no == 0xff)
0038         return;
0039 
0040     dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf);
0041 
0042     /*
0043      * Only the first 5 bytes contain IR data. Right shift so we move
0044      * the IR bits to the lower 40 bits.
0045      */
0046     data >>= 24;
0047 
0048     do {
0049         /*
0050          * Find highest set bit which is less or equal to offset
0051          *
0052          * offset is the bit above (base 0) where we start looking.
0053          *
0054          * data & (BIT_ULL(offset) - 1) masks off any unwanted bits,
0055          * so we have just bits less than offset.
0056          *
0057          * fls will tell us the highest bit set plus 1 (or 0 if no
0058          * bits are set).
0059          */
0060         rawir.pulse = !rawir.pulse;
0061         bit = fls64(data & (BIT_ULL(offset) - 1));
0062         if (bit < offset) {
0063             dev_dbg(imon->dev, "%s: %d bits",
0064                 rawir.pulse ? "pulse" : "space", offset - bit);
0065             rawir.duration = (offset - bit) * BIT_DURATION;
0066             ir_raw_event_store_with_filter(imon->rcdev, &rawir);
0067 
0068             offset = bit;
0069         }
0070 
0071         data = ~data;
0072     } while (offset > 0);
0073 
0074     if (packet_no == 0x0a && !imon->rcdev->idle) {
0075         ir_raw_event_set_idle(imon->rcdev, true);
0076         ir_raw_event_handle(imon->rcdev);
0077     }
0078 }
0079 
0080 static void imon_ir_rx(struct urb *urb)
0081 {
0082     struct imon *imon = urb->context;
0083     int ret;
0084 
0085     switch (urb->status) {
0086     case 0:
0087         imon_ir_data(imon);
0088         break;
0089     case -ECONNRESET:
0090     case -ENOENT:
0091     case -ESHUTDOWN:
0092         usb_unlink_urb(urb);
0093         return;
0094     case -EPIPE:
0095     default:
0096         dev_dbg(imon->dev, "error: urb status = %d", urb->status);
0097         break;
0098     }
0099 
0100     ret = usb_submit_urb(urb, GFP_ATOMIC);
0101     if (ret && ret != -ENODEV)
0102         dev_warn(imon->dev, "failed to resubmit urb: %d", ret);
0103 }
0104 
0105 static int imon_probe(struct usb_interface *intf,
0106               const struct usb_device_id *id)
0107 {
0108     struct usb_endpoint_descriptor *ir_ep = NULL;
0109     struct usb_host_interface *idesc;
0110     struct usb_device *udev;
0111     struct rc_dev *rcdev;
0112     struct imon *imon;
0113     int i, ret;
0114 
0115     udev = interface_to_usbdev(intf);
0116     idesc = intf->cur_altsetting;
0117 
0118     for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
0119         struct usb_endpoint_descriptor *ep = &idesc->endpoint[i].desc;
0120 
0121         if (usb_endpoint_is_int_in(ep)) {
0122             ir_ep = ep;
0123             break;
0124         }
0125     }
0126 
0127     if (!ir_ep) {
0128         dev_err(&intf->dev, "IR endpoint missing");
0129         return -ENODEV;
0130     }
0131 
0132     imon = devm_kmalloc(&intf->dev, sizeof(*imon), GFP_KERNEL);
0133     if (!imon)
0134         return -ENOMEM;
0135 
0136     imon->ir_urb = usb_alloc_urb(0, GFP_KERNEL);
0137     if (!imon->ir_urb)
0138         return -ENOMEM;
0139 
0140     imon->ir_buf = kmalloc(sizeof(__be64), GFP_KERNEL);
0141     if (!imon->ir_buf) {
0142         ret = -ENOMEM;
0143         goto free_urb;
0144     }
0145 
0146     imon->dev = &intf->dev;
0147     usb_fill_int_urb(imon->ir_urb, udev,
0148              usb_rcvintpipe(udev, ir_ep->bEndpointAddress),
0149              imon->ir_buf, sizeof(__be64),
0150              imon_ir_rx, imon, ir_ep->bInterval);
0151 
0152     rcdev = devm_rc_allocate_device(&intf->dev, RC_DRIVER_IR_RAW);
0153     if (!rcdev) {
0154         ret = -ENOMEM;
0155         goto free_urb;
0156     }
0157 
0158     usb_make_path(udev, imon->phys, sizeof(imon->phys));
0159 
0160     rcdev->device_name = "iMON Station";
0161     rcdev->driver_name = KBUILD_MODNAME;
0162     rcdev->input_phys = imon->phys;
0163     usb_to_input_id(udev, &rcdev->input_id);
0164     rcdev->dev.parent = &intf->dev;
0165     rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
0166     rcdev->map_name = RC_MAP_IMON_RSC;
0167     rcdev->rx_resolution = BIT_DURATION;
0168     rcdev->priv = imon;
0169 
0170     ret = devm_rc_register_device(&intf->dev, rcdev);
0171     if (ret)
0172         goto free_urb;
0173 
0174     imon->rcdev = rcdev;
0175 
0176     ret = usb_submit_urb(imon->ir_urb, GFP_KERNEL);
0177     if (ret)
0178         goto free_urb;
0179 
0180     usb_set_intfdata(intf, imon);
0181 
0182     return 0;
0183 
0184 free_urb:
0185     usb_free_urb(imon->ir_urb);
0186     kfree(imon->ir_buf);
0187     return ret;
0188 }
0189 
0190 static void imon_disconnect(struct usb_interface *intf)
0191 {
0192     struct imon *imon = usb_get_intfdata(intf);
0193 
0194     usb_kill_urb(imon->ir_urb);
0195     usb_free_urb(imon->ir_urb);
0196     kfree(imon->ir_buf);
0197 }
0198 
0199 static const struct usb_device_id imon_table[] = {
0200     /* SoundGraph iMON (IR only) -- sg_imon.inf */
0201     { USB_DEVICE(0x04e8, 0xff30) },
0202     {}
0203 };
0204 
0205 static struct usb_driver imon_driver = {
0206     .name = KBUILD_MODNAME,
0207     .probe = imon_probe,
0208     .disconnect = imon_disconnect,
0209     .id_table = imon_table
0210 };
0211 
0212 module_usb_driver(imon_driver);
0213 
0214 MODULE_DESCRIPTION("Early raw iMON IR devices");
0215 MODULE_AUTHOR("Sean Young <sean@mess.org>");
0216 MODULE_LICENSE("GPL");
0217 MODULE_DEVICE_TABLE(usb, imon_table);