static int iguanair_get_features(struct iguanair *ir) { int rc; /* * On cold boot, the iguanair initializes on the first packet * received but does not process that packet. Send an empty * packet. */ ir->packet->header.start = 0; ir->packet->header.direction = DIR_OUT; ir->packet->header.cmd = CMD_NOP; iguanair_send(ir, sizeof(ir->packet->header)); ir->packet->header.cmd = CMD_GET_VERSION; rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get version\n"); goto out; } if (ir->version < 0x205) { dev_err(ir->dev, "firmware 0x%04x is too old\n", ir->version); rc = -ENODEV; goto out; } ir->bufsize = 150; ir->cycle_overhead = 65; ir->packet->header.cmd = CMD_GET_BUFSIZE; rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get buffer size\n"); goto out; } if (ir->bufsize > BUF_SIZE) { dev_info(ir->dev, "buffer size %u larger than expected\n", ir->bufsize); ir->bufsize = BUF_SIZE; } ir->packet->header.cmd = CMD_GET_FEATURES; rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) dev_info(ir->dev, "failed to get features\n"); out: return rc; }
static int iguanair_get_features(struct iguanair *ir) { int rc; ir->packet->header.start = 0; ir->packet->header.direction = DIR_OUT; ir->packet->header.cmd = CMD_GET_VERSION; rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get version\n"); goto out; } if (ir->version < 0x205) { dev_err(ir->dev, "firmware 0x%04x is too old\n", ir->version); rc = -ENODEV; goto out; } ir->bufsize = 150; ir->cycle_overhead = 65; ir->packet->header.cmd = CMD_GET_BUFSIZE; rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get buffer size\n"); goto out; } if (ir->bufsize > BUF_SIZE) { dev_info(ir->dev, "buffer size %u larger than expected\n", ir->bufsize); ir->bufsize = BUF_SIZE; } ir->packet->header.cmd = CMD_GET_FEATURES; rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get features\n"); goto out; } out: return rc; }
static int iguanair_receiver(struct iguanair *ir, bool enable) { ir->packet->header.start = 0; ir->packet->header.direction = DIR_OUT; ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF; if (enable) ir_raw_event_reset(ir->rc); return iguanair_send(ir, sizeof(ir->packet->header)); }
static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) { struct iguanair *ir = dev->priv; uint8_t space; unsigned i, size, periods, bytes; int rc; mutex_lock(&ir->lock); /* convert from us to carrier periods */ for (i = space = size = 0; i < count; i++) { periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000); bytes = DIV_ROUND_UP(periods, 127); if (size + bytes > ir->bufsize) { count = i; break; } while (periods > 127) { ir->packet->payload[size++] = 127 | space; periods -= 127; } ir->packet->payload[size++] = periods | space; space ^= 0x80; } if (count == 0) { rc = -EINVAL; goto out; } ir->packet->header.start = 0; ir->packet->header.direction = DIR_OUT; ir->packet->header.cmd = CMD_SEND; ir->packet->length = size; ir->tx_overflow = false; rc = iguanair_send(ir, sizeof(*ir->packet) + size); if (rc == 0 && ir->tx_overflow) rc = -EOVERFLOW; out: mutex_unlock(&ir->lock); return rc ? rc : count; }
static int iguanair_receiver(struct iguanair *ir, bool enable) { struct packet packet = { 0, DIR_OUT, enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF }; int rc; INIT_COMPLETION(ir->completion); rc = iguanair_send(ir, &packet, sizeof(packet), NULL, NULL); if (rc) return rc; wait_for_completion_timeout(&ir->completion, TIMEOUT); return 0; }
static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) { struct iguanair *ir = dev->priv; uint8_t space, *payload; unsigned i, size, rc; struct send_packet *packet; mutex_lock(&ir->lock); /* convert from us to carrier periods */ for (i = size = 0; i < count; i++) { txbuf[i] = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000); size += (txbuf[i] + 126) / 127; } packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL); if (!packet) { rc = -ENOMEM; goto out; } if (size > ir->bufsize) { rc = -E2BIG; goto out; } packet->header.start = 0; packet->header.direction = DIR_OUT; packet->header.cmd = CMD_SEND; packet->length = size; packet->channels = ir->channels << 4; packet->busy7 = ir->busy7; packet->busy4 = ir->busy4; space = 0; payload = packet->payload; for (i = 0; i < count; i++) { unsigned periods = txbuf[i]; while (periods > 127) { *payload++ = 127 | space; periods -= 127; } *payload++ = periods | space; space ^= 0x80; } if (ir->receiver_on) { rc = iguanair_receiver(ir, false); if (rc) { dev_warn(ir->dev, "disable receiver before transmit failed\n"); goto out; } } ir->tx_overflow = false; INIT_COMPLETION(ir->completion); rc = iguanair_send(ir, packet, size + 8, NULL, NULL); if (rc == 0) { wait_for_completion_timeout(&ir->completion, TIMEOUT); if (ir->tx_overflow) rc = -EOVERFLOW; } ir->tx_overflow = false; if (ir->receiver_on) { if (iguanair_receiver(ir, true)) dev_warn(ir->dev, "re-enable receiver after transmit failed\n"); } out: mutex_unlock(&ir->lock); kfree(packet); return rc; }
static int iguanair_get_features(struct iguanair *ir) { struct packet packet; struct response_packet response; int rc, len; packet.start = 0; packet.direction = DIR_OUT; packet.cmd = CMD_GET_VERSION; rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len); if (rc) { dev_info(ir->dev, "failed to get version\n"); goto out; } if (len != 6) { dev_info(ir->dev, "failed to get version\n"); rc = -EIO; goto out; } ir->version[0] = response.data[0]; ir->version[1] = response.data[1]; ir->bufsize = 150; ir->cycle_overhead = 65; packet.cmd = CMD_GET_BUFSIZE; rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len); if (rc) { dev_info(ir->dev, "failed to get buffer size\n"); goto out; } if (len != 5) { dev_info(ir->dev, "failed to get buffer size\n"); rc = -EIO; goto out; } ir->bufsize = response.data[0]; if (ir->version[0] == 0 || ir->version[1] == 0) goto out; packet.cmd = CMD_GET_FEATURES; rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len); if (rc) { dev_info(ir->dev, "failed to get features\n"); goto out; } if (len < 5) { dev_info(ir->dev, "failed to get features\n"); rc = -EIO; goto out; } if (len > 5 && ir->version[0] >= 4) ir->cycle_overhead = response.data[1]; out: return rc; }