Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
  4 *               2005-2007 Takahiro Hirofuchi
  5 * Copyright (C) 2015-2016 Samsung Electronics
  6 *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
  7 *               Krzysztof Opasiak <k.opasiak@samsung.com>
  8 */
  9
 10#include <sys/types.h>
 11#include <libudev.h>
 12
 13#include <errno.h>
 14#include <stdbool.h>
 15#include <stdint.h>
 16#include <stdio.h>
 17#include <stdlib.h>
 18#include <string.h>
 19
 20#include <getopt.h>
 21#include <netdb.h>
 22#include <unistd.h>
 23
 24#include <dirent.h>
 25
 26#include <linux/usb/ch9.h>
 27
 28#include "usbip_common.h"
 29#include "usbip_network.h"
 30#include "usbip.h"
 31
 32static const char usbip_list_usage_string[] =
 33	"usbip list [-p|--parsable] <args>\n"
 34	"    -p, --parsable         Parsable list format\n"
 35	"    -r, --remote=<host>    List the exportable USB devices on <host>\n"
 36	"    -l, --local            List the local USB devices\n";
 37
 38void usbip_list_usage(void)
 39{
 40	printf("usage: %s", usbip_list_usage_string);
 41}
 42
 43static int get_exported_devices(char *host, int sockfd)
 44{
 45	char product_name[100];
 46	char class_name[100];
 47	struct op_devlist_reply reply;
 48	uint16_t code = OP_REP_DEVLIST;
 49	struct usbip_usb_device udev;
 50	struct usbip_usb_interface uintf;
 51	unsigned int i;
 52	int rc, j;
 53	int status;
 54
 55	rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
 56	if (rc < 0) {
 57		dbg("usbip_net_send_op_common failed");
 58		return -1;
 59	}
 60
 61	rc = usbip_net_recv_op_common(sockfd, &code, &status);
 62	if (rc < 0) {
 63		err("Exported Device List Request failed - %s\n",
 64		    usbip_op_common_status_string(status));
 65		return -1;
 66	}
 67
 68	memset(&reply, 0, sizeof(reply));
 69	rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
 70	if (rc < 0) {
 71		dbg("usbip_net_recv_op_devlist failed");
 72		return -1;
 73	}
 74	PACK_OP_DEVLIST_REPLY(0, &reply);
 75	dbg("exportable devices: %d\n", reply.ndev);
 76
 77	if (reply.ndev == 0) {
 78		info("no exportable devices found on %s", host);
 79		return 0;
 80	}
 81
 82	printf("Exportable USB devices\n");
 83	printf("======================\n");
 84	printf(" - %s\n", host);
 85
 86	for (i = 0; i < reply.ndev; i++) {
 87		memset(&udev, 0, sizeof(udev));
 88		rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
 89		if (rc < 0) {
 90			dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
 91			return -1;
 92		}
 93		usbip_net_pack_usb_device(0, &udev);
 94
 95		usbip_names_get_product(product_name, sizeof(product_name),
 96					udev.idVendor, udev.idProduct);
 97		usbip_names_get_class(class_name, sizeof(class_name),
 98				      udev.bDeviceClass, udev.bDeviceSubClass,
 99				      udev.bDeviceProtocol);
100		printf("%11s: %s\n", udev.busid, product_name);
101		printf("%11s: %s\n", "", udev.path);
102		printf("%11s: %s\n", "", class_name);
103
104		for (j = 0; j < udev.bNumInterfaces; j++) {
105			rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
106			if (rc < 0) {
107				err("usbip_net_recv failed: usbip_usb_intf[%d]",
108						j);
109
110				return -1;
111			}
112			usbip_net_pack_usb_interface(0, &uintf);
113
114			usbip_names_get_class(class_name, sizeof(class_name),
115					uintf.bInterfaceClass,
116					uintf.bInterfaceSubClass,
117					uintf.bInterfaceProtocol);
118			printf("%11s: %2d - %s\n", "", j, class_name);
119		}
120
121		printf("\n");
122	}
123
124	return 0;
125}
126
127static int list_exported_devices(char *host)
128{
129	int rc;
130	int sockfd;
131
132	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
133	if (sockfd < 0) {
134		err("could not connect to %s:%s: %s", host,
135		    usbip_port_string, gai_strerror(sockfd));
136		return -1;
137	}
138	dbg("connected to %s:%s", host, usbip_port_string);
139
140	rc = get_exported_devices(host, sockfd);
141	if (rc < 0) {
142		err("failed to get device list from %s", host);
143		return -1;
144	}
145
146	close(sockfd);
147
148	return 0;
149}
150
151static void print_device(const char *busid, const char *vendor,
152			 const char *product, bool parsable)
153{
154	if (parsable)
155		printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
156	else
157		printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
158}
159
160static void print_product_name(char *product_name, bool parsable)
161{
162	if (!parsable)
163		printf("   %s\n", product_name);
164}
165
166static int list_devices(bool parsable)
167{
168	struct udev *udev;
169	struct udev_enumerate *enumerate;
170	struct udev_list_entry *devices, *dev_list_entry;
171	struct udev_device *dev;
172	const char *path;
173	const char *idVendor;
174	const char *idProduct;
175	const char *bConfValue;
176	const char *bNumIntfs;
177	const char *busid;
178	char product_name[128];
179	int ret = -1;
180	const char *devpath;
181
182	/* Create libudev context. */
183	udev = udev_new();
184
185	/* Create libudev device enumeration. */
186	enumerate = udev_enumerate_new(udev);
187
188	/* Take only USB devices that are not hubs and do not have
189	 * the bInterfaceNumber attribute, i.e. are not interfaces.
190	 */
191	udev_enumerate_add_match_subsystem(enumerate, "usb");
192	udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
193	udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
194	udev_enumerate_scan_devices(enumerate);
195
196	devices = udev_enumerate_get_list_entry(enumerate);
197
198	/* Show information about each device. */
199	udev_list_entry_foreach(dev_list_entry, devices) {
200		path = udev_list_entry_get_name(dev_list_entry);
201		dev = udev_device_new_from_syspath(udev, path);
202
203		/* Ignore devices attached to vhci_hcd */
204		devpath = udev_device_get_devpath(dev);
205		if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
206			dbg("Skip the device %s already attached to %s\n",
207			    devpath, USBIP_VHCI_DRV_NAME);
208			continue;
209		}
210
211		/* Get device information. */
212		idVendor = udev_device_get_sysattr_value(dev, "idVendor");
213		idProduct = udev_device_get_sysattr_value(dev, "idProduct");
214		bConfValue = udev_device_get_sysattr_value(dev,
215				"bConfigurationValue");
216		bNumIntfs = udev_device_get_sysattr_value(dev,
217				"bNumInterfaces");
218		busid = udev_device_get_sysname(dev);
219		if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
220			err("problem getting device attributes: %s",
221			    strerror(errno));
222			goto err_out;
223		}
224
225		/* Get product name. */
226		usbip_names_get_product(product_name, sizeof(product_name),
227					strtol(idVendor, NULL, 16),
228					strtol(idProduct, NULL, 16));
229
230		/* Print information. */
231		print_device(busid, idVendor, idProduct, parsable);
232		print_product_name(product_name, parsable);
233
234		printf("\n");
235
236		udev_device_unref(dev);
237	}
238
239	ret = 0;
240
241err_out:
242	udev_enumerate_unref(enumerate);
243	udev_unref(udev);
244
245	return ret;
246}
247
248static int list_gadget_devices(bool parsable)
249{
250	int ret = -1;
251	struct udev *udev;
252	struct udev_enumerate *enumerate;
253	struct udev_list_entry *devices, *dev_list_entry;
254	struct udev_device *dev;
255	const char *path;
256	const char *driver;
257
258	const struct usb_device_descriptor *d_desc;
259	const char *descriptors;
260	char product_name[128];
261
262	uint16_t idVendor;
263	char idVendor_buf[8];
264	uint16_t idProduct;
265	char idProduct_buf[8];
266	const char *busid;
267
268	udev = udev_new();
269	enumerate = udev_enumerate_new(udev);
270
271	udev_enumerate_add_match_subsystem(enumerate, "platform");
272
273	udev_enumerate_scan_devices(enumerate);
274	devices = udev_enumerate_get_list_entry(enumerate);
275
276	udev_list_entry_foreach(dev_list_entry, devices) {
277		path = udev_list_entry_get_name(dev_list_entry);
278		dev = udev_device_new_from_syspath(udev, path);
279
280		driver = udev_device_get_driver(dev);
281		/* We only have mechanism to enumerate gadgets bound to vudc */
282		if (driver == NULL || strcmp(driver, USBIP_DEVICE_DRV_NAME))
283			continue;
284
285		/* Get device information. */
286		descriptors = udev_device_get_sysattr_value(dev,
287				VUDC_DEVICE_DESCR_FILE);
288
289		if (!descriptors) {
290			err("problem getting device attributes: %s",
291			    strerror(errno));
292			goto err_out;
293		}
294
295		d_desc = (const struct usb_device_descriptor *) descriptors;
296
297		idVendor = le16toh(d_desc->idVendor);
298		sprintf(idVendor_buf, "0x%4x", idVendor);
299		idProduct = le16toh(d_desc->idProduct);
300		sprintf(idProduct_buf, "0x%4x", idVendor);
301		busid = udev_device_get_sysname(dev);
302
303		/* Get product name. */
304		usbip_names_get_product(product_name, sizeof(product_name),
305					le16toh(idVendor),
306					le16toh(idProduct));
307
308		/* Print information. */
309		print_device(busid, idVendor_buf, idProduct_buf, parsable);
310		print_product_name(product_name, parsable);
311
312		printf("\n");
313
314		udev_device_unref(dev);
315	}
316	ret = 0;
317
318err_out:
319	udev_enumerate_unref(enumerate);
320	udev_unref(udev);
321
322	return ret;
323}
324
325int usbip_list(int argc, char *argv[])
326{
327	static const struct option opts[] = {
328		{ "parsable", no_argument,       NULL, 'p' },
329		{ "remote",   required_argument, NULL, 'r' },
330		{ "local",    no_argument,       NULL, 'l' },
331		{ "device",    no_argument,       NULL, 'd' },
332		{ NULL,       0,                 NULL,  0  }
333	};
334
335	bool parsable = false;
336	int opt;
337	int ret = -1;
338
339	if (usbip_names_init(USBIDS_FILE))
340		err("failed to open %s", USBIDS_FILE);
341
342	for (;;) {
343		opt = getopt_long(argc, argv, "pr:ld", opts, NULL);
344
345		if (opt == -1)
346			break;
347
348		switch (opt) {
349		case 'p':
350			parsable = true;
351			break;
352		case 'r':
353			ret = list_exported_devices(optarg);
354			goto out;
355		case 'l':
356			ret = list_devices(parsable);
357			goto out;
358		case 'd':
359			ret = list_gadget_devices(parsable);
360			goto out;
361		default:
362			goto err_out;
363		}
364	}
365
366err_out:
367	usbip_list_usage();
368out:
369	usbip_names_free();
370
371	return ret;
372}