staticvoid process_ir_data(struct iguanair *ir, unsigned len)
{ if (len >= 4 && ir->buf_in[0] == 0 && ir->buf_in[1] == 0) { switch (ir->buf_in[3]) { case CMD_GET_VERSION: if (len == 6) {
ir->version = (ir->buf_in[5] << 8) |
ir->buf_in[4];
complete(&ir->completion);
} break; case CMD_GET_BUFSIZE: if (len >= 5) {
ir->bufsize = ir->buf_in[4];
complete(&ir->completion);
} break; case CMD_GET_FEATURES: if (len > 5) {
ir->cycle_overhead = ir->buf_in[5];
complete(&ir->completion);
} break; case CMD_TX_OVERFLOW:
ir->tx_overflow = true;
fallthrough; case CMD_RECEIVER_OFF: case CMD_RECEIVER_ON: case CMD_SEND:
complete(&ir->completion); break; case CMD_RX_OVERFLOW:
dev_warn(ir->dev, "receive overflow\n");
ir_raw_event_overflow(ir->rc); break; default:
dev_warn(ir->dev, "control code %02x received\n",
ir->buf_in[3]); break;
}
} elseif (len >= 7) { struct ir_raw_event rawir = {}; unsigned i; bool event = false;
for (i = 0; i < 7; i++) { if (ir->buf_in[i] == 0x80) {
rawir.pulse = false;
rawir.duration = 21845;
} else {
rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
RX_RESOLUTION;
}
if (ir_raw_event_store_with_filter(ir->rc, &rawir))
event = true;
}
if (event)
ir_raw_event_handle(ir->rc);
}
}
staticvoid iguanair_rx(struct urb *urb)
{ struct iguanair *ir; int rc;
if (!urb) return;
ir = urb->context; if (!ir) return;
switch (urb->status) { case 0:
process_ir_data(ir, urb->actual_length); break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: return; case -EPIPE: default:
dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status); break;
}
rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc && rc != -ENODEV)
dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc);
}
if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0) {
usb_kill_urb(ir->urb_out); return -ETIMEDOUT;
}
return rc;
}
staticint 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;
}
/* * The iguanair creates the carrier by busy spinning after each half period. * This is counted in CPU cycles, with the CPU running at 24MHz. It is * broken down into 7-cycles and 4-cyles delays, with a preference for * 4-cycle delays, minus the overhead of the loop itself (cycle_overhead).
*/ staticint iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier)
{ struct iguanair *ir = dev->priv;
if (carrier < 25000 || carrier > 150000) return -EINVAL;
if (carrier != ir->carrier) {
uint32_t cycles, fours, sevens;
/* * Calculate minimum number of 7 cycles needed so * we are left with a multiple of 4; so we want to have * (sevens * 7) & 3 == cycles & 3
*/
sevens = (4 - cycles) & 3;
fours = (cycles - sevens * 7) / 4;
/* * The firmware interprets these values as a relative offset * for a branch. Immediately following the branches, there * 4 instructions of 7 cycles (2 bytes each) and 110 * instructions of 4 cycles (1 byte each). A relative branch * of 0 will execute all of them, branch further for less * cycle burning.
*/
ir->packet->busy7 = (4 - sevens) * 2;
ir->packet->busy4 = 110 - fours;
}
/* convert from us to carrier periods */ for (i = size = 0; i < count; i++) {
periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000); while (periods) {
p = min(periods, 127u); if (size >= ir->bufsize) {
rc = -EINVAL; goto out;
}
ir->packet->payload[size++] = p | ((i & 1) ? 0x80 : 0);
periods -= p;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.