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