source: mainline/uspace/app/usbinfo/main.c@ df0bbe1

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since df0bbe1 was df0bbe1, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

usbinfo accepts host:address device specification

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/*
2 * Copyright (c) 2010-2011 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup usbinfo
30 * @{
31 */
32/**
33 * @file
34 * USB querying.
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <errno.h>
40#include <str_error.h>
41#include <bool.h>
42#include <getopt.h>
43#include <devman.h>
44#include <devmap.h>
45#include <usb/usbdevice.h>
46#include <usb/pipes.h>
47#include <usb/host.h>
48#include "usbinfo.h"
49
50static bool try_parse_class_and_address(const char *path,
51 devman_handle_t *out_hc_handle, usb_address_t *out_device_address)
52{
53 size_t class_index;
54 size_t address;
55 int rc;
56 char *ptr;
57
58 rc = str_size_t(path, &ptr, 10, false, &class_index);
59 if (rc != EOK) {
60 return false;
61 }
62 if ((*ptr == ':') || (*ptr == '.')) {
63 ptr++;
64 } else {
65 return false;
66 }
67 rc = str_size_t(ptr, NULL, 10, true, &address);
68 if (rc != EOK) {
69 return false;
70 }
71 rc = usb_ddf_get_hc_handle_by_class(class_index, out_hc_handle);
72 if (rc != EOK) {
73 return false;
74 }
75 if (out_device_address != NULL) {
76 *out_device_address = (usb_address_t) address;
77 }
78 return true;
79}
80
81static bool resolve_hc_handle_and_dev_addr(const char *devpath,
82 devman_handle_t *out_hc_handle, usb_address_t *out_device_address)
83{
84 int rc;
85
86 /* Hack for QEMU to save-up on typing ;-). */
87 if (str_cmp(devpath, "qemu") == 0) {
88 devpath = "/hw/pci0/00:01.2/uhci-rh/usb00_a1";
89 }
90
91 /* Hack for virtual keyboard. */
92 if (str_cmp(devpath, "virt") == 0) {
93 devpath = "/virt/usbhc/usb00_a1/usb00_a2";
94 }
95
96 if (try_parse_class_and_address(devpath,
97 out_hc_handle, out_device_address)) {
98 return true;
99 }
100
101 char *path = str_dup(devpath);
102 if (path == NULL) {
103 return ENOMEM;
104 }
105
106 devman_handle_t hc = 0;
107 bool hc_found = false;
108 usb_address_t addr = 0;
109 bool addr_found = false;
110
111 /* Remove suffixes and hope that we will encounter device node. */
112 while (str_length(path) > 0) {
113 /* Get device handle first. */
114 devman_handle_t dev_handle;
115 rc = devman_device_get_handle(path, &dev_handle, 0);
116 if (rc != EOK) {
117 free(path);
118 return false;
119 }
120
121 /* Try to find its host controller. */
122 if (!hc_found) {
123 rc = usb_hc_find(dev_handle, &hc);
124 if (rc == EOK) {
125 hc_found = true;
126 }
127 }
128 /* Try to get its address. */
129 if (!addr_found) {
130 addr = usb_device_get_assigned_address(dev_handle);
131 if (addr >= 0) {
132 addr_found = true;
133 }
134 }
135
136 /* Speed-up. */
137 if (hc_found && addr_found) {
138 break;
139 }
140
141 /* Remove the last suffix. */
142 char *slash_pos = str_rchr(path, '/');
143 if (slash_pos != NULL) {
144 *slash_pos = 0;
145 }
146 }
147
148 free(path);
149
150 if (hc_found && addr_found) {
151 if (out_hc_handle != NULL) {
152 *out_hc_handle = hc;
153 }
154 if (out_device_address != NULL) {
155 *out_device_address = addr;
156 }
157 return true;
158 } else {
159 return false;
160 }
161}
162
163static void print_usage(char *app_name)
164{
165#define _INDENT " "
166#define _OPTION(opt, description) \
167 printf(_INDENT opt "\n" _INDENT _INDENT description "\n")
168
169 printf(NAME ": query USB devices for descriptors\n\n");
170 printf("Usage: %s [options] device [device [device [ ... ]]]\n",
171 app_name);
172 printf(_INDENT "The device is a devman path to the device.\n");
173
174 _OPTION("-h --help", "Print this help and exit.");
175 _OPTION("-i --identification", "Brief device identification.");
176 _OPTION("-m --match-ids", "Print match ids generated for the device.");
177 _OPTION("-t --descriptor-tree", "Print descriptor tree.");
178 _OPTION("-T --descriptor-tree-full", "Print detailed descriptor tree");
179 _OPTION("-s --strings", "Try to print all string descriptors.");
180 _OPTION("-S --status", "Get status of the device.");
181
182 printf("\n");
183 printf("If no option is specified, `-i' is considered default.\n");
184 printf("\n");
185
186#undef _OPTION
187#undef _INDENT
188}
189
190static struct option long_options[] = {
191 {"help", no_argument, NULL, 'h'},
192 {"identification", no_argument, NULL, 'i'},
193 {"match-ids", no_argument, NULL, 'm'},
194 {"descriptor-tree", no_argument, NULL, 't'},
195 {"descriptor-tree-full", no_argument, NULL, 'T'},
196 {"strings", no_argument, NULL, 's'},
197 {"status", no_argument, NULL, 'S'},
198 {0, 0, NULL, 0}
199};
200static const char *short_options = "himtTsS";
201
202static usbinfo_action_t actions[] = {
203 {
204 .opt = 'i',
205 .action = dump_short_device_identification,
206 .active = false
207 },
208 {
209 .opt = 'm',
210 .action = dump_device_match_ids,
211 .active = false
212 },
213 {
214 .opt = 't',
215 .action = dump_descriptor_tree_brief,
216 .active = false
217 },
218 {
219 .opt = 'T',
220 .action = dump_descriptor_tree_full,
221 .active = false
222 },
223 {
224 .opt = 's',
225 .action = dump_strings,
226 .active = false
227 },
228 {
229 .opt = 'S',
230 .action = dump_status,
231 .active = false
232 },
233 {
234 .opt = 0
235 }
236};
237
238int main(int argc, char *argv[])
239{
240 if (argc <= 1) {
241 print_usage(argv[0]);
242 return -1;
243 }
244
245 /*
246 * Process command-line options. They determine what shall be
247 * done with the device.
248 */
249 int opt;
250 do {
251 opt = getopt_long(argc, argv,
252 short_options, long_options, NULL);
253 switch (opt) {
254 case -1:
255 break;
256 case '?':
257 print_usage(argv[0]);
258 return 1;
259 case 'h':
260 print_usage(argv[0]);
261 return 0;
262 default: {
263 int idx = 0;
264 while (actions[idx].opt != 0) {
265 if (actions[idx].opt == opt) {
266 actions[idx].active = true;
267 break;
268 }
269 idx++;
270 }
271 break;
272 }
273 }
274 } while (opt > 0);
275
276 /* Set the default action. */
277 int idx = 0;
278 bool something_active = false;
279 while (actions[idx].opt != 0) {
280 if (actions[idx].active) {
281 something_active = true;
282 break;
283 }
284 idx++;
285 }
286 if (!something_active) {
287 actions[0].active = true;
288 }
289
290 /*
291 * Go through all devices given on the command line and run the
292 * specified actions.
293 */
294 int i;
295 for (i = optind; i < argc; i++) {
296 char *devpath = argv[i];
297
298 /* The initialization is here only to make compiler happy. */
299 devman_handle_t hc_handle = 0;
300 usb_address_t dev_addr = 0;
301 bool found = resolve_hc_handle_and_dev_addr(devpath,
302 &hc_handle, &dev_addr);
303 if (!found) {
304 fprintf(stderr, NAME ": device `%s' not found "
305 "or not of USB kind, skipping.\n",
306 devpath);
307 continue;
308 }
309
310 usbinfo_device_t *dev = prepare_device(hc_handle, dev_addr);
311 if (dev == NULL) {
312 continue;
313 }
314
315 /* Run actions the user specified. */
316 printf("%s\n", devpath);
317
318 int action = 0;
319 while (actions[action].opt != 0) {
320 if (actions[action].active) {
321 actions[action].action(dev);
322 }
323 action++;
324 }
325
326 /* Destroy the control pipe (close the session etc.). */
327 destroy_device(dev);
328 }
329
330 return 0;
331}
332
333
334/** @}
335 */
Note: See TracBrowser for help on using the repository browser.