563 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3/*4 * Infrared Toy and IR Droid RC core driver5 *6 * Copyright (C) 2020 Sean Young <sean@mess.org>7 *8 * http://dangerousprototypes.com/docs/USB_IR_Toy:_Sampling_mode9 *10 * This driver is based on the lirc driver which can be found here:11 * https://sourceforge.net/p/lirc/git/ci/master/tree/plugins/irtoy.c12 * Copyright (C) 2011 Peter Kooiman <pkooiman@gmail.com>13 */14 15#include <linux/unaligned.h>16#include <linux/completion.h>17#include <linux/kernel.h>18#include <linux/module.h>19#include <linux/usb.h>20#include <linux/slab.h>21#include <linux/usb/input.h>22 23#include <media/rc-core.h>24 25static const u8 COMMAND_VERSION[] = { 'v' };26// End transmit and repeat reset command so we exit sump mode27static const u8 COMMAND_RESET[] = { 0xff, 0xff, 0, 0, 0, 0, 0 };28static const u8 COMMAND_SMODE_ENTER[] = { 's' };29static const u8 COMMAND_SMODE_EXIT[] = { 0 };30static const u8 COMMAND_TXSTART[] = { 0x26, 0x24, 0x25, 0x03 };31 32#define REPLY_XMITCOUNT 't'33#define REPLY_XMITSUCCESS 'C'34#define REPLY_VERSION 'V'35#define REPLY_SAMPLEMODEPROTO 'S'36 37#define TIMEOUT 50038 39#define LEN_XMITRES 340#define LEN_VERSION 441#define LEN_SAMPLEMODEPROTO 342 43#define MIN_FW_VERSION 2044#define UNIT_US 2145#define MAX_TIMEOUT_US (UNIT_US * U16_MAX)46 47#define MAX_PACKET 6448 49enum state {50 STATE_IRDATA,51 STATE_COMMAND_NO_RESP,52 STATE_COMMAND,53 STATE_TX,54};55 56struct irtoy {57 struct device *dev;58 struct usb_device *usbdev;59 60 struct rc_dev *rc;61 struct urb *urb_in, *urb_out;62 63 u8 *in;64 u8 *out;65 struct completion command_done;66 67 bool pulse;68 enum state state;69 70 void *tx_buf;71 uint tx_len;72 73 uint emitted;74 uint hw_version;75 uint sw_version;76 uint proto_version;77 78 char phys[64];79};80 81static void irtoy_response(struct irtoy *irtoy, u32 len)82{83 switch (irtoy->state) {84 case STATE_COMMAND:85 if (len == LEN_VERSION && irtoy->in[0] == REPLY_VERSION) {86 uint version;87 88 irtoy->in[LEN_VERSION] = 0;89 90 if (kstrtouint(irtoy->in + 1, 10, &version)) {91 dev_err(irtoy->dev, "invalid version %*phN. Please make sure you are using firmware v20 or higher",92 LEN_VERSION, irtoy->in);93 break;94 }95 96 dev_dbg(irtoy->dev, "version %s\n", irtoy->in);97 98 irtoy->hw_version = version / 100;99 irtoy->sw_version = version % 100;100 101 irtoy->state = STATE_IRDATA;102 complete(&irtoy->command_done);103 } else if (len == LEN_SAMPLEMODEPROTO &&104 irtoy->in[0] == REPLY_SAMPLEMODEPROTO) {105 uint version;106 107 irtoy->in[LEN_SAMPLEMODEPROTO] = 0;108 109 if (kstrtouint(irtoy->in + 1, 10, &version)) {110 dev_err(irtoy->dev, "invalid sample mode response %*phN",111 LEN_SAMPLEMODEPROTO, irtoy->in);112 return;113 }114 115 dev_dbg(irtoy->dev, "protocol %s\n", irtoy->in);116 117 irtoy->proto_version = version;118 119 irtoy->state = STATE_IRDATA;120 complete(&irtoy->command_done);121 } else {122 dev_err(irtoy->dev, "unexpected response to command: %*phN\n",123 len, irtoy->in);124 }125 break;126 case STATE_COMMAND_NO_RESP:127 case STATE_IRDATA: {128 struct ir_raw_event rawir = { .pulse = irtoy->pulse };129 __be16 *in = (__be16 *)irtoy->in;130 int i;131 132 for (i = 0; i < len / sizeof(__be16); i++) {133 u16 v = be16_to_cpu(in[i]);134 135 if (v == 0xffff) {136 rawir.pulse = false;137 } else {138 rawir.duration = v * UNIT_US;139 ir_raw_event_store_with_timeout(irtoy->rc,140 &rawir);141 }142 143 rawir.pulse = !rawir.pulse;144 }145 146 irtoy->pulse = rawir.pulse;147 148 ir_raw_event_handle(irtoy->rc);149 break;150 }151 case STATE_TX:152 if (irtoy->tx_len == 0) {153 if (len == LEN_XMITRES &&154 irtoy->in[0] == REPLY_XMITCOUNT) {155 u16 emitted = get_unaligned_be16(irtoy->in + 1);156 157 dev_dbg(irtoy->dev, "emitted:%u\n", emitted);158 159 irtoy->emitted = emitted;160 } else if (len == 1 &&161 irtoy->in[0] == REPLY_XMITSUCCESS) {162 irtoy->state = STATE_IRDATA;163 complete(&irtoy->command_done);164 }165 } else {166 // send next part of tx buffer167 uint space = irtoy->in[0];168 uint buf_len;169 int err;170 171 if (len != 1 || space > MAX_PACKET || space == 0) {172 dev_dbg(irtoy->dev, "packet length expected: %*phN\n",173 len, irtoy->in);174 break;175 }176 177 buf_len = min(space, irtoy->tx_len);178 179 dev_dbg(irtoy->dev, "remaining:%u sending:%u\n",180 irtoy->tx_len, buf_len);181 182 memcpy(irtoy->out, irtoy->tx_buf, buf_len);183 irtoy->urb_out->transfer_buffer_length = buf_len;184 err = usb_submit_urb(irtoy->urb_out, GFP_ATOMIC);185 if (err != 0) {186 dev_err(irtoy->dev, "fail to submit tx buf urb: %d\n",187 err);188 irtoy->state = STATE_IRDATA;189 complete(&irtoy->command_done);190 break;191 }192 193 irtoy->tx_buf += buf_len;194 irtoy->tx_len -= buf_len;195 }196 break;197 }198}199 200static void irtoy_out_callback(struct urb *urb)201{202 struct irtoy *irtoy = urb->context;203 204 if (urb->status == 0) {205 if (irtoy->state == STATE_COMMAND_NO_RESP)206 complete(&irtoy->command_done);207 } else {208 dev_warn(irtoy->dev, "out urb status: %d\n", urb->status);209 }210}211 212static void irtoy_in_callback(struct urb *urb)213{214 struct irtoy *irtoy = urb->context;215 int ret;216 217 switch (urb->status) {218 case 0:219 irtoy_response(irtoy, urb->actual_length);220 break;221 case -ECONNRESET:222 case -ENOENT:223 case -ESHUTDOWN:224 case -EPROTO:225 case -EPIPE:226 usb_unlink_urb(urb);227 return;228 default:229 dev_dbg(irtoy->dev, "in urb status: %d\n", urb->status);230 }231 232 ret = usb_submit_urb(urb, GFP_ATOMIC);233 if (ret && ret != -ENODEV)234 dev_warn(irtoy->dev, "failed to resubmit urb: %d\n", ret);235}236 237static int irtoy_command(struct irtoy *irtoy, const u8 *cmd, int cmd_len,238 enum state state)239{240 int err;241 242 init_completion(&irtoy->command_done);243 244 irtoy->state = state;245 246 memcpy(irtoy->out, cmd, cmd_len);247 irtoy->urb_out->transfer_buffer_length = cmd_len;248 249 err = usb_submit_urb(irtoy->urb_out, GFP_KERNEL);250 if (err != 0)251 return err;252 253 if (!wait_for_completion_timeout(&irtoy->command_done,254 msecs_to_jiffies(TIMEOUT))) {255 usb_kill_urb(irtoy->urb_out);256 return -ETIMEDOUT;257 }258 259 return 0;260}261 262static int irtoy_setup(struct irtoy *irtoy)263{264 int err;265 266 err = irtoy_command(irtoy, COMMAND_RESET, sizeof(COMMAND_RESET),267 STATE_COMMAND_NO_RESP);268 if (err != 0) {269 dev_err(irtoy->dev, "could not write reset command: %d\n",270 err);271 return err;272 }273 274 usleep_range(50, 50);275 276 // get version277 err = irtoy_command(irtoy, COMMAND_VERSION, sizeof(COMMAND_VERSION),278 STATE_COMMAND);279 if (err) {280 dev_err(irtoy->dev, "could not write version command: %d\n",281 err);282 return err;283 }284 285 // enter sample mode286 err = irtoy_command(irtoy, COMMAND_SMODE_ENTER,287 sizeof(COMMAND_SMODE_ENTER), STATE_COMMAND);288 if (err)289 dev_err(irtoy->dev, "could not write sample command: %d\n",290 err);291 292 return err;293}294 295/*296 * When sending IR, it is imperative that we send the IR data as quickly297 * as possible to the device, so it does not run out of IR data and298 * introduce gaps. Allocate the buffer here, and then feed the data from299 * the urb callback handler.300 */301static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count)302{303 struct irtoy *irtoy = rc->priv;304 unsigned int i, size;305 __be16 *buf;306 int err;307 308 size = sizeof(u16) * (count + 1);309 buf = kmalloc(size, GFP_KERNEL);310 if (!buf)311 return -ENOMEM;312 313 for (i = 0; i < count; i++) {314 u16 v = DIV_ROUND_CLOSEST(txbuf[i], UNIT_US);315 316 if (!v)317 v = 1;318 buf[i] = cpu_to_be16(v);319 }320 321 buf[count] = cpu_to_be16(0xffff);322 323 irtoy->tx_buf = buf;324 irtoy->tx_len = size;325 irtoy->emitted = 0;326 327 // There is an issue where if the unit is receiving IR while the328 // first TXSTART command is sent, the device might end up hanging329 // with its led on. It does not respond to any command when this330 // happens. To work around this, re-enter sample mode.331 err = irtoy_command(irtoy, COMMAND_SMODE_EXIT,332 sizeof(COMMAND_SMODE_EXIT), STATE_COMMAND_NO_RESP);333 if (err) {334 dev_err(irtoy->dev, "exit sample mode: %d\n", err);335 kfree(buf);336 return err;337 }338 339 err = irtoy_command(irtoy, COMMAND_SMODE_ENTER,340 sizeof(COMMAND_SMODE_ENTER), STATE_COMMAND);341 if (err) {342 dev_err(irtoy->dev, "enter sample mode: %d\n", err);343 kfree(buf);344 return err;345 }346 347 err = irtoy_command(irtoy, COMMAND_TXSTART, sizeof(COMMAND_TXSTART),348 STATE_TX);349 kfree(buf);350 351 if (err) {352 dev_err(irtoy->dev, "failed to send tx start command: %d\n",353 err);354 // not sure what state the device is in, reset it355 irtoy_setup(irtoy);356 return err;357 }358 359 if (size != irtoy->emitted) {360 dev_err(irtoy->dev, "expected %u emitted, got %u\n", size,361 irtoy->emitted);362 // not sure what state the device is in, reset it363 irtoy_setup(irtoy);364 return -EINVAL;365 }366 367 return count;368}369 370static int irtoy_tx_carrier(struct rc_dev *rc, uint32_t carrier)371{372 struct irtoy *irtoy = rc->priv;373 u8 buf[3];374 int err;375 376 if (carrier < 11800)377 return -EINVAL;378 379 buf[0] = 0x06;380 buf[1] = DIV_ROUND_CLOSEST(48000000, 16 * carrier) - 1;381 buf[2] = 0;382 383 err = irtoy_command(irtoy, buf, sizeof(buf), STATE_COMMAND_NO_RESP);384 if (err)385 dev_err(irtoy->dev, "could not write carrier command: %d\n",386 err);387 388 return err;389}390 391static int irtoy_probe(struct usb_interface *intf,392 const struct usb_device_id *id)393{394 struct usb_host_interface *idesc = intf->cur_altsetting;395 struct usb_device *usbdev = interface_to_usbdev(intf);396 struct usb_endpoint_descriptor *ep_in = NULL;397 struct usb_endpoint_descriptor *ep_out = NULL;398 struct usb_endpoint_descriptor *ep = NULL;399 struct irtoy *irtoy;400 struct rc_dev *rc;401 struct urb *urb;402 int i, pipe, err = -ENOMEM;403 404 for (i = 0; i < idesc->desc.bNumEndpoints; i++) {405 ep = &idesc->endpoint[i].desc;406 407 if (!ep_in && usb_endpoint_is_bulk_in(ep) &&408 usb_endpoint_maxp(ep) == MAX_PACKET)409 ep_in = ep;410 411 if (!ep_out && usb_endpoint_is_bulk_out(ep) &&412 usb_endpoint_maxp(ep) == MAX_PACKET)413 ep_out = ep;414 }415 416 if (!ep_in || !ep_out) {417 dev_err(&intf->dev, "required endpoints not found\n");418 return -ENODEV;419 }420 421 irtoy = kzalloc(sizeof(*irtoy), GFP_KERNEL);422 if (!irtoy)423 return -ENOMEM;424 425 irtoy->in = kmalloc(MAX_PACKET, GFP_KERNEL);426 if (!irtoy->in)427 goto free_irtoy;428 429 irtoy->out = kmalloc(MAX_PACKET, GFP_KERNEL);430 if (!irtoy->out)431 goto free_irtoy;432 433 rc = rc_allocate_device(RC_DRIVER_IR_RAW);434 if (!rc)435 goto free_irtoy;436 437 urb = usb_alloc_urb(0, GFP_KERNEL);438 if (!urb)439 goto free_rcdev;440 441 pipe = usb_rcvbulkpipe(usbdev, ep_in->bEndpointAddress);442 usb_fill_bulk_urb(urb, usbdev, pipe, irtoy->in, MAX_PACKET,443 irtoy_in_callback, irtoy);444 irtoy->urb_in = urb;445 446 urb = usb_alloc_urb(0, GFP_KERNEL);447 if (!urb)448 goto free_rcdev;449 450 pipe = usb_sndbulkpipe(usbdev, ep_out->bEndpointAddress);451 usb_fill_bulk_urb(urb, usbdev, pipe, irtoy->out, MAX_PACKET,452 irtoy_out_callback, irtoy);453 454 irtoy->dev = &intf->dev;455 irtoy->usbdev = usbdev;456 irtoy->rc = rc;457 irtoy->urb_out = urb;458 irtoy->pulse = true;459 460 err = usb_submit_urb(irtoy->urb_in, GFP_KERNEL);461 if (err != 0) {462 dev_err(irtoy->dev, "fail to submit in urb: %d\n", err);463 goto free_rcdev;464 }465 466 err = irtoy_setup(irtoy);467 if (err)468 goto free_rcdev;469 470 dev_info(irtoy->dev, "version: hardware %u, firmware %u.%u, protocol %u",471 irtoy->hw_version, irtoy->sw_version / 10,472 irtoy->sw_version % 10, irtoy->proto_version);473 474 if (irtoy->sw_version < MIN_FW_VERSION) {475 dev_err(irtoy->dev, "need firmware V%02u or higher",476 MIN_FW_VERSION);477 err = -ENODEV;478 goto free_rcdev;479 }480 481 usb_make_path(usbdev, irtoy->phys, sizeof(irtoy->phys));482 483 rc->device_name = "Infrared Toy";484 rc->driver_name = KBUILD_MODNAME;485 rc->input_phys = irtoy->phys;486 usb_to_input_id(usbdev, &rc->input_id);487 rc->dev.parent = &intf->dev;488 rc->priv = irtoy;489 rc->tx_ir = irtoy_tx;490 rc->s_tx_carrier = irtoy_tx_carrier;491 rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;492 rc->map_name = RC_MAP_RC6_MCE;493 rc->rx_resolution = UNIT_US;494 rc->timeout = IR_DEFAULT_TIMEOUT;495 496 /*497 * end of transmission is detected by absence of a usb packet498 * with more pulse/spaces. However, each usb packet sent can499 * contain 32 pulse/spaces, which can be quite lengthy, so there500 * can be a delay between usb packets. For example with nec there is a501 * 17ms gap between packets.502 *503 * So, make timeout a largish minimum which works with most protocols.504 */505 rc->min_timeout = MS_TO_US(40);506 rc->max_timeout = MAX_TIMEOUT_US;507 508 err = rc_register_device(rc);509 if (err)510 goto free_rcdev;511 512 usb_set_intfdata(intf, irtoy);513 514 return 0;515 516free_rcdev:517 usb_kill_urb(irtoy->urb_out);518 usb_free_urb(irtoy->urb_out);519 usb_kill_urb(irtoy->urb_in);520 usb_free_urb(irtoy->urb_in);521 rc_free_device(rc);522free_irtoy:523 kfree(irtoy->in);524 kfree(irtoy->out);525 kfree(irtoy);526 return err;527}528 529static void irtoy_disconnect(struct usb_interface *intf)530{531 struct irtoy *ir = usb_get_intfdata(intf);532 533 rc_unregister_device(ir->rc);534 usb_set_intfdata(intf, NULL);535 usb_kill_urb(ir->urb_out);536 usb_free_urb(ir->urb_out);537 usb_kill_urb(ir->urb_in);538 usb_free_urb(ir->urb_in);539 kfree(ir->in);540 kfree(ir->out);541 kfree(ir);542}543 544static const struct usb_device_id irtoy_table[] = {545 { USB_DEVICE_INTERFACE_CLASS(0x04d8, 0xfd08, USB_CLASS_CDC_DATA) },546 { USB_DEVICE_INTERFACE_CLASS(0x04d8, 0xf58b, USB_CLASS_CDC_DATA) },547 { }548};549 550static struct usb_driver irtoy_driver = {551 .name = KBUILD_MODNAME,552 .probe = irtoy_probe,553 .disconnect = irtoy_disconnect,554 .id_table = irtoy_table,555};556 557module_usb_driver(irtoy_driver);558 559MODULE_AUTHOR("Sean Young <sean@mess.org>");560MODULE_DESCRIPTION("Infrared Toy and IR Droid driver");561MODULE_LICENSE("GPL");562MODULE_DEVICE_TABLE(usb, irtoy_table);563