summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-05-30 21:17:56 +0200
committerFelix Fietkau <nbd@openwrt.org>2013-05-30 21:17:56 +0200
commit525e150432e84636c420e499008713f228a4f134 (patch)
tree89a7d3a7ca985e3dd155d21e8188585ea2fadc92
parent925b9857173f5086c4afeed0a09fa29496b504ae (diff)
implement generic switching
-rw-r--r--main.c4
-rw-r--r--switch.c96
-rw-r--r--switch.h3
3 files changed, 100 insertions, 3 deletions
diff --git a/main.c b/main.c
index fca2a37..5cf6a45 100644
--- 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) {
diff --git a/switch.c b/switch.c
index 15933d4..ec5baa0 100644
--- 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;
diff --git a/switch.h b/switch.h
index 1c964db..441e6a3 100644
--- 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;