1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Infrared Toy and IR Droid RC core driver
6 * Copyright (C) 2020 Sean Young <sean@mess.org>
8 * This driver is based on the lirc driver which can be found here:
9 * https://sourceforge.net/p/lirc/git/ci/master/tree/plugins/irtoy.c
10 * Copyright (C) 2011 Peter Kooiman <pkooiman@gmail.com>
13 #include <asm/unaligned.h>
14 #include <linux/completion.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/usb.h>
18 #include <linux/slab.h>
19 #include <linux/usb/input.h>
21 #include <media/rc-core.h>
23 static const u8 COMMAND_VERSION
[] = { 'v' };
24 // End transmit and repeat reset command so we exit sump mode
25 static const u8 COMMAND_RESET
[] = { 0xff, 0xff, 0, 0, 0, 0, 0 };
26 static const u8 COMMAND_SMODE_ENTER
[] = { 's' };
27 static const u8 COMMAND_TXSTART
[] = { 0x26, 0x24, 0x25, 0x03 };
29 #define REPLY_XMITCOUNT 't'
30 #define REPLY_XMITSUCCESS 'C'
31 #define REPLY_VERSION 'V'
32 #define REPLY_SAMPLEMODEPROTO 'S'
38 #define LEN_SAMPLEMODEPROTO 3
40 #define MIN_FW_VERSION 20
42 #define MAX_TIMEOUT_US (UNIT_US * U16_MAX)
55 struct usb_device
*usbdev
;
58 struct urb
*urb_in
, *urb_out
;
62 struct completion command_done
;
78 static void irtoy_response(struct irtoy
*irtoy
, u32 len
)
80 switch (irtoy
->state
) {
82 if (len
== LEN_VERSION
&& irtoy
->in
[0] == REPLY_VERSION
) {
85 irtoy
->in
[LEN_VERSION
] = 0;
87 if (kstrtouint(irtoy
->in
+ 1, 10, &version
)) {
88 dev_err(irtoy
->dev
, "invalid version %*phN. Please make sure you are using firmware v20 or higher",
89 LEN_VERSION
, irtoy
->in
);
93 dev_dbg(irtoy
->dev
, "version %s\n", irtoy
->in
);
95 irtoy
->hw_version
= version
/ 100;
96 irtoy
->sw_version
= version
% 100;
98 irtoy
->state
= STATE_IRDATA
;
99 complete(&irtoy
->command_done
);
100 } else if (len
== LEN_SAMPLEMODEPROTO
&&
101 irtoy
->in
[0] == REPLY_SAMPLEMODEPROTO
) {
104 irtoy
->in
[LEN_SAMPLEMODEPROTO
] = 0;
106 if (kstrtouint(irtoy
->in
+ 1, 10, &version
)) {
107 dev_err(irtoy
->dev
, "invalid sample mode response %*phN",
108 LEN_SAMPLEMODEPROTO
, irtoy
->in
);
112 dev_dbg(irtoy
->dev
, "protocol %s\n", irtoy
->in
);
114 irtoy
->proto_version
= version
;
116 irtoy
->state
= STATE_IRDATA
;
117 complete(&irtoy
->command_done
);
119 dev_err(irtoy
->dev
, "unexpected response to command: %*phN\n",
124 struct ir_raw_event rawir
= { .pulse
= irtoy
->pulse
};
125 __be16
*in
= (__be16
*)irtoy
->in
;
128 for (i
= 0; i
< len
/ sizeof(__be16
); i
++) {
129 u16 v
= be16_to_cpu(in
[i
]);
134 rawir
.duration
= v
* UNIT_US
;
135 ir_raw_event_store_with_timeout(irtoy
->rc
,
139 rawir
.pulse
= !rawir
.pulse
;
142 irtoy
->pulse
= rawir
.pulse
;
144 ir_raw_event_handle(irtoy
->rc
);
148 if (irtoy
->tx_len
== 0) {
149 if (len
== LEN_XMITRES
&&
150 irtoy
->in
[0] == REPLY_XMITCOUNT
) {
151 u16 emitted
= get_unaligned_be16(irtoy
->in
+ 1);
153 dev_dbg(irtoy
->dev
, "emitted:%u\n", emitted
);
155 irtoy
->emitted
= emitted
;
156 } else if (len
== 1 &&
157 irtoy
->in
[0] == REPLY_XMITSUCCESS
) {
158 irtoy
->state
= STATE_IRDATA
;
159 complete(&irtoy
->command_done
);
162 // send next part of tx buffer
163 uint space
= irtoy
->in
[0];
167 if (len
!= 1 || space
> MAX_PACKET
|| space
== 0) {
168 dev_err(irtoy
->dev
, "packet length expected: %*phN\n",
170 irtoy
->state
= STATE_IRDATA
;
171 complete(&irtoy
->command_done
);
175 buf_len
= min(space
, irtoy
->tx_len
);
177 dev_dbg(irtoy
->dev
, "remaining:%u sending:%u\n",
178 irtoy
->tx_len
, buf_len
);
180 memcpy(irtoy
->out
, irtoy
->tx_buf
, buf_len
);
181 irtoy
->urb_out
->transfer_buffer_length
= buf_len
;
182 err
= usb_submit_urb(irtoy
->urb_out
, GFP_ATOMIC
);
184 dev_err(irtoy
->dev
, "fail to submit tx buf urb: %d\n",
186 irtoy
->state
= STATE_IRDATA
;
187 complete(&irtoy
->command_done
);
191 irtoy
->tx_buf
+= buf_len
;
192 irtoy
->tx_len
-= buf_len
;
196 dev_err(irtoy
->dev
, "unexpected response to reset: %*phN\n",
201 static void irtoy_out_callback(struct urb
*urb
)
203 struct irtoy
*irtoy
= urb
->context
;
205 if (urb
->status
== 0) {
206 if (irtoy
->state
== STATE_RESET
)
207 complete(&irtoy
->command_done
);
209 dev_warn(irtoy
->dev
, "out urb status: %d\n", urb
->status
);
213 static void irtoy_in_callback(struct urb
*urb
)
215 struct irtoy
*irtoy
= urb
->context
;
218 if (urb
->status
== 0)
219 irtoy_response(irtoy
, urb
->actual_length
);
221 dev_dbg(irtoy
->dev
, "in urb status: %d\n", urb
->status
);
223 ret
= usb_submit_urb(urb
, GFP_ATOMIC
);
224 if (ret
&& ret
!= -ENODEV
)
225 dev_warn(irtoy
->dev
, "failed to resubmit urb: %d\n", ret
);
228 static int irtoy_command(struct irtoy
*irtoy
, const u8
*cmd
, int cmd_len
,
233 init_completion(&irtoy
->command_done
);
235 irtoy
->state
= state
;
237 memcpy(irtoy
->out
, cmd
, cmd_len
);
238 irtoy
->urb_out
->transfer_buffer_length
= cmd_len
;
240 err
= usb_submit_urb(irtoy
->urb_out
, GFP_KERNEL
);
244 if (!wait_for_completion_timeout(&irtoy
->command_done
,
245 msecs_to_jiffies(TIMEOUT
))) {
246 usb_kill_urb(irtoy
->urb_out
);
253 static int irtoy_setup(struct irtoy
*irtoy
)
257 err
= irtoy_command(irtoy
, COMMAND_RESET
, sizeof(COMMAND_RESET
),
260 dev_err(irtoy
->dev
, "could not write reset command: %d\n",
265 usleep_range(50, 50);
268 err
= irtoy_command(irtoy
, COMMAND_VERSION
, sizeof(COMMAND_VERSION
),
271 dev_err(irtoy
->dev
, "could not write version command: %d\n",
277 err
= irtoy_command(irtoy
, COMMAND_SMODE_ENTER
,
278 sizeof(COMMAND_SMODE_ENTER
), STATE_COMMAND
);
280 dev_err(irtoy
->dev
, "could not write sample command: %d\n",
287 * When sending IR, it is imperative that we send the IR data as quickly
288 * as possible to the device, so it does not run out of IR data and
289 * introduce gaps. Allocate the buffer here, and then feed the data from
290 * the urb callback handler.
292 static int irtoy_tx(struct rc_dev
*rc
, uint
*txbuf
, uint count
)
294 struct irtoy
*irtoy
= rc
->priv
;
295 unsigned int i
, size
;
299 size
= sizeof(u16
) * (count
+ 1);
300 buf
= kmalloc(size
, GFP_KERNEL
);
304 for (i
= 0; i
< count
; i
++) {
305 u16 v
= DIV_ROUND_CLOSEST(txbuf
[i
], UNIT_US
);
309 buf
[i
] = cpu_to_be16(v
);
312 buf
[count
] = cpu_to_be16(0xffff);
315 irtoy
->tx_len
= size
;
318 err
= irtoy_command(irtoy
, COMMAND_TXSTART
, sizeof(COMMAND_TXSTART
),
323 dev_err(irtoy
->dev
, "failed to send tx start command: %d\n",
325 // not sure what state the device is in, reset it
330 if (size
!= irtoy
->emitted
) {
331 dev_err(irtoy
->dev
, "expected %u emitted, got %u\n", size
,
333 // not sure what state the device is in, reset it
341 static int irtoy_probe(struct usb_interface
*intf
,
342 const struct usb_device_id
*id
)
344 struct usb_host_interface
*idesc
= intf
->cur_altsetting
;
345 struct usb_device
*usbdev
= interface_to_usbdev(intf
);
346 struct usb_endpoint_descriptor
*ep_in
= NULL
;
347 struct usb_endpoint_descriptor
*ep_out
= NULL
;
348 struct usb_endpoint_descriptor
*ep
= NULL
;
352 int i
, pipe
, err
= -ENOMEM
;
354 for (i
= 0; i
< idesc
->desc
.bNumEndpoints
; i
++) {
355 ep
= &idesc
->endpoint
[i
].desc
;
357 if (!ep_in
&& usb_endpoint_is_bulk_in(ep
) &&
358 usb_endpoint_maxp(ep
) == MAX_PACKET
)
361 if (!ep_out
&& usb_endpoint_is_bulk_out(ep
) &&
362 usb_endpoint_maxp(ep
) == MAX_PACKET
)
366 if (!ep_in
|| !ep_out
) {
367 dev_err(&intf
->dev
, "required endpoints not found\n");
371 irtoy
= kzalloc(sizeof(*irtoy
), GFP_KERNEL
);
375 irtoy
->in
= kmalloc(MAX_PACKET
, GFP_KERNEL
);
379 irtoy
->out
= kmalloc(MAX_PACKET
, GFP_KERNEL
);
383 rc
= rc_allocate_device(RC_DRIVER_IR_RAW
);
387 urb
= usb_alloc_urb(0, GFP_KERNEL
);
391 pipe
= usb_rcvbulkpipe(usbdev
, ep_in
->bEndpointAddress
);
392 usb_fill_bulk_urb(urb
, usbdev
, pipe
, irtoy
->in
, MAX_PACKET
,
393 irtoy_in_callback
, irtoy
);
396 urb
= usb_alloc_urb(0, GFP_KERNEL
);
400 pipe
= usb_sndbulkpipe(usbdev
, ep_out
->bEndpointAddress
);
401 usb_fill_bulk_urb(urb
, usbdev
, pipe
, irtoy
->out
, MAX_PACKET
,
402 irtoy_out_callback
, irtoy
);
404 irtoy
->dev
= &intf
->dev
;
405 irtoy
->usbdev
= usbdev
;
407 irtoy
->urb_out
= urb
;
410 err
= usb_submit_urb(irtoy
->urb_in
, GFP_KERNEL
);
412 dev_err(irtoy
->dev
, "fail to submit in urb: %d\n", err
);
416 err
= irtoy_setup(irtoy
);
420 dev_info(irtoy
->dev
, "version: hardware %u, firmware %u, protocol %u",
421 irtoy
->hw_version
, irtoy
->sw_version
, irtoy
->proto_version
);
423 if (irtoy
->sw_version
< MIN_FW_VERSION
) {
424 dev_err(irtoy
->dev
, "need firmware V%02u or higher",
430 usb_make_path(usbdev
, irtoy
->phys
, sizeof(irtoy
->phys
));
432 rc
->device_name
= "Infrared Toy";
433 rc
->driver_name
= KBUILD_MODNAME
;
434 rc
->input_phys
= irtoy
->phys
;
435 usb_to_input_id(usbdev
, &rc
->input_id
);
436 rc
->dev
.parent
= &intf
->dev
;
438 rc
->tx_ir
= irtoy_tx
;
439 rc
->allowed_protocols
= RC_PROTO_BIT_ALL_IR_DECODER
;
440 rc
->map_name
= RC_MAP_RC6_MCE
;
441 rc
->rx_resolution
= UNIT_US
;
442 rc
->timeout
= IR_DEFAULT_TIMEOUT
;
445 * end of transmission is detected by absence of a usb packet
446 * with more pulse/spaces. However, each usb packet sent can
447 * contain 32 pulse/spaces, which can be quite lengthy, so there
448 * can be a delay between usb packets. For example with nec there is a
449 * 17ms gap between packets.
451 * So, make timeout a largish minimum which works with most protocols.
453 rc
->min_timeout
= MS_TO_US(40);
454 rc
->max_timeout
= MAX_TIMEOUT_US
;
456 err
= rc_register_device(rc
);
460 usb_set_intfdata(intf
, irtoy
);
465 usb_kill_urb(irtoy
->urb_out
);
466 usb_free_urb(irtoy
->urb_out
);
467 usb_kill_urb(irtoy
->urb_in
);
468 usb_free_urb(irtoy
->urb_in
);
477 static void irtoy_disconnect(struct usb_interface
*intf
)
479 struct irtoy
*ir
= usb_get_intfdata(intf
);
481 rc_unregister_device(ir
->rc
);
482 usb_set_intfdata(intf
, NULL
);
483 usb_kill_urb(ir
->urb_out
);
484 usb_free_urb(ir
->urb_out
);
485 usb_kill_urb(ir
->urb_in
);
486 usb_free_urb(ir
->urb_in
);
492 static const struct usb_device_id irtoy_table
[] = {
493 { USB_DEVICE_INTERFACE_CLASS(0x04d8, 0xfd08, USB_CLASS_CDC_DATA
) },
497 static struct usb_driver irtoy_driver
= {
498 .name
= KBUILD_MODNAME
,
499 .probe
= irtoy_probe
,
500 .disconnect
= irtoy_disconnect
,
501 .id_table
= irtoy_table
,
504 module_usb_driver(irtoy_driver
);
506 MODULE_AUTHOR("Sean Young <sean@mess.org>");
507 MODULE_DESCRIPTION("Infrared Toy and IR Droid driver");
508 MODULE_LICENSE("GPL");
509 MODULE_DEVICE_TABLE(usb
, irtoy_table
);