static void handle_outbound(struct aura_node *node, struct aura_object *o, struct aura_buffer *buf) { int ret = -EIO; if (OPCODE("export")) { int gpio = aura_buffer_get_u32(buf); slog(4, SLOG_DEBUG, "gpio: export %d", gpio); ret = gpio_export(gpio); } else if (OPCODE("write")) { int gpio = aura_buffer_get_u32(buf); int value = aura_buffer_get_u32(buf); slog(4, SLOG_DEBUG, "gpio: write gpio %d value %d", gpio, value); ret = gpio_write(gpio, value); } else if (OPCODE("in")) { int gpio = aura_buffer_get_u32(buf); ret = gpio_in(gpio); } else if (OPCODE("out")) { int gpio = aura_buffer_get_u32(buf); ret = gpio_out(gpio); } else if (OPCODE("read")) { int gpio = aura_buffer_get_u32(buf); ret = gpio_read(gpio, &gpio); aura_buffer_rewind(buf); aura_buffer_put_u32(buf, gpio); } slog(0, SLOG_DEBUG, "gpio ret = %d", ret); if (ret) { aura_call_fail(node, o); return; } aura_queue_buffer(&node->inbound_buffers, buf); }
static void cb_event_readout_done(struct libusb_transfer *transfer) { struct aura_node *node = transfer->user_data; struct usb_dev_info *inf = aura_get_transportdata(node); struct usb_event_packet *evt; struct aura_buffer *buf = inf->current_buffer; struct aura_object *o; if (0 != check_control(transfer)) goto ignore; if (transfer->actual_length < sizeof(struct usb_event_packet)) goto ignore; evt = (struct usb_event_packet *) libusb_control_transfer_get_data(transfer); o = aura_etable_find_id(node->tbl, evt->id); if (!o) { slog(0, SLOG_ERROR, "usb: got bogus event id from device %d, resetting", evt->id); goto panic; } if ((transfer->actual_length - LIBUSB_CONTROL_SETUP_SIZE) < (sizeof(struct usb_event_packet) + o->retlen)) { slog(0, SLOG_ERROR, "usb: short read for evt %d: %d bytes expected %d got", evt->id, o->retlen + sizeof(struct usb_event_packet), transfer->actual_length); goto panic; } inf->pending--; slog(4, SLOG_DEBUG, "Event readout completed, %d bytes, %d evt left", transfer->actual_length, inf->pending); buf->object = o; /* Position the buffer at the start of the responses */ buf->pos = LIBUSB_CONTROL_SETUP_SIZE + sizeof(struct usb_event_packet); aura_queue_buffer(&node->inbound_buffers, buf); return; panic: usb_panic_and_reset_state(node); ignore: aura_buffer_release(node, buf); inf->current_buffer = NULL; return; }
/* This one is small, but tricky */ static void aura_handle_inbound(struct aura_node *node) { while(1) { struct aura_buffer *buf; struct aura_object *o; buf = aura_dequeue_buffer(&node->inbound_buffers); if (!buf) break; o = buf->object; node->current_object = o; aura_buffer_rewind(buf); slog(4, SLOG_DEBUG, "Handling %s id %d (%s) sync_call_running=%d", object_is_method(o) ? "response" : "event", o->id, o->name, node->sync_call_running); if (object_is_method(o) && !o->pending) { slog(0, SLOG_WARN, "Dropping orphan call result %d (%s)", o->id, o->name); aura_buffer_release(node, buf); } else if (o->calldonecb) { slog(4, SLOG_DEBUG, "Callback for method/event %d (%s)", o->id, o->name); o->calldonecb(node, AURA_CALL_COMPLETED, buf, o->arg); aura_buffer_release(node, buf); } else if (object_is_method(o) && (node->sync_call_running)) { slog(4, SLOG_DEBUG, "Completing call for method %d (%s)", o->id, o->name); node->sync_call_result = AURA_CALL_COMPLETED; node->sync_ret_buf = buf; o->pending--; if (o->pending < 0) BUG(node, "Internal BUG: pending evt count lesser than zero"); } else { /* This one is tricky. We have an event with no callback */ if (node->sync_event_max > 0) { /* Queue it up into event_queue if it's enabled */ /* If we have an overrun - drop the oldest event to free up space first*/ if (node->sync_event_max <= node->sync_event_count) { struct aura_buffer *todrop; const struct aura_object *dummy; int ret = aura_get_next_event(node, &dummy, &todrop); if (ret != 0) BUG(node, "Internal bug, no next event"); aura_buffer_release(node, todrop); } /* Now just queue the next one */ aura_queue_buffer(&node->event_buffers, buf); node->sync_event_count++; slog(4, SLOG_DEBUG, "Queued event %d (%s) for sync readout", o->id, o->name); } else { /* Last resort - try the catch-all event callback */ if (node->unhandled_evt_cb) node->unhandled_evt_cb(node, buf, node->unhandled_evt_arg); else /* Or just drop it with a warning */ slog(0, SLOG_WARN, "Dropping event %d (%s)", o->id, o->name); aura_buffer_release(node, buf); } } } node->current_object = NULL; }