1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // Copyright (C) 2018 Sean Young <sean@mess.org> 4 5 #include <linux/module.h> 6 #include <linux/usb.h> 7 #include <linux/usb/input.h> 8 #include <media/rc-core.h> 9 10 /* Each bit is 250us */ 11 #define BIT_DURATION 250000 12 13 struct imon { 14 struct device *dev; 15 struct urb *ir_urb; 16 struct rc_dev *rcdev; 17 u8 ir_buf[8]; 18 char phys[64]; 19 }; 20 21 /* 22 * ffs/find_next_bit() searches in the wrong direction, so open-code our own. 23 */ 24 static inline int is_bit_set(const u8 *buf, int bit) 25 { 26 return buf[bit / 8] & (0x80 >> (bit & 7)); 27 } 28 29 static void imon_ir_data(struct imon *imon) 30 { 31 DEFINE_IR_RAW_EVENT(rawir); 32 int offset = 0, size = 5 * 8; 33 int bit; 34 35 dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf); 36 37 while (offset < size) { 38 bit = offset; 39 while (!is_bit_set(imon->ir_buf, bit) && bit < size) 40 bit++; 41 dev_dbg(imon->dev, "pulse: %d bits", bit - offset); 42 if (bit > offset) { 43 rawir.pulse = true; 44 rawir.duration = (bit - offset) * BIT_DURATION; 45 ir_raw_event_store_with_filter(imon->rcdev, &rawir); 46 } 47 48 if (bit >= size) 49 break; 50 51 offset = bit; 52 while (is_bit_set(imon->ir_buf, bit) && bit < size) 53 bit++; 54 dev_dbg(imon->dev, "space: %d bits", bit - offset); 55 56 rawir.pulse = false; 57 rawir.duration = (bit - offset) * BIT_DURATION; 58 ir_raw_event_store_with_filter(imon->rcdev, &rawir); 59 60 offset = bit; 61 } 62 63 if (imon->ir_buf[7] == 0x0a) { 64 ir_raw_event_set_idle(imon->rcdev, true); 65 ir_raw_event_handle(imon->rcdev); 66 } 67 } 68 69 static void imon_ir_rx(struct urb *urb) 70 { 71 struct imon *imon = urb->context; 72 int ret; 73 74 switch (urb->status) { 75 case 0: 76 if (imon->ir_buf[7] != 0xff) 77 imon_ir_data(imon); 78 break; 79 case -ECONNRESET: 80 case -ENOENT: 81 case -ESHUTDOWN: 82 usb_unlink_urb(urb); 83 return; 84 case -EPIPE: 85 default: 86 dev_dbg(imon->dev, "error: urb status = %d", urb->status); 87 break; 88 } 89 90 ret = usb_submit_urb(urb, GFP_ATOMIC); 91 if (ret && ret != -ENODEV) 92 dev_warn(imon->dev, "failed to resubmit urb: %d", ret); 93 } 94 95 static int imon_probe(struct usb_interface *intf, 96 const struct usb_device_id *id) 97 { 98 struct usb_endpoint_descriptor *ir_ep = NULL; 99 struct usb_host_interface *idesc; 100 struct usb_device *udev; 101 struct rc_dev *rcdev; 102 struct imon *imon; 103 int i, ret; 104 105 udev = interface_to_usbdev(intf); 106 idesc = intf->cur_altsetting; 107 108 for (i = 0; i < idesc->desc.bNumEndpoints; i++) { 109 struct usb_endpoint_descriptor *ep = &idesc->endpoint[i].desc; 110 111 if (usb_endpoint_is_int_in(ep)) { 112 ir_ep = ep; 113 break; 114 } 115 } 116 117 if (!ir_ep) { 118 dev_err(&intf->dev, "IR endpoint missing"); 119 return -ENODEV; 120 } 121 122 imon = devm_kmalloc(&intf->dev, sizeof(*imon), GFP_KERNEL); 123 if (!imon) 124 return -ENOMEM; 125 126 imon->ir_urb = usb_alloc_urb(0, GFP_KERNEL); 127 if (!imon->ir_urb) 128 return -ENOMEM; 129 130 imon->dev = &intf->dev; 131 usb_fill_int_urb(imon->ir_urb, udev, 132 usb_rcvintpipe(udev, ir_ep->bEndpointAddress), 133 imon->ir_buf, sizeof(imon->ir_buf), 134 imon_ir_rx, imon, ir_ep->bInterval); 135 136 rcdev = devm_rc_allocate_device(&intf->dev, RC_DRIVER_IR_RAW); 137 if (!rcdev) { 138 ret = -ENOMEM; 139 goto free_urb; 140 } 141 142 usb_make_path(udev, imon->phys, sizeof(imon->phys)); 143 144 rcdev->device_name = "iMON Station"; 145 rcdev->driver_name = KBUILD_MODNAME; 146 rcdev->input_phys = imon->phys; 147 usb_to_input_id(udev, &rcdev->input_id); 148 rcdev->dev.parent = &intf->dev; 149 rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; 150 rcdev->map_name = RC_MAP_IMON_RSC; 151 rcdev->rx_resolution = BIT_DURATION; 152 rcdev->priv = imon; 153 154 ret = devm_rc_register_device(&intf->dev, rcdev); 155 if (ret) 156 goto free_urb; 157 158 imon->rcdev = rcdev; 159 160 ret = usb_submit_urb(imon->ir_urb, GFP_KERNEL); 161 if (ret) 162 goto free_urb; 163 164 usb_set_intfdata(intf, imon); 165 166 return 0; 167 168 free_urb: 169 usb_free_urb(imon->ir_urb); 170 return ret; 171 } 172 173 static void imon_disconnect(struct usb_interface *intf) 174 { 175 struct imon *imon = usb_get_intfdata(intf); 176 177 usb_kill_urb(imon->ir_urb); 178 usb_free_urb(imon->ir_urb); 179 } 180 181 static const struct usb_device_id imon_table[] = { 182 /* SoundGraph iMON (IR only) -- sg_imon.inf */ 183 { USB_DEVICE(0x04e8, 0xff30) }, 184 {} 185 }; 186 187 static struct usb_driver imon_driver = { 188 .name = KBUILD_MODNAME, 189 .probe = imon_probe, 190 .disconnect = imon_disconnect, 191 .id_table = imon_table 192 }; 193 194 module_usb_driver(imon_driver); 195 196 MODULE_DESCRIPTION("Early raw iMON IR devices"); 197 MODULE_AUTHOR("Sean Young <sean@mess.org>"); 198 MODULE_LICENSE("GPL"); 199 MODULE_DEVICE_TABLE(usb, imon_table); 200