5 #include <libubox/blobmsg_json.h>
6 #include <libubox/avl.h>
7 #include <libubox/avl-cmp.h>
10 #define DEFAULT_CONFIG "/etc/usb-mode.json"
14 struct blob_attr *data;
18 struct libusb_device_descriptor desc;
19 libusb_device_handle *devh;
20 struct blob_attr *info;
23 char mfg[128], prod[128], serial[128];
26 static int verbose = 0;
27 static const char *config_file = DEFAULT_CONFIG;
28 static struct blob_buf conf;
30 static struct blob_attr **messages;
31 static int n_messages;
33 static struct avl_tree devices;
35 static struct libusb_context *usb;
36 static struct libusb_device **usbdevs;
39 static int parse_config(void)
46 static const struct blobmsg_policy policy[__CONF_MAX] = {
47 [CONF_MESSAGES] = { .name = "messages", .type = BLOBMSG_TYPE_ARRAY },
48 [CONF_DEVICES] = { .name = "devices", .type = BLOBMSG_TYPE_TABLE },
50 struct blob_attr *tb[__CONF_MAX];
51 struct blob_attr *cur;
55 blobmsg_parse(policy, __CONF_MAX, tb, blob_data(conf.head), blob_len(conf.head));
56 if (!tb[CONF_MESSAGES] || !tb[CONF_DEVICES]) {
57 fprintf(stderr, "Configuration incomplete\n");
61 blobmsg_for_each_attr(cur, tb[CONF_MESSAGES], rem)
64 messages = calloc(n_messages, sizeof(*messages));
66 blobmsg_for_each_attr(cur, tb[CONF_MESSAGES], rem)
67 messages[n_messages++] = cur;
69 blobmsg_for_each_attr(cur, tb[CONF_DEVICES], rem) {
70 dev = calloc(1, sizeof(*dev));
71 dev->avl.key = blobmsg_name(cur);
73 avl_insert(&devices, &dev->avl);
79 static int usage(const char *prog)
81 fprintf(stderr, "Usage: %s <command> <options>\n"
83 " -l List matching devices\n"
84 " -s Modeswitch matching devices\n"
87 " -v Verbose output\n"
88 " -c <file> Set configuration file to <file> (default: %s)\n"
89 "\n", prog, DEFAULT_CONFIG);
93 typedef void (*cmd_cb_t)(struct usbdev_data *data);
95 static struct blob_attr *
96 find_dev_data(struct usbdev_data *data, struct device *dev)
98 struct blob_attr *cur;
101 blobmsg_for_each_attr(cur, dev->data, rem) {
102 const char *name = blobmsg_name(cur);
106 if (!strcmp(blobmsg_name(cur), "*"))
109 next = strchr(name, '=');
114 if (!strncmp(name, "uMa", 3)) {
116 } else if (!strncmp(name, "uPr", 3)) {
118 } else if (!strncmp(name, "uSe", 3)) {
121 /* ignore unsupported scsi attributes */
125 if (!strcmp(val, next))
132 static void iterate_devs(cmd_cb_t cb)
134 struct usbdev_data data;
141 for (i = 0; i < n_usbdevs; i++) {
142 memset(&data, 0, sizeof(data));
144 if (libusb_get_device_descriptor(usbdevs[i], &data.desc))
147 sprintf(data.idstr, "%04x:%04x", data.desc.idVendor, data.desc.idProduct);
149 dev = avl_find_element(&devices, data.idstr, dev, avl);
153 if (libusb_open(usbdevs[i], &data.devh))
156 libusb_get_string_descriptor_ascii(
157 data.devh, data.desc.iManufacturer,
158 (void *) data.mfg, sizeof(data.mfg));
159 libusb_get_string_descriptor_ascii(
160 data.devh, data.desc.iProduct,
161 (void *) data.prod, sizeof(data.prod));
162 libusb_get_string_descriptor_ascii(
163 data.devh, data.desc.iSerialNumber,
164 (void *) data.serial, sizeof(data.serial));
166 data.info = find_dev_data(&data, dev);
169 libusb_close(data.devh);
173 static void handle_list(struct usbdev_data *data)
175 fprintf(stderr, "Found device: %s (Manufacturer: \"%s\", Product: \"%s\", Serial: \"%s\")\n",
176 data->idstr, data->mfg, data->prod, data->serial);
179 static void handle_switch(struct usbdev_data *data)
183 int main(int argc, char **argv)
189 avl_init(&devices, avl_strcmp, false, NULL);
191 while ((ch = getopt(argc, argv, "lsc:v")) != -1) {
200 config_file = optarg;
206 return usage(argv[0]);
210 blob_buf_init(&conf, 0);
211 if (!blobmsg_add_json_from_file(&conf, config_file) ||
213 fprintf(stderr, "Failed to load config file\n");
217 ret = libusb_init(&usb);
219 fprintf(stderr, "Failed to initialize libusb: %s\n", libusb_error_name(ret));
223 n_usbdevs = libusb_get_device_list(usb, &usbdevs);
225 libusb_free_device_list(usbdevs, 1);