xref: /OK3568_Linux_fs/kernel/drivers/media/rc/imon_raw.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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