6 #include <libubox/blobmsg_json.h>
7 #include <libubox/avl.h>
8 #include <libubox/avl-cmp.h>
11 #define DEFAULT_CONFIG "/etc/usb-mode.json"
15 struct blob_attr
*data
;
18 static int verbose
= 0;
19 static const char *config_file
= DEFAULT_CONFIG
;
20 static struct blob_buf conf
;
22 static struct blob_attr
**messages
;
23 static int n_messages
;
25 static struct avl_tree devices
;
27 static struct libusb_context
*usb
;
28 static struct libusb_device
**usbdevs
;
31 static int hex2num(char c
)
33 if (c
>= '0' && c
<= '9')
37 if (c
>= 'A' && c
<= 'F')
43 static int hex2byte(const char *hex
)
58 static int hexstr2bin(const char *hex
, char *buffer
, int len
)
60 const char *ipos
= hex
;
64 for (i
= 0; i
< len
; i
++) {
76 static bool convert_message(struct blob_attr
*attr
)
84 data
= blobmsg_data(attr
);
89 return !hexstr2bin(data
, data
, len
/ 2);
92 static int parse_config(void)
99 static const struct blobmsg_policy policy
[__CONF_MAX
] = {
100 [CONF_MESSAGES
] = { .name
= "messages", .type
= BLOBMSG_TYPE_ARRAY
},
101 [CONF_DEVICES
] = { .name
= "devices", .type
= BLOBMSG_TYPE_TABLE
},
103 struct blob_attr
*tb
[__CONF_MAX
];
104 struct blob_attr
*cur
;
108 blobmsg_parse(policy
, __CONF_MAX
, tb
, blob_data(conf
.head
), blob_len(conf
.head
));
109 if (!tb
[CONF_MESSAGES
] || !tb
[CONF_DEVICES
]) {
110 fprintf(stderr
, "Configuration incomplete\n");
114 blobmsg_for_each_attr(cur
, tb
[CONF_MESSAGES
], rem
)
117 messages
= calloc(n_messages
, sizeof(*messages
));
119 blobmsg_for_each_attr(cur
, tb
[CONF_MESSAGES
], rem
) {
120 if (!convert_message(cur
)) {
121 fprintf(stderr
, "Invalid data in message %d\n", n_messages
);
124 messages
[n_messages
++] = cur
;
127 blobmsg_for_each_attr(cur
, tb
[CONF_DEVICES
], rem
) {
128 dev
= calloc(1, sizeof(*dev
));
129 dev
->avl
.key
= blobmsg_name(cur
);
131 avl_insert(&devices
, &dev
->avl
);
137 static int usage(const char *prog
)
139 fprintf(stderr
, "Usage: %s <command> <options>\n"
141 " -l List matching devices\n"
142 " -s Modeswitch matching devices\n"
145 " -v Verbose output\n"
146 " -c <file> Set configuration file to <file> (default: %s)\n"
147 "\n", prog
, DEFAULT_CONFIG
);
151 typedef void (*cmd_cb_t
)(struct usbdev_data
*data
);
153 static struct blob_attr
*
154 find_dev_data(struct usbdev_data
*data
, struct device
*dev
)
156 struct blob_attr
*cur
;
159 blobmsg_for_each_attr(cur
, dev
->data
, rem
) {
160 const char *name
= blobmsg_name(cur
);
164 if (!strcmp(blobmsg_name(cur
), "*"))
167 next
= strchr(name
, '=');
172 if (!strncmp(name
, "uMa", 3)) {
174 } else if (!strncmp(name
, "uPr", 3)) {
176 } else if (!strncmp(name
, "uSe", 3)) {
179 /* ignore unsupported scsi attributes */
183 if (!strcmp(val
, next
))
191 parse_interface_config(libusb_device
*dev
, struct usbdev_data
*data
)
193 struct libusb_config_descriptor
*config
;
194 const struct libusb_interface
*iface
;
196 data
->interface
= -1;
197 if (libusb_get_config_descriptor(dev
, 0, &config
))
200 data
->config
= config
;
201 if (!config
->bNumInterfaces
)
204 iface
= &config
->interface
[0];
205 if (!iface
->num_altsetting
)
208 data
->interface
= iface
->altsetting
[0].bInterfaceNumber
;
211 static void iterate_devs(cmd_cb_t cb
)
213 struct usbdev_data data
;
220 for (i
= 0; i
< n_usbdevs
; i
++) {
221 memset(&data
, 0, sizeof(data
));
223 if (libusb_get_device_descriptor(usbdevs
[i
], &data
.desc
))
226 sprintf(data
.idstr
, "%04x:%04x", data
.desc
.idVendor
, data
.desc
.idProduct
);
228 dev
= avl_find_element(&devices
, data
.idstr
, dev
, avl
);
232 if (libusb_open(usbdevs
[i
], &data
.devh
))
235 libusb_get_string_descriptor_ascii(
236 data
.devh
, data
.desc
.iManufacturer
,
237 (void *) data
.mfg
, sizeof(data
.mfg
));
238 libusb_get_string_descriptor_ascii(
239 data
.devh
, data
.desc
.iProduct
,
240 (void *) data
.prod
, sizeof(data
.prod
));
241 libusb_get_string_descriptor_ascii(
242 data
.devh
, data
.desc
.iSerialNumber
,
243 (void *) data
.serial
, sizeof(data
.serial
));
245 parse_interface_config(usbdevs
[i
], &data
);
247 data
.info
= find_dev_data(&data
, dev
);
252 libusb_free_config_descriptor(data
.config
);
254 libusb_close(data
.devh
);
258 static void handle_list(struct usbdev_data
*data
)
260 fprintf(stderr
, "Found device: %s (Manufacturer: \"%s\", Product: \"%s\", Serial: \"%s\")\n",
261 data
->idstr
, data
->mfg
, data
->prod
, data
->serial
);
264 int main(int argc
, char **argv
)
270 avl_init(&devices
, avl_strcmp
, false, NULL
);
272 while ((ch
= getopt(argc
, argv
, "lsc:v")) != -1) {
281 config_file
= optarg
;
287 return usage(argv
[0]);
291 blob_buf_init(&conf
, 0);
292 if (!blobmsg_add_json_from_file(&conf
, config_file
) ||
294 fprintf(stderr
, "Failed to load config file\n");
298 ret
= libusb_init(&usb
);
300 fprintf(stderr
, "Failed to initialize libusb: %s\n", libusb_error_name(ret
));
304 n_usbdevs
= libusb_get_device_list(usb
, &usbdevs
);
306 libusb_free_device_list(usbdevs
, 1);