Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * IguanaWorks USB IR Transceiver support
0004  *
0005  * Copyright (C) 2012 Sean Young <sean@mess.org>
0006  */
0007 
0008 #include <linux/device.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/usb.h>
0012 #include <linux/usb/input.h>
0013 #include <linux/slab.h>
0014 #include <linux/completion.h>
0015 #include <media/rc-core.h>
0016 
0017 #define BUF_SIZE 152
0018 
0019 struct iguanair {
0020     struct rc_dev *rc;
0021 
0022     struct device *dev;
0023     struct usb_device *udev;
0024 
0025     uint16_t version;
0026     uint8_t bufsize;
0027     uint8_t cycle_overhead;
0028 
0029     /* receiver support */
0030     bool receiver_on;
0031     dma_addr_t dma_in, dma_out;
0032     uint8_t *buf_in;
0033     struct urb *urb_in, *urb_out;
0034     struct completion completion;
0035 
0036     /* transmit support */
0037     bool tx_overflow;
0038     uint32_t carrier;
0039     struct send_packet *packet;
0040 
0041     char name[64];
0042     char phys[64];
0043 };
0044 
0045 #define CMD_NOP         0x00
0046 #define CMD_GET_VERSION     0x01
0047 #define CMD_GET_BUFSIZE     0x11
0048 #define CMD_GET_FEATURES    0x10
0049 #define CMD_SEND        0x15
0050 #define CMD_EXECUTE     0x1f
0051 #define CMD_RX_OVERFLOW     0x31
0052 #define CMD_TX_OVERFLOW     0x32
0053 #define CMD_RECEIVER_ON     0x12
0054 #define CMD_RECEIVER_OFF    0x14
0055 
0056 #define DIR_IN          0xdc
0057 #define DIR_OUT         0xcd
0058 
0059 #define MAX_IN_PACKET       8u
0060 #define MAX_OUT_PACKET      (sizeof(struct send_packet) + BUF_SIZE)
0061 #define TIMEOUT         1000
0062 #define RX_RESOLUTION       21
0063 
0064 struct packet {
0065     uint16_t start;
0066     uint8_t direction;
0067     uint8_t cmd;
0068 };
0069 
0070 struct send_packet {
0071     struct packet header;
0072     uint8_t length;
0073     uint8_t channels;
0074     uint8_t busy7;
0075     uint8_t busy4;
0076     uint8_t payload[];
0077 };
0078 
0079 static void process_ir_data(struct iguanair *ir, unsigned len)
0080 {
0081     if (len >= 4 && ir->buf_in[0] == 0 && ir->buf_in[1] == 0) {
0082         switch (ir->buf_in[3]) {
0083         case CMD_GET_VERSION:
0084             if (len == 6) {
0085                 ir->version = (ir->buf_in[5] << 8) |
0086                             ir->buf_in[4];
0087                 complete(&ir->completion);
0088             }
0089             break;
0090         case CMD_GET_BUFSIZE:
0091             if (len >= 5) {
0092                 ir->bufsize = ir->buf_in[4];
0093                 complete(&ir->completion);
0094             }
0095             break;
0096         case CMD_GET_FEATURES:
0097             if (len > 5) {
0098                 ir->cycle_overhead = ir->buf_in[5];
0099                 complete(&ir->completion);
0100             }
0101             break;
0102         case CMD_TX_OVERFLOW:
0103             ir->tx_overflow = true;
0104             fallthrough;
0105         case CMD_RECEIVER_OFF:
0106         case CMD_RECEIVER_ON:
0107         case CMD_SEND:
0108             complete(&ir->completion);
0109             break;
0110         case CMD_RX_OVERFLOW:
0111             dev_warn(ir->dev, "receive overflow\n");
0112             ir_raw_event_overflow(ir->rc);
0113             break;
0114         default:
0115             dev_warn(ir->dev, "control code %02x received\n",
0116                             ir->buf_in[3]);
0117             break;
0118         }
0119     } else if (len >= 7) {
0120         struct ir_raw_event rawir = {};
0121         unsigned i;
0122         bool event = false;
0123 
0124         for (i = 0; i < 7; i++) {
0125             if (ir->buf_in[i] == 0x80) {
0126                 rawir.pulse = false;
0127                 rawir.duration = 21845;
0128             } else {
0129                 rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
0130                 rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
0131                                  RX_RESOLUTION;
0132             }
0133 
0134             if (ir_raw_event_store_with_filter(ir->rc, &rawir))
0135                 event = true;
0136         }
0137 
0138         if (event)
0139             ir_raw_event_handle(ir->rc);
0140     }
0141 }
0142 
0143 static void iguanair_rx(struct urb *urb)
0144 {
0145     struct iguanair *ir;
0146     int rc;
0147 
0148     if (!urb)
0149         return;
0150 
0151     ir = urb->context;
0152     if (!ir)
0153         return;
0154 
0155     switch (urb->status) {
0156     case 0:
0157         process_ir_data(ir, urb->actual_length);
0158         break;
0159     case -ECONNRESET:
0160     case -ENOENT:
0161     case -ESHUTDOWN:
0162         return;
0163     case -EPIPE:
0164     default:
0165         dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
0166         break;
0167     }
0168 
0169     rc = usb_submit_urb(urb, GFP_ATOMIC);
0170     if (rc && rc != -ENODEV)
0171         dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc);
0172 }
0173 
0174 static void iguanair_irq_out(struct urb *urb)
0175 {
0176     struct iguanair *ir = urb->context;
0177 
0178     if (urb->status)
0179         dev_dbg(ir->dev, "Error: out urb status = %d\n", urb->status);
0180 
0181     /* if we sent an nop packet, do not expect a response */
0182     if (urb->status == 0 && ir->packet->header.cmd == CMD_NOP)
0183         complete(&ir->completion);
0184 }
0185 
0186 static int iguanair_send(struct iguanair *ir, unsigned size)
0187 {
0188     int rc;
0189 
0190     reinit_completion(&ir->completion);
0191 
0192     ir->urb_out->transfer_buffer_length = size;
0193     rc = usb_submit_urb(ir->urb_out, GFP_KERNEL);
0194     if (rc)
0195         return rc;
0196 
0197     if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0)
0198         return -ETIMEDOUT;
0199 
0200     return rc;
0201 }
0202 
0203 static int iguanair_get_features(struct iguanair *ir)
0204 {
0205     int rc;
0206 
0207     /*
0208      * On cold boot, the iguanair initializes on the first packet
0209      * received but does not process that packet. Send an empty
0210      * packet.
0211      */
0212     ir->packet->header.start = 0;
0213     ir->packet->header.direction = DIR_OUT;
0214     ir->packet->header.cmd = CMD_NOP;
0215     iguanair_send(ir, sizeof(ir->packet->header));
0216 
0217     ir->packet->header.cmd = CMD_GET_VERSION;
0218     rc = iguanair_send(ir, sizeof(ir->packet->header));
0219     if (rc) {
0220         dev_info(ir->dev, "failed to get version\n");
0221         goto out;
0222     }
0223 
0224     if (ir->version < 0x205) {
0225         dev_err(ir->dev, "firmware 0x%04x is too old\n", ir->version);
0226         rc = -ENODEV;
0227         goto out;
0228     }
0229 
0230     ir->bufsize = 150;
0231     ir->cycle_overhead = 65;
0232 
0233     ir->packet->header.cmd = CMD_GET_BUFSIZE;
0234 
0235     rc = iguanair_send(ir, sizeof(ir->packet->header));
0236     if (rc) {
0237         dev_info(ir->dev, "failed to get buffer size\n");
0238         goto out;
0239     }
0240 
0241     if (ir->bufsize > BUF_SIZE) {
0242         dev_info(ir->dev, "buffer size %u larger than expected\n",
0243                                 ir->bufsize);
0244         ir->bufsize = BUF_SIZE;
0245     }
0246 
0247     ir->packet->header.cmd = CMD_GET_FEATURES;
0248 
0249     rc = iguanair_send(ir, sizeof(ir->packet->header));
0250     if (rc)
0251         dev_info(ir->dev, "failed to get features\n");
0252 out:
0253     return rc;
0254 }
0255 
0256 static int iguanair_receiver(struct iguanair *ir, bool enable)
0257 {
0258     ir->packet->header.start = 0;
0259     ir->packet->header.direction = DIR_OUT;
0260     ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF;
0261 
0262     return iguanair_send(ir, sizeof(ir->packet->header));
0263 }
0264 
0265 /*
0266  * The iguanair creates the carrier by busy spinning after each half period.
0267  * This is counted in CPU cycles, with the CPU running at 24MHz. It is
0268  * broken down into 7-cycles and 4-cyles delays, with a preference for
0269  * 4-cycle delays, minus the overhead of the loop itself (cycle_overhead).
0270  */
0271 static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier)
0272 {
0273     struct iguanair *ir = dev->priv;
0274 
0275     if (carrier < 25000 || carrier > 150000)
0276         return -EINVAL;
0277 
0278     if (carrier != ir->carrier) {
0279         uint32_t cycles, fours, sevens;
0280 
0281         ir->carrier = carrier;
0282 
0283         cycles = DIV_ROUND_CLOSEST(24000000, carrier * 2) -
0284                             ir->cycle_overhead;
0285 
0286         /*
0287          * Calculate minimum number of 7 cycles needed so
0288          * we are left with a multiple of 4; so we want to have
0289          * (sevens * 7) & 3 == cycles & 3
0290          */
0291         sevens = (4 - cycles) & 3;
0292         fours = (cycles - sevens * 7) / 4;
0293 
0294         /*
0295          * The firmware interprets these values as a relative offset
0296          * for a branch. Immediately following the branches, there
0297          * 4 instructions of 7 cycles (2 bytes each) and 110
0298          * instructions of 4 cycles (1 byte each). A relative branch
0299          * of 0 will execute all of them, branch further for less
0300          * cycle burning.
0301          */
0302         ir->packet->busy7 = (4 - sevens) * 2;
0303         ir->packet->busy4 = 110 - fours;
0304     }
0305 
0306     return 0;
0307 }
0308 
0309 static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask)
0310 {
0311     struct iguanair *ir = dev->priv;
0312 
0313     if (mask > 15)
0314         return 4;
0315 
0316     ir->packet->channels = mask << 4;
0317 
0318     return 0;
0319 }
0320 
0321 static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
0322 {
0323     struct iguanair *ir = dev->priv;
0324     unsigned int i, size, p, periods;
0325     int rc;
0326 
0327     /* convert from us to carrier periods */
0328     for (i = size = 0; i < count; i++) {
0329         periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
0330         while (periods) {
0331             p = min(periods, 127u);
0332             if (size >= ir->bufsize) {
0333                 rc = -EINVAL;
0334                 goto out;
0335             }
0336             ir->packet->payload[size++] = p | ((i & 1) ? 0x80 : 0);
0337             periods -= p;
0338         }
0339     }
0340 
0341     ir->packet->header.start = 0;
0342     ir->packet->header.direction = DIR_OUT;
0343     ir->packet->header.cmd = CMD_SEND;
0344     ir->packet->length = size;
0345 
0346     ir->tx_overflow = false;
0347 
0348     rc = iguanair_send(ir, sizeof(*ir->packet) + size);
0349 
0350     if (rc == 0 && ir->tx_overflow)
0351         rc = -EOVERFLOW;
0352 
0353 out:
0354     return rc ? rc : count;
0355 }
0356 
0357 static int iguanair_open(struct rc_dev *rdev)
0358 {
0359     struct iguanair *ir = rdev->priv;
0360     int rc;
0361 
0362     rc = iguanair_receiver(ir, true);
0363     if (rc == 0)
0364         ir->receiver_on = true;
0365 
0366     return rc;
0367 }
0368 
0369 static void iguanair_close(struct rc_dev *rdev)
0370 {
0371     struct iguanair *ir = rdev->priv;
0372     int rc;
0373 
0374     rc = iguanair_receiver(ir, false);
0375     ir->receiver_on = false;
0376     if (rc && rc != -ENODEV)
0377         dev_warn(ir->dev, "failed to disable receiver: %d\n", rc);
0378 }
0379 
0380 static int iguanair_probe(struct usb_interface *intf,
0381               const struct usb_device_id *id)
0382 {
0383     struct usb_device *udev = interface_to_usbdev(intf);
0384     struct iguanair *ir;
0385     struct rc_dev *rc;
0386     int ret, pipein, pipeout;
0387     struct usb_host_interface *idesc;
0388 
0389     idesc = intf->cur_altsetting;
0390     if (idesc->desc.bNumEndpoints < 2)
0391         return -ENODEV;
0392 
0393     ir = kzalloc(sizeof(*ir), GFP_KERNEL);
0394     rc = rc_allocate_device(RC_DRIVER_IR_RAW);
0395     if (!ir || !rc) {
0396         ret = -ENOMEM;
0397         goto out;
0398     }
0399 
0400     ir->buf_in = usb_alloc_coherent(udev, MAX_IN_PACKET, GFP_KERNEL,
0401                                 &ir->dma_in);
0402     ir->packet = usb_alloc_coherent(udev, MAX_OUT_PACKET, GFP_KERNEL,
0403                                 &ir->dma_out);
0404     ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
0405     ir->urb_out = usb_alloc_urb(0, GFP_KERNEL);
0406 
0407     if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out ||
0408         !usb_endpoint_is_int_in(&idesc->endpoint[0].desc) ||
0409         !usb_endpoint_is_int_out(&idesc->endpoint[1].desc)) {
0410         ret = -ENOMEM;
0411         goto out;
0412     }
0413 
0414     ir->rc = rc;
0415     ir->dev = &intf->dev;
0416     ir->udev = udev;
0417 
0418     init_completion(&ir->completion);
0419     pipeout = usb_sndintpipe(udev,
0420                 idesc->endpoint[1].desc.bEndpointAddress);
0421     usb_fill_int_urb(ir->urb_out, udev, pipeout, ir->packet, MAX_OUT_PACKET,
0422                         iguanair_irq_out, ir, 1);
0423     ir->urb_out->transfer_dma = ir->dma_out;
0424     ir->urb_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
0425 
0426     pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress);
0427     usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_IN_PACKET,
0428                              iguanair_rx, ir, 1);
0429     ir->urb_in->transfer_dma = ir->dma_in;
0430     ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
0431 
0432     ret = usb_submit_urb(ir->urb_in, GFP_KERNEL);
0433     if (ret) {
0434         dev_warn(&intf->dev, "failed to submit urb: %d\n", ret);
0435         goto out;
0436     }
0437 
0438     ret = iguanair_get_features(ir);
0439     if (ret)
0440         goto out2;
0441 
0442     snprintf(ir->name, sizeof(ir->name),
0443         "IguanaWorks USB IR Transceiver version 0x%04x", ir->version);
0444 
0445     usb_make_path(ir->udev, ir->phys, sizeof(ir->phys));
0446 
0447     rc->device_name = ir->name;
0448     rc->input_phys = ir->phys;
0449     usb_to_input_id(ir->udev, &rc->input_id);
0450     rc->dev.parent = &intf->dev;
0451     rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
0452     rc->priv = ir;
0453     rc->open = iguanair_open;
0454     rc->close = iguanair_close;
0455     rc->s_tx_mask = iguanair_set_tx_mask;
0456     rc->s_tx_carrier = iguanair_set_tx_carrier;
0457     rc->tx_ir = iguanair_tx;
0458     rc->driver_name = KBUILD_MODNAME;
0459     rc->map_name = RC_MAP_RC6_MCE;
0460     rc->min_timeout = 1;
0461     rc->timeout = IR_DEFAULT_TIMEOUT;
0462     rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
0463     rc->rx_resolution = RX_RESOLUTION;
0464 
0465     iguanair_set_tx_carrier(rc, 38000);
0466     iguanair_set_tx_mask(rc, 0);
0467 
0468     ret = rc_register_device(rc);
0469     if (ret < 0) {
0470         dev_err(&intf->dev, "failed to register rc device %d", ret);
0471         goto out2;
0472     }
0473 
0474     usb_set_intfdata(intf, ir);
0475 
0476     return 0;
0477 out2:
0478     usb_kill_urb(ir->urb_in);
0479     usb_kill_urb(ir->urb_out);
0480 out:
0481     if (ir) {
0482         usb_free_urb(ir->urb_in);
0483         usb_free_urb(ir->urb_out);
0484         usb_free_coherent(udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in);
0485         usb_free_coherent(udev, MAX_OUT_PACKET, ir->packet,
0486                                 ir->dma_out);
0487     }
0488     rc_free_device(rc);
0489     kfree(ir);
0490     return ret;
0491 }
0492 
0493 static void iguanair_disconnect(struct usb_interface *intf)
0494 {
0495     struct iguanair *ir = usb_get_intfdata(intf);
0496 
0497     rc_unregister_device(ir->rc);
0498     usb_set_intfdata(intf, NULL);
0499     usb_kill_urb(ir->urb_in);
0500     usb_kill_urb(ir->urb_out);
0501     usb_free_urb(ir->urb_in);
0502     usb_free_urb(ir->urb_out);
0503     usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in);
0504     usb_free_coherent(ir->udev, MAX_OUT_PACKET, ir->packet, ir->dma_out);
0505     kfree(ir);
0506 }
0507 
0508 static int iguanair_suspend(struct usb_interface *intf, pm_message_t message)
0509 {
0510     struct iguanair *ir = usb_get_intfdata(intf);
0511     int rc = 0;
0512 
0513     if (ir->receiver_on) {
0514         rc = iguanair_receiver(ir, false);
0515         if (rc)
0516             dev_warn(ir->dev, "failed to disable receiver for suspend\n");
0517     }
0518 
0519     usb_kill_urb(ir->urb_in);
0520     usb_kill_urb(ir->urb_out);
0521 
0522     return rc;
0523 }
0524 
0525 static int iguanair_resume(struct usb_interface *intf)
0526 {
0527     struct iguanair *ir = usb_get_intfdata(intf);
0528     int rc;
0529 
0530     rc = usb_submit_urb(ir->urb_in, GFP_KERNEL);
0531     if (rc)
0532         dev_warn(&intf->dev, "failed to submit urb: %d\n", rc);
0533 
0534     if (ir->receiver_on) {
0535         rc = iguanair_receiver(ir, true);
0536         if (rc)
0537             dev_warn(ir->dev, "failed to enable receiver after resume\n");
0538     }
0539 
0540     return rc;
0541 }
0542 
0543 static const struct usb_device_id iguanair_table[] = {
0544     { USB_DEVICE(0x1781, 0x0938) },
0545     { }
0546 };
0547 
0548 static struct usb_driver iguanair_driver = {
0549     .name = KBUILD_MODNAME,
0550     .probe = iguanair_probe,
0551     .disconnect = iguanair_disconnect,
0552     .suspend = iguanair_suspend,
0553     .resume = iguanair_resume,
0554     .reset_resume = iguanair_resume,
0555     .id_table = iguanair_table,
0556     .soft_unbind = 1    /* we want to disable receiver on unbind */
0557 };
0558 
0559 module_usb_driver(iguanair_driver);
0560 
0561 MODULE_DESCRIPTION("IguanaWorks USB IR Transceiver");
0562 MODULE_AUTHOR("Sean Young <sean@mess.org>");
0563 MODULE_LICENSE("GPL");
0564 MODULE_DEVICE_TABLE(usb, iguanair_table);
0565