1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IgorPlug-USB IR Receiver
5 * Copyright (C) 2014 Sean Young <sean@mess.org>
7 * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
8 * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
10 * Based on the lirc_igorplugusb.c driver:
11 * Copyright (C) 2004 Jan M. Hochstein
12 * <hochstein@algo.informatik.tu-darmstadt.de>
14 #include <linux/device.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/usb.h>
18 #include <linux/usb/input.h>
19 #include <media/rc-core.h>
21 #define DRIVER_DESC "IgorPlug-USB IR Receiver"
22 #define DRIVER_NAME "igorplugusb"
26 #define MAX_PACKET (HEADERLEN + BUFLEN)
28 #define SET_INFRABUFFER_EMPTY 1
29 #define GET_INFRACODE 2
37 struct usb_ctrlrequest request
;
39 struct timer_list timer
;
41 uint8_t buf_in
[MAX_PACKET
];
46 static void igorplugusb_cmd(struct igorplugusb
*ir
, int cmd
);
48 static void igorplugusb_irdata(struct igorplugusb
*ir
, unsigned len
)
50 struct ir_raw_event rawir
= {};
51 unsigned i
, start
, overflow
;
53 dev_dbg(ir
->dev
, "irdata: %*ph (len=%u)", len
, ir
->buf_in
, len
);
56 * If more than 36 pulses and spaces follow each other, the igorplugusb
57 * overwrites its buffer from the beginning. The overflow value is the
58 * last offset which was not overwritten. Everything from this offset
59 * onwards occurred before everything until this offset.
61 overflow
= ir
->buf_in
[2];
62 i
= start
= overflow
+ HEADERLEN
;
65 dev_err(ir
->dev
, "receive overflow invalid: %u", overflow
);
68 dev_warn(ir
->dev
, "receive overflow, at least %u lost",
72 rawir
.duration
= ir
->buf_in
[i
] * 85333;
75 ir_raw_event_store_with_filter(ir
->rc
, &rawir
);
81 /* add a trailing space */
82 rawir
.duration
= ir
->rc
->timeout
;
84 ir_raw_event_store_with_filter(ir
->rc
, &rawir
);
86 ir_raw_event_handle(ir
->rc
);
89 igorplugusb_cmd(ir
, SET_INFRABUFFER_EMPTY
);
92 static void igorplugusb_callback(struct urb
*urb
)
94 struct usb_ctrlrequest
*req
;
95 struct igorplugusb
*ir
= urb
->context
;
97 req
= (struct usb_ctrlrequest
*)urb
->setup_packet
;
99 switch (urb
->status
) {
101 if (req
->bRequest
== GET_INFRACODE
&&
102 urb
->actual_length
> HEADERLEN
)
103 igorplugusb_irdata(ir
, urb
->actual_length
);
104 else /* request IR */
105 mod_timer(&ir
->timer
, jiffies
+ msecs_to_jiffies(50));
114 dev_warn(ir
->dev
, "Error: urb status = %d\n", urb
->status
);
115 igorplugusb_cmd(ir
, SET_INFRABUFFER_EMPTY
);
120 static void igorplugusb_cmd(struct igorplugusb
*ir
, int cmd
)
124 ir
->request
.bRequest
= cmd
;
125 ir
->urb
->transfer_flags
= 0;
126 ret
= usb_submit_urb(ir
->urb
, GFP_ATOMIC
);
128 dev_err(ir
->dev
, "submit urb failed: %d", ret
);
131 static void igorplugusb_timer(struct timer_list
*t
)
133 struct igorplugusb
*ir
= from_timer(ir
, t
, timer
);
135 igorplugusb_cmd(ir
, GET_INFRACODE
);
138 static int igorplugusb_probe(struct usb_interface
*intf
,
139 const struct usb_device_id
*id
)
141 struct usb_device
*udev
;
142 struct usb_host_interface
*idesc
;
143 struct usb_endpoint_descriptor
*ep
;
144 struct igorplugusb
*ir
;
148 udev
= interface_to_usbdev(intf
);
149 idesc
= intf
->cur_altsetting
;
151 if (idesc
->desc
.bNumEndpoints
!= 1) {
152 dev_err(&intf
->dev
, "incorrect number of endpoints");
156 ep
= &idesc
->endpoint
[0].desc
;
157 if (!usb_endpoint_dir_in(ep
) || !usb_endpoint_xfer_control(ep
)) {
158 dev_err(&intf
->dev
, "endpoint incorrect");
162 ir
= devm_kzalloc(&intf
->dev
, sizeof(*ir
), GFP_KERNEL
);
166 ir
->dev
= &intf
->dev
;
168 timer_setup(&ir
->timer
, igorplugusb_timer
, 0);
170 ir
->request
.bRequest
= GET_INFRACODE
;
171 ir
->request
.bRequestType
= USB_TYPE_VENDOR
| USB_DIR_IN
;
172 ir
->request
.wLength
= cpu_to_le16(sizeof(ir
->buf_in
));
174 ir
->urb
= usb_alloc_urb(0, GFP_KERNEL
);
178 usb_fill_control_urb(ir
->urb
, udev
,
179 usb_rcvctrlpipe(udev
, 0), (uint8_t *)&ir
->request
,
180 ir
->buf_in
, sizeof(ir
->buf_in
), igorplugusb_callback
, ir
);
182 usb_make_path(udev
, ir
->phys
, sizeof(ir
->phys
));
184 rc
= rc_allocate_device(RC_DRIVER_IR_RAW
);
188 rc
->device_name
= DRIVER_DESC
;
189 rc
->input_phys
= ir
->phys
;
190 usb_to_input_id(udev
, &rc
->input_id
);
191 rc
->dev
.parent
= &intf
->dev
;
193 * This device can only store 36 pulses + spaces, which is not enough
194 * for the NEC protocol and many others.
196 rc
->allowed_protocols
= RC_PROTO_BIT_ALL_IR_DECODER
&
197 ~(RC_PROTO_BIT_NEC
| RC_PROTO_BIT_NECX
| RC_PROTO_BIT_NEC32
|
198 RC_PROTO_BIT_RC6_6A_20
| RC_PROTO_BIT_RC6_6A_24
|
199 RC_PROTO_BIT_RC6_6A_32
| RC_PROTO_BIT_RC6_MCE
|
200 RC_PROTO_BIT_SONY20
| RC_PROTO_BIT_SANYO
);
203 rc
->driver_name
= DRIVER_NAME
;
204 rc
->map_name
= RC_MAP_HAUPPAUGE
;
205 rc
->timeout
= MS_TO_NS(100);
206 rc
->rx_resolution
= 85333;
209 ret
= rc_register_device(rc
);
211 dev_err(&intf
->dev
, "failed to register rc device: %d", ret
);
215 usb_set_intfdata(intf
, ir
);
217 igorplugusb_cmd(ir
, SET_INFRABUFFER_EMPTY
);
221 rc_free_device(ir
->rc
);
222 usb_free_urb(ir
->urb
);
223 del_timer(&ir
->timer
);
228 static void igorplugusb_disconnect(struct usb_interface
*intf
)
230 struct igorplugusb
*ir
= usb_get_intfdata(intf
);
232 rc_unregister_device(ir
->rc
);
233 del_timer_sync(&ir
->timer
);
234 usb_set_intfdata(intf
, NULL
);
235 usb_kill_urb(ir
->urb
);
236 usb_free_urb(ir
->urb
);
239 static const struct usb_device_id igorplugusb_table
[] = {
240 /* Igor Plug USB (Atmel's Manufact. ID) */
241 { USB_DEVICE(0x03eb, 0x0002) },
242 /* Fit PC2 Infrared Adapter */
243 { USB_DEVICE(0x03eb, 0x21fe) },
244 /* Terminating entry */
248 static struct usb_driver igorplugusb_driver
= {
250 .probe
= igorplugusb_probe
,
251 .disconnect
= igorplugusb_disconnect
,
252 .id_table
= igorplugusb_table
255 module_usb_driver(igorplugusb_driver
);
257 MODULE_DESCRIPTION(DRIVER_DESC
);
258 MODULE_AUTHOR("Sean Young <sean@mess.org>");
259 MODULE_LICENSE("GPL");
260 MODULE_DEVICE_TABLE(usb
, igorplugusb_table
);