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
;
17 static int verbose
= 0;
18 static const char *config_file
= DEFAULT_CONFIG
;
19 static struct blob_buf conf
;
21 static struct blob_attr
**messages
;
22 static int n_messages
;
24 static struct avl_tree devices
;
26 static struct libusb_context
*usb
;
27 static struct libusb_device
**usbdevs
;
30 static int parse_config(void)
37 static const struct blobmsg_policy policy
[__CONF_MAX
] = {
38 [CONF_MESSAGES
] = { .name
= "messages", .type
= BLOBMSG_TYPE_ARRAY
},
39 [CONF_DEVICES
] = { .name
= "devices", .type
= BLOBMSG_TYPE_TABLE
},
41 struct blob_attr
*tb
[__CONF_MAX
];
42 struct blob_attr
*cur
;
46 blobmsg_parse(policy
, __CONF_MAX
, tb
, blob_data(conf
.head
), blob_len(conf
.head
));
47 if (!tb
[CONF_MESSAGES
] || !tb
[CONF_DEVICES
]) {
48 fprintf(stderr
, "Configuration incomplete\n");
52 blobmsg_for_each_attr(cur
, tb
[CONF_MESSAGES
], rem
)
55 messages
= calloc(n_messages
, sizeof(*messages
));
57 blobmsg_for_each_attr(cur
, tb
[CONF_MESSAGES
], rem
)
58 messages
[n_messages
++] = cur
;
60 blobmsg_for_each_attr(cur
, tb
[CONF_DEVICES
], rem
) {
61 dev
= calloc(1, sizeof(*dev
));
62 dev
->avl
.key
= blobmsg_name(cur
);
64 avl_insert(&devices
, &dev
->avl
);
70 static int usage(const char *prog
)
72 fprintf(stderr
, "Usage: %s <command> <options>\n"
74 " -l List matching devices\n"
75 " -s Modeswitch matching devices\n"
78 " -v Verbose output\n"
79 " -c <file> Set configuration file to <file> (default: %s)\n"
80 "\n", prog
, DEFAULT_CONFIG
);
84 typedef void (*cmd_cb_t
)(struct usbdev_data
*data
);
86 static struct blob_attr
*
87 find_dev_data(struct usbdev_data
*data
, struct device
*dev
)
89 struct blob_attr
*cur
;
92 blobmsg_for_each_attr(cur
, dev
->data
, rem
) {
93 const char *name
= blobmsg_name(cur
);
97 if (!strcmp(blobmsg_name(cur
), "*"))
100 next
= strchr(name
, '=');
105 if (!strncmp(name
, "uMa", 3)) {
107 } else if (!strncmp(name
, "uPr", 3)) {
109 } else if (!strncmp(name
, "uSe", 3)) {
112 /* ignore unsupported scsi attributes */
116 if (!strcmp(val
, next
))
123 static void iterate_devs(cmd_cb_t cb
)
125 struct usbdev_data data
;
132 for (i
= 0; i
< n_usbdevs
; i
++) {
133 memset(&data
, 0, sizeof(data
));
135 if (libusb_get_device_descriptor(usbdevs
[i
], &data
.desc
))
138 sprintf(data
.idstr
, "%04x:%04x", data
.desc
.idVendor
, data
.desc
.idProduct
);
140 dev
= avl_find_element(&devices
, data
.idstr
, dev
, avl
);
144 if (libusb_open(usbdevs
[i
], &data
.devh
))
147 libusb_get_string_descriptor_ascii(
148 data
.devh
, data
.desc
.iManufacturer
,
149 (void *) data
.mfg
, sizeof(data
.mfg
));
150 libusb_get_string_descriptor_ascii(
151 data
.devh
, data
.desc
.iProduct
,
152 (void *) data
.prod
, sizeof(data
.prod
));
153 libusb_get_string_descriptor_ascii(
154 data
.devh
, data
.desc
.iSerialNumber
,
155 (void *) data
.serial
, sizeof(data
.serial
));
157 data
.info
= find_dev_data(&data
, dev
);
160 libusb_close(data
.devh
);
164 static void handle_list(struct usbdev_data
*data
)
166 fprintf(stderr
, "Found device: %s (Manufacturer: \"%s\", Product: \"%s\", Serial: \"%s\")\n",
167 data
->idstr
, data
->mfg
, data
->prod
, data
->serial
);
170 int main(int argc
, char **argv
)
176 avl_init(&devices
, avl_strcmp
, false, NULL
);
178 while ((ch
= getopt(argc
, argv
, "lsc:v")) != -1) {
187 config_file
= optarg
;
193 return usage(argv
[0]);
197 blob_buf_init(&conf
, 0);
198 if (!blobmsg_add_json_from_file(&conf
, config_file
) ||
200 fprintf(stderr
, "Failed to load config file\n");
204 ret
= libusb_init(&usb
);
206 fprintf(stderr
, "Failed to initialize libusb: %s\n", libusb_error_name(ret
));
210 n_usbdevs
= libusb_get_device_list(usb
, &usbdevs
);
212 libusb_free_device_list(usbdevs
, 1);