162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2005-2007 Takahiro Hirofuchi
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "usbip_common.h"
762306a36Sopenharmony_ci#include "vhci_driver.h"
862306a36Sopenharmony_ci#include <limits.h>
962306a36Sopenharmony_ci#include <netdb.h>
1062306a36Sopenharmony_ci#include <libudev.h>
1162306a36Sopenharmony_ci#include <dirent.h>
1262306a36Sopenharmony_ci#include "sysfs_utils.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#undef  PROGNAME
1562306a36Sopenharmony_ci#define PROGNAME "libusbip"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistruct usbip_vhci_driver *vhci_driver;
1862306a36Sopenharmony_cistruct udev *udev_context;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic struct usbip_imported_device *
2162306a36Sopenharmony_ciimported_device_init(struct usbip_imported_device *idev, char *busid)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	struct udev_device *sudev;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	sudev = udev_device_new_from_subsystem_sysname(udev_context,
2662306a36Sopenharmony_ci						       "usb", busid);
2762306a36Sopenharmony_ci	if (!sudev) {
2862306a36Sopenharmony_ci		dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
2962306a36Sopenharmony_ci		goto err;
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci	read_usb_device(sudev, &idev->udev);
3262306a36Sopenharmony_ci	udev_device_unref(sudev);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	return idev;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cierr:
3762306a36Sopenharmony_ci	return NULL;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic int parse_status(const char *value)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	int ret = 0;
4362306a36Sopenharmony_ci	char *c;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* skip a header line */
4662306a36Sopenharmony_ci	c = strchr(value, '\n');
4762306a36Sopenharmony_ci	if (!c)
4862306a36Sopenharmony_ci		return -1;
4962306a36Sopenharmony_ci	c++;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	while (*c != '\0') {
5262306a36Sopenharmony_ci		int port, status, speed, devid;
5362306a36Sopenharmony_ci		int sockfd;
5462306a36Sopenharmony_ci		char lbusid[SYSFS_BUS_ID_SIZE];
5562306a36Sopenharmony_ci		struct usbip_imported_device *idev;
5662306a36Sopenharmony_ci		char hub[3];
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci		ret = sscanf(c, "%2s  %d %d %d %x %u %31s\n",
5962306a36Sopenharmony_ci				hub, &port, &status, &speed,
6062306a36Sopenharmony_ci				&devid, &sockfd, lbusid);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci		if (ret < 5) {
6362306a36Sopenharmony_ci			dbg("sscanf failed: %d", ret);
6462306a36Sopenharmony_ci			BUG();
6562306a36Sopenharmony_ci		}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		dbg("hub %s port %d status %d speed %d devid %x",
6862306a36Sopenharmony_ci				hub, port, status, speed, devid);
6962306a36Sopenharmony_ci		dbg("sockfd %u lbusid %s", sockfd, lbusid);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci		/* if a device is connected, look at it */
7262306a36Sopenharmony_ci		idev = &vhci_driver->idev[port];
7362306a36Sopenharmony_ci		memset(idev, 0, sizeof(*idev));
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		if (strncmp("hs", hub, 2) == 0)
7662306a36Sopenharmony_ci			idev->hub = HUB_SPEED_HIGH;
7762306a36Sopenharmony_ci		else /* strncmp("ss", hub, 2) == 0 */
7862306a36Sopenharmony_ci			idev->hub = HUB_SPEED_SUPER;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci		idev->port	= port;
8162306a36Sopenharmony_ci		idev->status	= status;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		idev->devid	= devid;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		idev->busnum	= (devid >> 16);
8662306a36Sopenharmony_ci		idev->devnum	= (devid & 0x0000ffff);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci		if (idev->status != VDEV_ST_NULL
8962306a36Sopenharmony_ci		    && idev->status != VDEV_ST_NOTASSIGNED) {
9062306a36Sopenharmony_ci			idev = imported_device_init(idev, lbusid);
9162306a36Sopenharmony_ci			if (!idev) {
9262306a36Sopenharmony_ci				dbg("imported_device_init failed");
9362306a36Sopenharmony_ci				return -1;
9462306a36Sopenharmony_ci			}
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci		/* go to the next line */
9862306a36Sopenharmony_ci		c = strchr(c, '\n');
9962306a36Sopenharmony_ci		if (!c)
10062306a36Sopenharmony_ci			break;
10162306a36Sopenharmony_ci		c++;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	dbg("exit");
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define MAX_STATUS_NAME 18
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int refresh_imported_device_list(void)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	const char *attr_status;
11462306a36Sopenharmony_ci	char status[MAX_STATUS_NAME+1] = "status";
11562306a36Sopenharmony_ci	int i, ret;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	for (i = 0; i < vhci_driver->ncontrollers; i++) {
11862306a36Sopenharmony_ci		if (i > 0)
11962306a36Sopenharmony_ci			snprintf(status, sizeof(status), "status.%d", i);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
12262306a36Sopenharmony_ci							    status);
12362306a36Sopenharmony_ci		if (!attr_status) {
12462306a36Sopenharmony_ci			err("udev_device_get_sysattr_value failed");
12562306a36Sopenharmony_ci			return -1;
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		dbg("controller %d", i);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		ret = parse_status(attr_status);
13162306a36Sopenharmony_ci		if (ret != 0)
13262306a36Sopenharmony_ci			return ret;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return 0;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic int get_nports(struct udev_device *hc_device)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	const char *attr_nports;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	attr_nports = udev_device_get_sysattr_value(hc_device, "nports");
14362306a36Sopenharmony_ci	if (!attr_nports) {
14462306a36Sopenharmony_ci		err("udev_device_get_sysattr_value nports failed");
14562306a36Sopenharmony_ci		return -1;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return (int)strtoul(attr_nports, NULL, 10);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic int vhci_hcd_filter(const struct dirent *dirent)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	return !strncmp(dirent->d_name, "vhci_hcd.", 9);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int get_ncontrollers(void)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct dirent **namelist;
15962306a36Sopenharmony_ci	struct udev_device *platform;
16062306a36Sopenharmony_ci	int n;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	platform = udev_device_get_parent(vhci_driver->hc_device);
16362306a36Sopenharmony_ci	if (platform == NULL)
16462306a36Sopenharmony_ci		return -1;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	n = scandir(udev_device_get_syspath(platform), &namelist, vhci_hcd_filter, NULL);
16762306a36Sopenharmony_ci	if (n < 0)
16862306a36Sopenharmony_ci		err("scandir failed");
16962306a36Sopenharmony_ci	else {
17062306a36Sopenharmony_ci		for (int i = 0; i < n; i++)
17162306a36Sopenharmony_ci			free(namelist[i]);
17262306a36Sopenharmony_ci		free(namelist);
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return n;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/*
17962306a36Sopenharmony_ci * Read the given port's record.
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci * To avoid buffer overflow we will read the entire line and
18262306a36Sopenharmony_ci * validate each part's size. The initial buffer is padded by 4 to
18362306a36Sopenharmony_ci * accommodate the 2 spaces, 1 newline and an additional character
18462306a36Sopenharmony_ci * which is needed to properly validate the 3rd part without it being
18562306a36Sopenharmony_ci * truncated to an acceptable length.
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_cistatic int read_record(int rhport, char *host, unsigned long host_len,
18862306a36Sopenharmony_ci		char *port, unsigned long port_len, char *busid)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	int part;
19162306a36Sopenharmony_ci	FILE *file;
19262306a36Sopenharmony_ci	char path[PATH_MAX+1];
19362306a36Sopenharmony_ci	char *buffer, *start, *end;
19462306a36Sopenharmony_ci	char delim[] = {' ', ' ', '\n'};
19562306a36Sopenharmony_ci	int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
19662306a36Sopenharmony_ci	size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	buffer = malloc(buffer_len);
19962306a36Sopenharmony_ci	if (!buffer)
20062306a36Sopenharmony_ci		return -1;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	file = fopen(path, "r");
20562306a36Sopenharmony_ci	if (!file) {
20662306a36Sopenharmony_ci		err("fopen");
20762306a36Sopenharmony_ci		free(buffer);
20862306a36Sopenharmony_ci		return -1;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (fgets(buffer, buffer_len, file) == NULL) {
21262306a36Sopenharmony_ci		err("fgets");
21362306a36Sopenharmony_ci		free(buffer);
21462306a36Sopenharmony_ci		fclose(file);
21562306a36Sopenharmony_ci		return -1;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci	fclose(file);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* validate the length of each of the 3 parts */
22062306a36Sopenharmony_ci	start = buffer;
22162306a36Sopenharmony_ci	for (part = 0; part < 3; part++) {
22262306a36Sopenharmony_ci		end = strchr(start, delim[part]);
22362306a36Sopenharmony_ci		if (end == NULL || (end - start) > max_len[part]) {
22462306a36Sopenharmony_ci			free(buffer);
22562306a36Sopenharmony_ci			return -1;
22662306a36Sopenharmony_ci		}
22762306a36Sopenharmony_ci		start = end + 1;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
23162306a36Sopenharmony_ci		err("sscanf");
23262306a36Sopenharmony_ci		free(buffer);
23362306a36Sopenharmony_ci		return -1;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	free(buffer);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ciint usbip_vhci_driver_open(void)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	int nports;
24662306a36Sopenharmony_ci	struct udev_device *hc_device;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	udev_context = udev_new();
24962306a36Sopenharmony_ci	if (!udev_context) {
25062306a36Sopenharmony_ci		err("udev_new failed");
25162306a36Sopenharmony_ci		return -1;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* will be freed in usbip_driver_close() */
25562306a36Sopenharmony_ci	hc_device =
25662306a36Sopenharmony_ci		udev_device_new_from_subsystem_sysname(udev_context,
25762306a36Sopenharmony_ci						       USBIP_VHCI_BUS_TYPE,
25862306a36Sopenharmony_ci						       USBIP_VHCI_DEVICE_NAME);
25962306a36Sopenharmony_ci	if (!hc_device) {
26062306a36Sopenharmony_ci		err("udev_device_new_from_subsystem_sysname failed");
26162306a36Sopenharmony_ci		goto err;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	nports = get_nports(hc_device);
26562306a36Sopenharmony_ci	if (nports <= 0) {
26662306a36Sopenharmony_ci		err("no available ports");
26762306a36Sopenharmony_ci		goto err;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	dbg("available ports: %d", nports);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver) +
27262306a36Sopenharmony_ci			nports * sizeof(struct usbip_imported_device));
27362306a36Sopenharmony_ci	if (!vhci_driver) {
27462306a36Sopenharmony_ci		err("vhci_driver allocation failed");
27562306a36Sopenharmony_ci		goto err;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	vhci_driver->nports = nports;
27962306a36Sopenharmony_ci	vhci_driver->hc_device = hc_device;
28062306a36Sopenharmony_ci	vhci_driver->ncontrollers = get_ncontrollers();
28162306a36Sopenharmony_ci	dbg("available controllers: %d", vhci_driver->ncontrollers);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (vhci_driver->ncontrollers <=0) {
28462306a36Sopenharmony_ci		err("no available usb controllers");
28562306a36Sopenharmony_ci		goto err;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (refresh_imported_device_list())
28962306a36Sopenharmony_ci		goto err;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cierr:
29462306a36Sopenharmony_ci	udev_device_unref(hc_device);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (vhci_driver)
29762306a36Sopenharmony_ci		free(vhci_driver);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	vhci_driver = NULL;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	udev_unref(udev_context);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	return -1;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_civoid usbip_vhci_driver_close(void)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	if (!vhci_driver)
31062306a36Sopenharmony_ci		return;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	udev_device_unref(vhci_driver->hc_device);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	free(vhci_driver);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	vhci_driver = NULL;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	udev_unref(udev_context);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ciint usbip_vhci_refresh_device_list(void)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (refresh_imported_device_list())
32662306a36Sopenharmony_ci		goto err;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return 0;
32962306a36Sopenharmony_cierr:
33062306a36Sopenharmony_ci	dbg("failed to refresh device list");
33162306a36Sopenharmony_ci	return -1;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciint usbip_vhci_get_free_port(uint32_t speed)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	for (int i = 0; i < vhci_driver->nports; i++) {
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		switch (speed) {
34062306a36Sopenharmony_ci		case	USB_SPEED_SUPER:
34162306a36Sopenharmony_ci			if (vhci_driver->idev[i].hub != HUB_SPEED_SUPER)
34262306a36Sopenharmony_ci				continue;
34362306a36Sopenharmony_ci		break;
34462306a36Sopenharmony_ci		default:
34562306a36Sopenharmony_ci			if (vhci_driver->idev[i].hub != HUB_SPEED_HIGH)
34662306a36Sopenharmony_ci				continue;
34762306a36Sopenharmony_ci		break;
34862306a36Sopenharmony_ci		}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		if (vhci_driver->idev[i].status == VDEV_ST_NULL)
35162306a36Sopenharmony_ci			return vhci_driver->idev[i].port;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	return -1;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ciint usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
35862306a36Sopenharmony_ci		uint32_t speed) {
35962306a36Sopenharmony_ci	char buff[200]; /* what size should be ? */
36062306a36Sopenharmony_ci	char attach_attr_path[SYSFS_PATH_MAX];
36162306a36Sopenharmony_ci	char attr_attach[] = "attach";
36262306a36Sopenharmony_ci	const char *path;
36362306a36Sopenharmony_ci	int ret;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	snprintf(buff, sizeof(buff), "%u %d %u %u",
36662306a36Sopenharmony_ci			port, sockfd, devid, speed);
36762306a36Sopenharmony_ci	dbg("writing: %s", buff);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	path = udev_device_get_syspath(vhci_driver->hc_device);
37062306a36Sopenharmony_ci	snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
37162306a36Sopenharmony_ci		 path, attr_attach);
37262306a36Sopenharmony_ci	dbg("attach attribute path: %s", attach_attr_path);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff));
37562306a36Sopenharmony_ci	if (ret < 0) {
37662306a36Sopenharmony_ci		dbg("write_sysfs_attribute failed");
37762306a36Sopenharmony_ci		return -1;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	dbg("attached port: %d", port);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	return 0;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic unsigned long get_devid(uint8_t busnum, uint8_t devnum)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	return (busnum << 16) | devnum;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/* will be removed */
39162306a36Sopenharmony_ciint usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
39262306a36Sopenharmony_ci		uint8_t devnum, uint32_t speed)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	int devid = get_devid(busnum, devnum);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return usbip_vhci_attach_device2(port, sockfd, devid, speed);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ciint usbip_vhci_detach_device(uint8_t port)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	char detach_attr_path[SYSFS_PATH_MAX];
40262306a36Sopenharmony_ci	char attr_detach[] = "detach";
40362306a36Sopenharmony_ci	char buff[200]; /* what size should be ? */
40462306a36Sopenharmony_ci	const char *path;
40562306a36Sopenharmony_ci	int ret;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	snprintf(buff, sizeof(buff), "%u", port);
40862306a36Sopenharmony_ci	dbg("writing: %s", buff);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	path = udev_device_get_syspath(vhci_driver->hc_device);
41162306a36Sopenharmony_ci	snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
41262306a36Sopenharmony_ci		 path, attr_detach);
41362306a36Sopenharmony_ci	dbg("detach attribute path: %s", detach_attr_path);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff));
41662306a36Sopenharmony_ci	if (ret < 0) {
41762306a36Sopenharmony_ci		dbg("write_sysfs_attribute failed");
41862306a36Sopenharmony_ci		return -1;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	dbg("detached port: %d", port);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	return 0;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ciint usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	char product_name[100];
42962306a36Sopenharmony_ci	char host[NI_MAXHOST] = "unknown host";
43062306a36Sopenharmony_ci	char serv[NI_MAXSERV] = "unknown port";
43162306a36Sopenharmony_ci	char remote_busid[SYSFS_BUS_ID_SIZE];
43262306a36Sopenharmony_ci	int ret;
43362306a36Sopenharmony_ci	int read_record_error = 0;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
43662306a36Sopenharmony_ci		return 0;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
43962306a36Sopenharmony_ci			  remote_busid);
44062306a36Sopenharmony_ci	if (ret) {
44162306a36Sopenharmony_ci		err("read_record");
44262306a36Sopenharmony_ci		read_record_error = 1;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	printf("Port %02d: <%s> at %s\n", idev->port,
44662306a36Sopenharmony_ci	       usbip_status_string(idev->status),
44762306a36Sopenharmony_ci	       usbip_speed_string(idev->udev.speed));
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	usbip_names_get_product(product_name, sizeof(product_name),
45062306a36Sopenharmony_ci				idev->udev.idVendor, idev->udev.idProduct);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	printf("       %s\n",  product_name);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (!read_record_error) {
45562306a36Sopenharmony_ci		printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid,
45662306a36Sopenharmony_ci		       host, serv, remote_busid);
45762306a36Sopenharmony_ci		printf("%10s -> remote bus/dev %03d/%03d\n", " ",
45862306a36Sopenharmony_ci		       idev->busnum, idev->devnum);
45962306a36Sopenharmony_ci	} else {
46062306a36Sopenharmony_ci		printf("%10s -> unknown host, remote port and remote busid\n",
46162306a36Sopenharmony_ci		       idev->udev.busid);
46262306a36Sopenharmony_ci		printf("%10s -> remote bus/dev %03d/%03d\n", " ",
46362306a36Sopenharmony_ci		       idev->busnum, idev->devnum);
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci}
468