18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2005-2007 Takahiro Hirofuchi
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "usbip_common.h"
78c2ecf20Sopenharmony_ci#include "vhci_driver.h"
88c2ecf20Sopenharmony_ci#include <limits.h>
98c2ecf20Sopenharmony_ci#include <netdb.h>
108c2ecf20Sopenharmony_ci#include <libudev.h>
118c2ecf20Sopenharmony_ci#include <dirent.h>
128c2ecf20Sopenharmony_ci#include "sysfs_utils.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#undef  PROGNAME
158c2ecf20Sopenharmony_ci#define PROGNAME "libusbip"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistruct usbip_vhci_driver *vhci_driver;
188c2ecf20Sopenharmony_cistruct udev *udev_context;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic struct usbip_imported_device *
218c2ecf20Sopenharmony_ciimported_device_init(struct usbip_imported_device *idev, char *busid)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	struct udev_device *sudev;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	sudev = udev_device_new_from_subsystem_sysname(udev_context,
268c2ecf20Sopenharmony_ci						       "usb", busid);
278c2ecf20Sopenharmony_ci	if (!sudev) {
288c2ecf20Sopenharmony_ci		dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
298c2ecf20Sopenharmony_ci		goto err;
308c2ecf20Sopenharmony_ci	}
318c2ecf20Sopenharmony_ci	read_usb_device(sudev, &idev->udev);
328c2ecf20Sopenharmony_ci	udev_device_unref(sudev);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	return idev;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cierr:
378c2ecf20Sopenharmony_ci	return NULL;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic int parse_status(const char *value)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	int ret = 0;
438c2ecf20Sopenharmony_ci	char *c;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/* skip a header line */
468c2ecf20Sopenharmony_ci	c = strchr(value, '\n');
478c2ecf20Sopenharmony_ci	if (!c)
488c2ecf20Sopenharmony_ci		return -1;
498c2ecf20Sopenharmony_ci	c++;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	while (*c != '\0') {
528c2ecf20Sopenharmony_ci		int port, status, speed, devid;
538c2ecf20Sopenharmony_ci		int sockfd;
548c2ecf20Sopenharmony_ci		char lbusid[SYSFS_BUS_ID_SIZE];
558c2ecf20Sopenharmony_ci		struct usbip_imported_device *idev;
568c2ecf20Sopenharmony_ci		char hub[3];
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		ret = sscanf(c, "%2s  %d %d %d %x %u %31s\n",
598c2ecf20Sopenharmony_ci				hub, &port, &status, &speed,
608c2ecf20Sopenharmony_ci				&devid, &sockfd, lbusid);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci		if (ret < 5) {
638c2ecf20Sopenharmony_ci			dbg("sscanf failed: %d", ret);
648c2ecf20Sopenharmony_ci			BUG();
658c2ecf20Sopenharmony_ci		}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci		dbg("hub %s port %d status %d speed %d devid %x",
688c2ecf20Sopenharmony_ci				hub, port, status, speed, devid);
698c2ecf20Sopenharmony_ci		dbg("sockfd %u lbusid %s", sockfd, lbusid);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci		/* if a device is connected, look at it */
728c2ecf20Sopenharmony_ci		idev = &vhci_driver->idev[port];
738c2ecf20Sopenharmony_ci		memset(idev, 0, sizeof(*idev));
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		if (strncmp("hs", hub, 2) == 0)
768c2ecf20Sopenharmony_ci			idev->hub = HUB_SPEED_HIGH;
778c2ecf20Sopenharmony_ci		else /* strncmp("ss", hub, 2) == 0 */
788c2ecf20Sopenharmony_ci			idev->hub = HUB_SPEED_SUPER;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		idev->port	= port;
818c2ecf20Sopenharmony_ci		idev->status	= status;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		idev->devid	= devid;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		idev->busnum	= (devid >> 16);
868c2ecf20Sopenharmony_ci		idev->devnum	= (devid & 0x0000ffff);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		if (idev->status != VDEV_ST_NULL
898c2ecf20Sopenharmony_ci		    && idev->status != VDEV_ST_NOTASSIGNED) {
908c2ecf20Sopenharmony_ci			idev = imported_device_init(idev, lbusid);
918c2ecf20Sopenharmony_ci			if (!idev) {
928c2ecf20Sopenharmony_ci				dbg("imported_device_init failed");
938c2ecf20Sopenharmony_ci				return -1;
948c2ecf20Sopenharmony_ci			}
958c2ecf20Sopenharmony_ci		}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci		/* go to the next line */
988c2ecf20Sopenharmony_ci		c = strchr(c, '\n');
998c2ecf20Sopenharmony_ci		if (!c)
1008c2ecf20Sopenharmony_ci			break;
1018c2ecf20Sopenharmony_ci		c++;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	dbg("exit");
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return 0;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#define MAX_STATUS_NAME 18
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int refresh_imported_device_list(void)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	const char *attr_status;
1148c2ecf20Sopenharmony_ci	char status[MAX_STATUS_NAME+1] = "status";
1158c2ecf20Sopenharmony_ci	int i, ret;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	for (i = 0; i < vhci_driver->ncontrollers; i++) {
1188c2ecf20Sopenharmony_ci		if (i > 0)
1198c2ecf20Sopenharmony_ci			snprintf(status, sizeof(status), "status.%d", i);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
1228c2ecf20Sopenharmony_ci							    status);
1238c2ecf20Sopenharmony_ci		if (!attr_status) {
1248c2ecf20Sopenharmony_ci			err("udev_device_get_sysattr_value failed");
1258c2ecf20Sopenharmony_ci			return -1;
1268c2ecf20Sopenharmony_ci		}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci		dbg("controller %d", i);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		ret = parse_status(attr_status);
1318c2ecf20Sopenharmony_ci		if (ret != 0)
1328c2ecf20Sopenharmony_ci			return ret;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int get_nports(struct udev_device *hc_device)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	const char *attr_nports;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	attr_nports = udev_device_get_sysattr_value(hc_device, "nports");
1438c2ecf20Sopenharmony_ci	if (!attr_nports) {
1448c2ecf20Sopenharmony_ci		err("udev_device_get_sysattr_value nports failed");
1458c2ecf20Sopenharmony_ci		return -1;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return (int)strtoul(attr_nports, NULL, 10);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic int vhci_hcd_filter(const struct dirent *dirent)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	return !strncmp(dirent->d_name, "vhci_hcd.", 9);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic int get_ncontrollers(void)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct dirent **namelist;
1598c2ecf20Sopenharmony_ci	struct udev_device *platform;
1608c2ecf20Sopenharmony_ci	int n;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	platform = udev_device_get_parent(vhci_driver->hc_device);
1638c2ecf20Sopenharmony_ci	if (platform == NULL)
1648c2ecf20Sopenharmony_ci		return -1;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	n = scandir(udev_device_get_syspath(platform), &namelist, vhci_hcd_filter, NULL);
1678c2ecf20Sopenharmony_ci	if (n < 0)
1688c2ecf20Sopenharmony_ci		err("scandir failed");
1698c2ecf20Sopenharmony_ci	else {
1708c2ecf20Sopenharmony_ci		for (int i = 0; i < n; i++)
1718c2ecf20Sopenharmony_ci			free(namelist[i]);
1728c2ecf20Sopenharmony_ci		free(namelist);
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return n;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/*
1798c2ecf20Sopenharmony_ci * Read the given port's record.
1808c2ecf20Sopenharmony_ci *
1818c2ecf20Sopenharmony_ci * To avoid buffer overflow we will read the entire line and
1828c2ecf20Sopenharmony_ci * validate each part's size. The initial buffer is padded by 4 to
1838c2ecf20Sopenharmony_ci * accommodate the 2 spaces, 1 newline and an additional character
1848c2ecf20Sopenharmony_ci * which is needed to properly validate the 3rd part without it being
1858c2ecf20Sopenharmony_ci * truncated to an acceptable length.
1868c2ecf20Sopenharmony_ci */
1878c2ecf20Sopenharmony_cistatic int read_record(int rhport, char *host, unsigned long host_len,
1888c2ecf20Sopenharmony_ci		char *port, unsigned long port_len, char *busid)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	int part;
1918c2ecf20Sopenharmony_ci	FILE *file;
1928c2ecf20Sopenharmony_ci	char path[PATH_MAX+1];
1938c2ecf20Sopenharmony_ci	char *buffer, *start, *end;
1948c2ecf20Sopenharmony_ci	char delim[] = {' ', ' ', '\n'};
1958c2ecf20Sopenharmony_ci	int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
1968c2ecf20Sopenharmony_ci	size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	buffer = malloc(buffer_len);
1998c2ecf20Sopenharmony_ci	if (!buffer)
2008c2ecf20Sopenharmony_ci		return -1;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	file = fopen(path, "r");
2058c2ecf20Sopenharmony_ci	if (!file) {
2068c2ecf20Sopenharmony_ci		err("fopen");
2078c2ecf20Sopenharmony_ci		free(buffer);
2088c2ecf20Sopenharmony_ci		return -1;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (fgets(buffer, buffer_len, file) == NULL) {
2128c2ecf20Sopenharmony_ci		err("fgets");
2138c2ecf20Sopenharmony_ci		free(buffer);
2148c2ecf20Sopenharmony_ci		fclose(file);
2158c2ecf20Sopenharmony_ci		return -1;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci	fclose(file);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/* validate the length of each of the 3 parts */
2208c2ecf20Sopenharmony_ci	start = buffer;
2218c2ecf20Sopenharmony_ci	for (part = 0; part < 3; part++) {
2228c2ecf20Sopenharmony_ci		end = strchr(start, delim[part]);
2238c2ecf20Sopenharmony_ci		if (end == NULL || (end - start) > max_len[part]) {
2248c2ecf20Sopenharmony_ci			free(buffer);
2258c2ecf20Sopenharmony_ci			return -1;
2268c2ecf20Sopenharmony_ci		}
2278c2ecf20Sopenharmony_ci		start = end + 1;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
2318c2ecf20Sopenharmony_ci		err("sscanf");
2328c2ecf20Sopenharmony_ci		free(buffer);
2338c2ecf20Sopenharmony_ci		return -1;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	free(buffer);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return 0;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------- */
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ciint usbip_vhci_driver_open(void)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	int nports;
2468c2ecf20Sopenharmony_ci	struct udev_device *hc_device;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	udev_context = udev_new();
2498c2ecf20Sopenharmony_ci	if (!udev_context) {
2508c2ecf20Sopenharmony_ci		err("udev_new failed");
2518c2ecf20Sopenharmony_ci		return -1;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/* will be freed in usbip_driver_close() */
2558c2ecf20Sopenharmony_ci	hc_device =
2568c2ecf20Sopenharmony_ci		udev_device_new_from_subsystem_sysname(udev_context,
2578c2ecf20Sopenharmony_ci						       USBIP_VHCI_BUS_TYPE,
2588c2ecf20Sopenharmony_ci						       USBIP_VHCI_DEVICE_NAME);
2598c2ecf20Sopenharmony_ci	if (!hc_device) {
2608c2ecf20Sopenharmony_ci		err("udev_device_new_from_subsystem_sysname failed");
2618c2ecf20Sopenharmony_ci		goto err;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	nports = get_nports(hc_device);
2658c2ecf20Sopenharmony_ci	if (nports <= 0) {
2668c2ecf20Sopenharmony_ci		err("no available ports");
2678c2ecf20Sopenharmony_ci		goto err;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci	dbg("available ports: %d", nports);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver) +
2728c2ecf20Sopenharmony_ci			nports * sizeof(struct usbip_imported_device));
2738c2ecf20Sopenharmony_ci	if (!vhci_driver) {
2748c2ecf20Sopenharmony_ci		err("vhci_driver allocation failed");
2758c2ecf20Sopenharmony_ci		goto err;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	vhci_driver->nports = nports;
2798c2ecf20Sopenharmony_ci	vhci_driver->hc_device = hc_device;
2808c2ecf20Sopenharmony_ci	vhci_driver->ncontrollers = get_ncontrollers();
2818c2ecf20Sopenharmony_ci	dbg("available controllers: %d", vhci_driver->ncontrollers);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (vhci_driver->ncontrollers <=0) {
2848c2ecf20Sopenharmony_ci		err("no available usb controllers");
2858c2ecf20Sopenharmony_ci		goto err;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (refresh_imported_device_list())
2898c2ecf20Sopenharmony_ci		goto err;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return 0;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cierr:
2948c2ecf20Sopenharmony_ci	udev_device_unref(hc_device);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (vhci_driver)
2978c2ecf20Sopenharmony_ci		free(vhci_driver);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	vhci_driver = NULL;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	udev_unref(udev_context);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return -1;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_civoid usbip_vhci_driver_close(void)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	if (!vhci_driver)
3108c2ecf20Sopenharmony_ci		return;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	udev_device_unref(vhci_driver->hc_device);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	free(vhci_driver);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	vhci_driver = NULL;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	udev_unref(udev_context);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ciint usbip_vhci_refresh_device_list(void)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (refresh_imported_device_list())
3268c2ecf20Sopenharmony_ci		goto err;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return 0;
3298c2ecf20Sopenharmony_cierr:
3308c2ecf20Sopenharmony_ci	dbg("failed to refresh device list");
3318c2ecf20Sopenharmony_ci	return -1;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ciint usbip_vhci_get_free_port(uint32_t speed)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	for (int i = 0; i < vhci_driver->nports; i++) {
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		switch (speed) {
3408c2ecf20Sopenharmony_ci		case	USB_SPEED_SUPER:
3418c2ecf20Sopenharmony_ci			if (vhci_driver->idev[i].hub != HUB_SPEED_SUPER)
3428c2ecf20Sopenharmony_ci				continue;
3438c2ecf20Sopenharmony_ci		break;
3448c2ecf20Sopenharmony_ci		default:
3458c2ecf20Sopenharmony_ci			if (vhci_driver->idev[i].hub != HUB_SPEED_HIGH)
3468c2ecf20Sopenharmony_ci				continue;
3478c2ecf20Sopenharmony_ci		break;
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		if (vhci_driver->idev[i].status == VDEV_ST_NULL)
3518c2ecf20Sopenharmony_ci			return vhci_driver->idev[i].port;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return -1;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ciint usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
3588c2ecf20Sopenharmony_ci		uint32_t speed) {
3598c2ecf20Sopenharmony_ci	char buff[200]; /* what size should be ? */
3608c2ecf20Sopenharmony_ci	char attach_attr_path[SYSFS_PATH_MAX];
3618c2ecf20Sopenharmony_ci	char attr_attach[] = "attach";
3628c2ecf20Sopenharmony_ci	const char *path;
3638c2ecf20Sopenharmony_ci	int ret;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	snprintf(buff, sizeof(buff), "%u %d %u %u",
3668c2ecf20Sopenharmony_ci			port, sockfd, devid, speed);
3678c2ecf20Sopenharmony_ci	dbg("writing: %s", buff);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	path = udev_device_get_syspath(vhci_driver->hc_device);
3708c2ecf20Sopenharmony_ci	snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
3718c2ecf20Sopenharmony_ci		 path, attr_attach);
3728c2ecf20Sopenharmony_ci	dbg("attach attribute path: %s", attach_attr_path);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff));
3758c2ecf20Sopenharmony_ci	if (ret < 0) {
3768c2ecf20Sopenharmony_ci		dbg("write_sysfs_attribute failed");
3778c2ecf20Sopenharmony_ci		return -1;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	dbg("attached port: %d", port);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	return 0;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic unsigned long get_devid(uint8_t busnum, uint8_t devnum)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	return (busnum << 16) | devnum;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci/* will be removed */
3918c2ecf20Sopenharmony_ciint usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
3928c2ecf20Sopenharmony_ci		uint8_t devnum, uint32_t speed)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	int devid = get_devid(busnum, devnum);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	return usbip_vhci_attach_device2(port, sockfd, devid, speed);
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ciint usbip_vhci_detach_device(uint8_t port)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	char detach_attr_path[SYSFS_PATH_MAX];
4028c2ecf20Sopenharmony_ci	char attr_detach[] = "detach";
4038c2ecf20Sopenharmony_ci	char buff[200]; /* what size should be ? */
4048c2ecf20Sopenharmony_ci	const char *path;
4058c2ecf20Sopenharmony_ci	int ret;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	snprintf(buff, sizeof(buff), "%u", port);
4088c2ecf20Sopenharmony_ci	dbg("writing: %s", buff);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	path = udev_device_get_syspath(vhci_driver->hc_device);
4118c2ecf20Sopenharmony_ci	snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
4128c2ecf20Sopenharmony_ci		 path, attr_detach);
4138c2ecf20Sopenharmony_ci	dbg("detach attribute path: %s", detach_attr_path);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff));
4168c2ecf20Sopenharmony_ci	if (ret < 0) {
4178c2ecf20Sopenharmony_ci		dbg("write_sysfs_attribute failed");
4188c2ecf20Sopenharmony_ci		return -1;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	dbg("detached port: %d", port);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	return 0;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ciint usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	char product_name[100];
4298c2ecf20Sopenharmony_ci	char host[NI_MAXHOST] = "unknown host";
4308c2ecf20Sopenharmony_ci	char serv[NI_MAXSERV] = "unknown port";
4318c2ecf20Sopenharmony_ci	char remote_busid[SYSFS_BUS_ID_SIZE];
4328c2ecf20Sopenharmony_ci	int ret;
4338c2ecf20Sopenharmony_ci	int read_record_error = 0;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
4368c2ecf20Sopenharmony_ci		return 0;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
4398c2ecf20Sopenharmony_ci			  remote_busid);
4408c2ecf20Sopenharmony_ci	if (ret) {
4418c2ecf20Sopenharmony_ci		err("read_record");
4428c2ecf20Sopenharmony_ci		read_record_error = 1;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	printf("Port %02d: <%s> at %s\n", idev->port,
4468c2ecf20Sopenharmony_ci	       usbip_status_string(idev->status),
4478c2ecf20Sopenharmony_ci	       usbip_speed_string(idev->udev.speed));
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	usbip_names_get_product(product_name, sizeof(product_name),
4508c2ecf20Sopenharmony_ci				idev->udev.idVendor, idev->udev.idProduct);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	printf("       %s\n",  product_name);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	if (!read_record_error) {
4558c2ecf20Sopenharmony_ci		printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid,
4568c2ecf20Sopenharmony_ci		       host, serv, remote_busid);
4578c2ecf20Sopenharmony_ci		printf("%10s -> remote bus/dev %03d/%03d\n", " ",
4588c2ecf20Sopenharmony_ci		       idev->busnum, idev->devnum);
4598c2ecf20Sopenharmony_ci	} else {
4608c2ecf20Sopenharmony_ci		printf("%10s -> unknown host, remote port and remote busid\n",
4618c2ecf20Sopenharmony_ci		       idev->udev.busid);
4628c2ecf20Sopenharmony_ci		printf("%10s -> remote bus/dev %03d/%03d\n", " ",
4638c2ecf20Sopenharmony_ci		       idev->busnum, idev->devnum);
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return 0;
4678c2ecf20Sopenharmony_ci}
468