2 * IgorPlug-USB IR Receiver
4 * Copyright (C) 2014 Sean Young <sean@mess.org>
6 * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
7 * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
9 * Based on the lirc_igorplugusb.c driver:
10 * Copyright (C) 2004 Jan M. Hochstein
11 * <hochstein@algo.informatik.tu-darmstadt.de>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 #include <linux/device.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/usb.h>
27 #include <linux/usb/input.h>
28 #include <media/rc-core.h>
30 #define DRIVER_DESC "IgorPlug-USB IR Receiver"
31 #define DRIVER_NAME "igorplugusb"
35 #define MAX_PACKET (HEADERLEN + BUFLEN)
37 #define SET_INFRABUFFER_EMPTY 1
38 #define GET_INFRACODE 2
46 struct usb_ctrlrequest request
;
48 struct timer_list timer
;
50 uint8_t buf_in
[MAX_PACKET
];
55 static void igorplugusb_cmd(struct igorplugusb
*ir
, int cmd
);
57 static void igorplugusb_irdata(struct igorplugusb
*ir
, unsigned len
)
59 DEFINE_IR_RAW_EVENT(rawir
);
60 unsigned i
, start
, overflow
;
62 dev_dbg(ir
->dev
, "irdata: %*ph (len=%u)", len
, ir
->buf_in
, len
);
65 * If more than 36 pulses and spaces follow each other, the igorplugusb
66 * overwrites its buffer from the beginning. The overflow value is the
67 * last offset which was not overwritten. Everything from this offset
68 * onwards occurred before everything until this offset.
70 overflow
= ir
->buf_in
[2];
71 i
= start
= overflow
+ HEADERLEN
;
74 dev_err(ir
->dev
, "receive overflow invalid: %u", overflow
);
77 dev_warn(ir
->dev
, "receive overflow, at least %u lost",
81 rawir
.duration
= ir
->buf_in
[i
] * 85333;
84 ir_raw_event_store_with_filter(ir
->rc
, &rawir
);
90 /* add a trailing space */
91 rawir
.duration
= ir
->rc
->timeout
;
93 ir_raw_event_store_with_filter(ir
->rc
, &rawir
);
95 ir_raw_event_handle(ir
->rc
);
98 igorplugusb_cmd(ir
, SET_INFRABUFFER_EMPTY
);
101 static void igorplugusb_callback(struct urb
*urb
)
103 struct usb_ctrlrequest
*req
;
104 struct igorplugusb
*ir
= urb
->context
;
106 req
= (struct usb_ctrlrequest
*)urb
->setup_packet
;
108 switch (urb
->status
) {
110 if (req
->bRequest
== GET_INFRACODE
&&
111 urb
->actual_length
> HEADERLEN
)
112 igorplugusb_irdata(ir
, urb
->actual_length
);
113 else /* request IR */
114 mod_timer(&ir
->timer
, jiffies
+ msecs_to_jiffies(50));
123 dev_warn(ir
->dev
, "Error: urb status = %d\n", urb
->status
);
124 igorplugusb_cmd(ir
, SET_INFRABUFFER_EMPTY
);
129 static void igorplugusb_cmd(struct igorplugusb
*ir
, int cmd
)
133 ir
->request
.bRequest
= cmd
;
134 ir
->urb
->transfer_flags
= 0;
135 ret
= usb_submit_urb(ir
->urb
, GFP_ATOMIC
);
137 dev_err(ir
->dev
, "submit urb failed: %d", ret
);
140 static void igorplugusb_timer(struct timer_list
*t
)
142 struct igorplugusb
*ir
= from_timer(ir
, t
, timer
);
144 igorplugusb_cmd(ir
, GET_INFRACODE
);
147 static int igorplugusb_probe(struct usb_interface
*intf
,
148 const struct usb_device_id
*id
)
150 struct usb_device
*udev
;
151 struct usb_host_interface
*idesc
;
152 struct usb_endpoint_descriptor
*ep
;
153 struct igorplugusb
*ir
;
157 udev
= interface_to_usbdev(intf
);
158 idesc
= intf
->cur_altsetting
;
160 if (idesc
->desc
.bNumEndpoints
!= 1) {
161 dev_err(&intf
->dev
, "incorrect number of endpoints");
165 ep
= &idesc
->endpoint
[0].desc
;
166 if (!usb_endpoint_dir_in(ep
) || !usb_endpoint_xfer_control(ep
)) {
167 dev_err(&intf
->dev
, "endpoint incorrect");
171 ir
= devm_kzalloc(&intf
->dev
, sizeof(*ir
), GFP_KERNEL
);
175 ir
->dev
= &intf
->dev
;
177 timer_setup(&ir
->timer
, igorplugusb_timer
, 0);
179 ir
->request
.bRequest
= GET_INFRACODE
;
180 ir
->request
.bRequestType
= USB_TYPE_VENDOR
| USB_DIR_IN
;
181 ir
->request
.wLength
= cpu_to_le16(sizeof(ir
->buf_in
));
183 ir
->urb
= usb_alloc_urb(0, GFP_KERNEL
);
187 usb_fill_control_urb(ir
->urb
, udev
,
188 usb_rcvctrlpipe(udev
, 0), (uint8_t *)&ir
->request
,
189 ir
->buf_in
, sizeof(ir
->buf_in
), igorplugusb_callback
, ir
);
191 usb_make_path(udev
, ir
->phys
, sizeof(ir
->phys
));
193 rc
= rc_allocate_device(RC_DRIVER_IR_RAW
);
197 rc
->device_name
= DRIVER_DESC
;
198 rc
->input_phys
= ir
->phys
;
199 usb_to_input_id(udev
, &rc
->input_id
);
200 rc
->dev
.parent
= &intf
->dev
;
202 * This device can only store 36 pulses + spaces, which is not enough
203 * for the NEC protocol and many others.
205 rc
->allowed_protocols
= RC_PROTO_BIT_ALL_IR_DECODER
&
206 ~(RC_PROTO_BIT_NEC
| RC_PROTO_BIT_NECX
| RC_PROTO_BIT_NEC32
|
207 RC_PROTO_BIT_RC6_6A_20
| RC_PROTO_BIT_RC6_6A_24
|
208 RC_PROTO_BIT_RC6_6A_32
| RC_PROTO_BIT_RC6_MCE
|
209 RC_PROTO_BIT_SONY20
| RC_PROTO_BIT_SANYO
);
212 rc
->driver_name
= DRIVER_NAME
;
213 rc
->map_name
= RC_MAP_HAUPPAUGE
;
214 rc
->timeout
= MS_TO_NS(100);
215 rc
->rx_resolution
= 85333;
218 ret
= rc_register_device(rc
);
220 dev_err(&intf
->dev
, "failed to register rc device: %d", ret
);
224 usb_set_intfdata(intf
, ir
);
226 igorplugusb_cmd(ir
, SET_INFRABUFFER_EMPTY
);
230 rc_free_device(ir
->rc
);
231 usb_free_urb(ir
->urb
);
232 del_timer(&ir
->timer
);
237 static void igorplugusb_disconnect(struct usb_interface
*intf
)
239 struct igorplugusb
*ir
= usb_get_intfdata(intf
);
241 rc_unregister_device(ir
->rc
);
242 del_timer_sync(&ir
->timer
);
243 usb_set_intfdata(intf
, NULL
);
244 usb_kill_urb(ir
->urb
);
245 usb_free_urb(ir
->urb
);
248 static const struct usb_device_id igorplugusb_table
[] = {
249 /* Igor Plug USB (Atmel's Manufact. ID) */
250 { USB_DEVICE(0x03eb, 0x0002) },
251 /* Fit PC2 Infrared Adapter */
252 { USB_DEVICE(0x03eb, 0x21fe) },
253 /* Terminating entry */
257 static struct usb_driver igorplugusb_driver
= {
259 .probe
= igorplugusb_probe
,
260 .disconnect
= igorplugusb_disconnect
,
261 .id_table
= igorplugusb_table
264 module_usb_driver(igorplugusb_driver
);
266 MODULE_DESCRIPTION(DRIVER_DESC
);
267 MODULE_AUTHOR("Sean Young <sean@mess.org>");
268 MODULE_LICENSE("GPL");
269 MODULE_DEVICE_TABLE(usb
, igorplugusb_table
);