diff options
Diffstat (limited to 'switch.c')
-rw-r--r-- | switch.c | 96 |
1 files changed, 96 insertions, 0 deletions
@@ -1,9 +1,14 @@ +#include <unistd.h> #include "switch.h" enum { DATA_MODE, DATA_MSG, DATA_INTERFACE, + DATA_MSG_EP, + DATA_RES_EP, + DATA_RESPONSE, + DATA_RELEASE_DELAY, __DATA_MAX }; @@ -12,9 +17,85 @@ static void detach_driver(struct usbdev_data *data) libusb_detach_kernel_driver(data->devh, data->interface); } +static int send_msg(struct usbdev_data *data, int msg) +{ + int transferred; + + return libusb_bulk_transfer(data->devh, data->msg_endpoint, + (void *) messages[msg], message_len[msg], + &transferred, 3000); +} + +static int read_response(struct usbdev_data *data, int len) +{ + unsigned char *buf; + int ret, transferred; + + if (len < 13) + len = 13; + buf = alloca(len); + ret = libusb_bulk_transfer(data->devh, data->response_endpoint, + buf, len, &transferred, 3000); + libusb_bulk_transfer(data->devh, data->response_endpoint, + buf, 13, &transferred, 100); + return ret; +} + +static void send_messages(struct usbdev_data *data, struct blob_attr *attr) +{ + struct blob_attr *cur; + int rem; + + libusb_claim_interface(data->devh, data->interface); + libusb_clear_halt(data->devh, data->msg_endpoint); + + blobmsg_for_each_attr(cur, attr, rem) { + int msg, len; + + if (blobmsg_type(cur) != BLOBMSG_TYPE_INT32) { + fprintf(stderr, "Invalid data in message list\n"); + return; + } + + msg = blobmsg_get_u32(cur); + if (msg >= n_messages) { + fprintf(stderr, "Message index out of range!\n"); + return; + } + + if (send_msg(data, msg)) { + fprintf(stderr, "Failed to send switch message\n"); + continue; + } + + if (!data->need_response) + continue; + + if (!memcmp(messages[msg], "\x55\x53\x42\x43", 4)) + len = 13; + else + len = message_len[msg]; + + if (read_response(data, len)) + return; + } + + libusb_clear_halt(data->devh, data->msg_endpoint); + libusb_clear_halt(data->devh, data->response_endpoint); + + usleep(200000); + + if (data->release_delay) + usleep(data->release_delay * 1000); + + libusb_release_interface(data->devh, data->interface); + return; +} + static void handle_generic(struct usbdev_data *data, struct blob_attr **tb) { detach_driver(data); + send_messages(data, tb[DATA_MSG]); } static void handle_huawei(struct usbdev_data *data, struct blob_attr **tb) @@ -101,6 +182,9 @@ void handle_switch(struct usbdev_data *data) [DATA_MODE] = { .name = "mode", .type = BLOBMSG_TYPE_STRING }, [DATA_MSG] = { .name = "msg", .type = BLOBMSG_TYPE_ARRAY }, [DATA_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_INT32 }, + [DATA_MSG_EP] = { .name = "msg_endpoint", .type = BLOBMSG_TYPE_INT32 }, + [DATA_RES_EP] = { .name = "response_endpoint", .type = BLOBMSG_TYPE_INT32 }, + [DATA_RESPONSE] = { .name = "response", .type = BLOBMSG_TYPE_INT32 }, }; struct blob_attr *tb[__DATA_MAX]; int mode = MODE_GENERIC; @@ -110,6 +194,18 @@ void handle_switch(struct usbdev_data *data) if (tb[DATA_INTERFACE]) data->interface = blobmsg_get_u32(tb[DATA_INTERFACE]); + if (tb[DATA_MSG_EP]) + data->msg_endpoint = blobmsg_get_u32(tb[DATA_MSG_EP]); + + if (tb[DATA_RES_EP]) + data->response_endpoint = blobmsg_get_u32(tb[DATA_RES_EP]); + + if (tb[DATA_RELEASE_DELAY]) + data->release_delay = blobmsg_get_u32(tb[DATA_RELEASE_DELAY]); + + if (tb[DATA_RESPONSE]) + data->need_response = blobmsg_get_bool(tb[DATA_RESPONSE]); + if (tb[DATA_MODE]) { const char *modestr; int i; |