implement generic switching
authorFelix Fietkau <nbd@openwrt.org>
Thu, 30 May 2013 19:17:56 +0000 (21:17 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 30 May 2013 19:17:56 +0000 (21:17 +0200)
main.c
switch.c
switch.h

diff --git a/main.c b/main.c
index fca2a37..5cf6a45 100644 (file)
--- a/main.c
+++ b/main.c
@@ -19,7 +19,7 @@ static int verbose = 0;
 static const char *config_file = DEFAULT_CONFIG;
 static struct blob_buf conf;
 
-struct blob_attr **messages = NULL;
+char **messages = NULL;
 int *message_len;
 int n_messages = 0;
 
@@ -127,7 +127,7 @@ static int parse_config(void)
                }
 
                message_len[n_messages] = len;
-               messages[n_messages++] = cur;
+               messages[n_messages++] = blobmsg_data(cur);
        }
 
        blobmsg_for_each_attr(cur, tb[CONF_DEVICES], rem) {
index 15933d4..ec5baa0 100644 (file)
--- a/switch.c
+++ b/switch.c
@@ -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;
index 1c964db..441e6a3 100644 (file)
--- a/switch.h
+++ b/switch.h
@@ -12,13 +12,14 @@ struct usbdev_data {
        int interface;
        int msg_endpoint;
        int response_endpoint;
+       int release_delay;
        bool need_response;
 
        char idstr[10];
        char mfg[128], prod[128], serial[128];
 };
 
-extern struct blob_attr **messages;
+extern char **messages;
 extern int *message_len;
 extern int n_messages;