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 struct blob_attr
**messages
= NULL
;
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
;
195 const struct libusb_interface_descriptor
*alt
;
198 data
->interface
= -1;
199 if (libusb_get_config_descriptor(dev
, 0, &config
))
202 data
->config
= config
;
203 if (!config
->bNumInterfaces
)
206 iface
= &config
->interface
[0];
207 if (!iface
->num_altsetting
)
210 alt
= &iface
->altsetting
[0];
211 data
->interface
= alt
->bInterfaceNumber
;
213 for (i
= 0; i
< alt
->bNumEndpoints
; i
++) {
214 const struct libusb_endpoint_descriptor
*ep
= &alt
->endpoint
[i
];
217 if (data
->msg_endpoint
&& data
->response_endpoint
)
220 if ((ep
->bmAttributes
& LIBUSB_TRANSFER_TYPE_MASK
) !=
221 LIBUSB_TRANSFER_TYPE_BULK
)
224 out
= (ep
->bEndpointAddress
& LIBUSB_ENDPOINT_DIR_MASK
) ==
227 if (!data
->msg_endpoint
&& out
)
228 data
->msg_endpoint
= ep
->bEndpointAddress
;
229 if (!data
->response_endpoint
&& !out
)
230 data
->response_endpoint
= ep
->bEndpointAddress
;
234 static void iterate_devs(cmd_cb_t cb
)
236 struct usbdev_data data
;
243 for (i
= 0; i
< n_usbdevs
; i
++) {
244 memset(&data
, 0, sizeof(data
));
246 if (libusb_get_device_descriptor(usbdevs
[i
], &data
.desc
))
249 sprintf(data
.idstr
, "%04x:%04x", data
.desc
.idVendor
, data
.desc
.idProduct
);
251 dev
= avl_find_element(&devices
, data
.idstr
, dev
, avl
);
255 if (libusb_open(usbdevs
[i
], &data
.devh
))
258 libusb_get_string_descriptor_ascii(
259 data
.devh
, data
.desc
.iManufacturer
,
260 (void *) data
.mfg
, sizeof(data
.mfg
));
261 libusb_get_string_descriptor_ascii(
262 data
.devh
, data
.desc
.iProduct
,
263 (void *) data
.prod
, sizeof(data
.prod
));
264 libusb_get_string_descriptor_ascii(
265 data
.devh
, data
.desc
.iSerialNumber
,
266 (void *) data
.serial
, sizeof(data
.serial
));
268 parse_interface_config(usbdevs
[i
], &data
);
270 data
.info
= find_dev_data(&data
, dev
);
275 libusb_free_config_descriptor(data
.config
);
277 libusb_close(data
.devh
);
281 static void handle_list(struct usbdev_data
*data
)
283 fprintf(stderr
, "Found device: %s (Manufacturer: \"%s\", Product: \"%s\", Serial: \"%s\")\n",
284 data
->idstr
, data
->mfg
, data
->prod
, data
->serial
);
287 int main(int argc
, char **argv
)
293 avl_init(&devices
, avl_strcmp
, false, NULL
);
295 while ((ch
= getopt(argc
, argv
, "lsc:v")) != -1) {
304 config_file
= optarg
;
310 return usage(argv
[0]);
314 blob_buf_init(&conf
, 0);
315 if (!blobmsg_add_json_from_file(&conf
, config_file
) ||
317 fprintf(stderr
, "Failed to load config file\n");
321 ret
= libusb_init(&usb
);
323 fprintf(stderr
, "Failed to initialize libusb: %s\n", libusb_error_name(ret
));
327 n_usbdevs
= libusb_get_device_list(usb
, &usbdevs
);
329 libusb_free_device_list(usbdevs
, 1);