• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/usbmode/main.c

  1 #include <stdio.h>
  2 #include <getopt.h>
  3 #include <stdbool.h>
  4 #include <ctype.h>
  5 
  6 #include <libubox/blobmsg_json.h>
  7 #include <libubox/avl.h>
  8 #include <libubox/avl-cmp.h>
  9 #include "switch.h"
 10 
 11 #define DEFAULT_CONFIG "/etc/usb-mode.json"
 12 
 13 struct device {
 14         struct avl_node avl;
 15         struct blob_attr *data;
 16 };
 17 
 18 static int verbose = 0;
 19 static const char *config_file = DEFAULT_CONFIG;
 20 static struct blob_buf conf;
 21 
 22 char **messages = NULL;
 23 int *message_len;
 24 int n_messages = 0;
 25 
 26 static struct avl_tree devices;
 27 
 28 struct libusb_context *usb;
 29 static struct libusb_device **usbdevs;
 30 static int n_usbdevs;
 31 
 32 static int hex2num(char c)
 33 {
 34         if (c >= '' && c <= '9')
 35                 return c - '';
 36 
 37         c = toupper(c);
 38         if (c >= 'A' && c <= 'F')
 39                 return c - 'A' + 10;
 40 
 41         return -1;
 42 }
 43 
 44 static int hex2byte(const char *hex)
 45 {
 46         int a, b;
 47 
 48         a = hex2num(*hex++);
 49         if (a < 0)
 50                 return -1;
 51 
 52         b = hex2num(*hex++);
 53         if (b < 0)
 54                 return -1;
 55 
 56         return (a << 4) | b;
 57 }
 58 
 59 static int hexstr2bin(const char *hex, char *buffer, int len)
 60 {
 61         const char *ipos = hex;
 62         char *opos = buffer;
 63         int i, a;
 64 
 65         for (i = 0; i < len; i++) {
 66                 a = hex2byte(ipos);
 67                 if (a < 0)
 68                         return -1;
 69 
 70                 *opos++ = a;
 71                 ipos += 2;
 72         }
 73 
 74         return 0;
 75 }
 76 
 77 static int convert_message(struct blob_attr *attr)
 78 {
 79         char *data;
 80         int len;
 81 
 82         data = blobmsg_data(attr);
 83         len = strlen(data);
 84         if (len % 2)
 85                 return -1;
 86 
 87         if (hexstr2bin(data, data, len / 2))
 88                 return -1;
 89 
 90         return len / 2;
 91 }
 92 
 93 static int parse_config(void)
 94 {
 95         enum {
 96                 CONF_MESSAGES,
 97                 CONF_DEVICES,
 98                 __CONF_MAX
 99         };
100         static const struct blobmsg_policy policy[__CONF_MAX] = {
101                 [CONF_MESSAGES] = { .name = "messages", .type = BLOBMSG_TYPE_ARRAY },
102                 [CONF_DEVICES] = { .name = "devices", .type = BLOBMSG_TYPE_TABLE },
103         };
104         struct blob_attr *tb[__CONF_MAX];
105         struct blob_attr *cur;
106         struct device *dev;
107         int rem;
108 
109         blobmsg_parse(policy, __CONF_MAX, tb, blob_data(conf.head), blob_len(conf.head));
110         if (!tb[CONF_MESSAGES] || !tb[CONF_DEVICES]) {
111                 fprintf(stderr, "Configuration incomplete\n");
112                 return -1;
113         }
114 
115         blobmsg_for_each_attr(cur, tb[CONF_MESSAGES], rem)
116                 n_messages++;
117 
118         messages = calloc(n_messages, sizeof(*messages));
119         message_len = calloc(n_messages, sizeof(*message_len));
120         n_messages = 0;
121         blobmsg_for_each_attr(cur, tb[CONF_MESSAGES], rem) {
122                 int len = convert_message(cur);
123 
124                 if (len < 0) {
125                         fprintf(stderr, "Invalid data in message %d\n", n_messages);
126                         return -1;
127                 }
128 
129                 message_len[n_messages] = len;
130                 messages[n_messages++] = blobmsg_data(cur);
131         }
132 
133         blobmsg_for_each_attr(cur, tb[CONF_DEVICES], rem) {
134             dev = calloc(1, sizeof(*dev));
135             dev->avl.key = blobmsg_name(cur);
136             dev->data = cur;
137             avl_insert(&devices, &dev->avl);
138         }
139 
140         return 0;
141 }
142 
143 static int usage(const char *prog)
144 {
145         fprintf(stderr, "Usage: %s <command> <options>\n"
146                 "Commands:\n"
147                 "       -l              List matching devices\n"
148                 "       -s              Modeswitch matching devices\n"
149                 "\n"
150                 "Options:\n"
151                 "       -v              Verbose output\n"
152                 "       -c <file>       Set configuration file to <file> (default: %s)\n"
153                 "\n", prog, DEFAULT_CONFIG);
154         return 1;
155 }
156 
157 typedef void (*cmd_cb_t)(struct usbdev_data *data);
158 
159 static struct blob_attr *
160 find_dev_data(struct usbdev_data *data, struct device *dev)
161 {
162         struct blob_attr *cur;
163         int rem;
164 
165         blobmsg_for_each_attr(cur, dev->data, rem) {
166                 const char *name = blobmsg_name(cur);
167                 const char *next;
168                 char *val;
169 
170                 if (!strcmp(blobmsg_name(cur), "*"))
171                         return cur;
172 
173                 next = strchr(name, '=');
174                 if (!next)
175                         continue;
176 
177                 next++;
178                 if (!strncmp(name, "uMa", 3)) {
179                         val = data->mfg;
180                 } else if (!strncmp(name, "uPr", 3)) {
181                         val = data->prod;
182                 } else if (!strncmp(name, "uSe", 3)) {
183                         val = data->serial;
184                 } else {
185                         /* ignore unsupported scsi attributes */
186                         return cur;
187                 }
188 
189                 if (!strcmp(val, next))
190                         return cur;
191         }
192 
193         return NULL;
194 }
195 
196 static void
197 parse_interface_config(libusb_device *dev, struct usbdev_data *data)
198 {
199         struct libusb_config_descriptor *config;
200         const struct libusb_interface *iface;
201         const struct libusb_interface_descriptor *alt;
202         int i;
203 
204         data->interface = -1;
205         if (libusb_get_config_descriptor(dev, 0, &config))
206                 return;
207 
208         data->config = config;
209         if (!config->bNumInterfaces)
210                 return;
211 
212         iface = &config->interface[0];
213         if (!iface->num_altsetting)
214                 return;
215 
216         alt = &iface->altsetting[0];
217         data->interface = alt->bInterfaceNumber;
218         data->dev_class = alt->bInterfaceClass;
219 
220         for (i = 0; i < alt->bNumEndpoints; i++) {
221                 const struct libusb_endpoint_descriptor *ep = &alt->endpoint[i];
222                 bool out = false;
223 
224                 if (data->msg_endpoint && data->response_endpoint)
225                         break;
226 
227                 if ((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) !=
228                     LIBUSB_TRANSFER_TYPE_BULK)
229                         continue;
230 
231                 out = (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
232                       LIBUSB_ENDPOINT_OUT;
233 
234                 if (!data->msg_endpoint && out)
235                         data->msg_endpoint = ep->bEndpointAddress;
236                 if (!data->response_endpoint && !out)
237                         data->response_endpoint = ep->bEndpointAddress;
238         }
239 }
240 
241 static void iterate_devs(cmd_cb_t cb)
242 {
243         struct usbdev_data data;
244         struct device *dev;
245         int i;
246 
247         if (!cb)
248                 return;
249 
250         for (i = 0; i < n_usbdevs; i++) {
251                 memset(&data, 0, sizeof(data));
252 
253                 if (libusb_get_device_descriptor(usbdevs[i], &data.desc))
254                         continue;
255 
256                 sprintf(data.idstr, "%04x:%04x", data.desc.idVendor, data.desc.idProduct);
257 
258                 dev = avl_find_element(&devices, data.idstr, dev, avl);
259                 if (!dev)
260                         continue;
261 
262                 if (libusb_open(usbdevs[i], &data.devh))
263                         continue;
264 
265                 data.dev = usbdevs[i];
266 
267                 libusb_get_string_descriptor_ascii(
268                         data.devh, data.desc.iManufacturer,
269                         (void *) data.mfg, sizeof(data.mfg));
270                 libusb_get_string_descriptor_ascii(
271                         data.devh, data.desc.iProduct,
272                         (void *) data.prod, sizeof(data.prod));
273                 libusb_get_string_descriptor_ascii(
274                         data.devh, data.desc.iSerialNumber,
275                         (void *) data.serial, sizeof(data.serial));
276 
277                 parse_interface_config(usbdevs[i], &data);
278 
279                 data.info = find_dev_data(&data, dev);
280                 if (data.info)
281                         cb(&data);
282 
283                 if (data.config)
284                         libusb_free_config_descriptor(data.config);
285 
286                 if (data.devh)
287                         libusb_close(data.devh);
288         }
289 }
290 
291 static void handle_list(struct usbdev_data *data)
292 {
293         fprintf(stderr, "Found device: %s (Manufacturer: \"%s\", Product: \"%s\", Serial: \"%s\")\n",
294                 data->idstr, data->mfg, data->prod, data->serial);
295 }
296 
297 int main(int argc, char **argv)
298 {
299         cmd_cb_t cb = NULL;
300         int ret;
301         int ch;
302 
303         avl_init(&devices, avl_strcmp, false, NULL);
304 
305         while ((ch = getopt(argc, argv, "lsc:v")) != -1) {
306                 switch (ch) {
307                 case 'l':
308                         cb = handle_list;
309                         break;
310                 case 's':
311                         cb = handle_switch;
312                         break;
313                 case 'c':
314                         config_file = optarg;
315                         break;
316                 case 'v':
317                         verbose++;
318                         break;
319                 default:
320                         return usage(argv[0]);
321                 }
322         }
323 
324         blob_buf_init(&conf, 0);
325         if (!blobmsg_add_json_from_file(&conf, config_file) ||
326             parse_config()) {
327                 fprintf(stderr, "Failed to load config file\n");
328                 return 1;
329         }
330 
331         ret = libusb_init(&usb);
332         if (ret) {
333                 fprintf(stderr, "Failed to initialize libusb: %s\n", libusb_error_name(ret));
334                 return 1;
335         }
336 
337         n_usbdevs = libusb_get_device_list(usb, &usbdevs);
338         iterate_devs(cb);
339         libusb_free_device_list(usbdevs, 1);
340         libusb_exit(usb);
341 
342         return 0;
343 }
344 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt