Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/usb/usbip/src/usbip_bind.c
26288 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (C) 2011 matt mooney <[email protected]>
4
* 2005-2007 Takahiro Hirofuchi
5
*/
6
7
#include <libudev.h>
8
9
#include <errno.h>
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <string.h>
13
14
#include <getopt.h>
15
16
#include "usbip_common.h"
17
#include "utils.h"
18
#include "usbip.h"
19
#include "sysfs_utils.h"
20
21
enum unbind_status {
22
UNBIND_ST_OK,
23
UNBIND_ST_USBIP_HOST,
24
UNBIND_ST_FAILED
25
};
26
27
static const char usbip_bind_usage_string[] =
28
"usbip bind <args>\n"
29
" -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device "
30
"on <busid>\n";
31
32
void usbip_bind_usage(void)
33
{
34
printf("usage: %s", usbip_bind_usage_string);
35
}
36
37
/* call at unbound state */
38
static int bind_usbip(char *busid)
39
{
40
char attr_name[] = "bind";
41
char bind_attr_path[SYSFS_PATH_MAX];
42
int rc = -1;
43
44
snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
45
SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
46
SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
47
48
rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
49
if (rc < 0) {
50
err("error binding device %s to driver: %s", busid,
51
strerror(errno));
52
return -1;
53
}
54
55
return 0;
56
}
57
58
/* buggy driver may cause dead lock */
59
static int unbind_other(char *busid)
60
{
61
enum unbind_status status = UNBIND_ST_OK;
62
63
char attr_name[] = "unbind";
64
char unbind_attr_path[SYSFS_PATH_MAX];
65
int rc = -1;
66
67
struct udev *udev;
68
struct udev_device *dev;
69
const char *driver;
70
const char *bDevClass;
71
72
/* Create libudev context. */
73
udev = udev_new();
74
75
/* Get the device. */
76
dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
77
if (!dev) {
78
dbg("unable to find device with bus ID %s", busid);
79
goto err_close_busid_dev;
80
}
81
82
/* Check what kind of device it is. */
83
bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass");
84
if (!bDevClass) {
85
dbg("unable to get bDevClass device attribute");
86
goto err_close_busid_dev;
87
}
88
89
if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
90
dbg("skip unbinding of hub");
91
goto err_close_busid_dev;
92
}
93
94
/* Get the device driver. */
95
driver = udev_device_get_driver(dev);
96
if (!driver) {
97
/* No driver bound to this device. */
98
goto out;
99
}
100
101
if (!strncmp(USBIP_HOST_DRV_NAME, driver,
102
strlen(USBIP_HOST_DRV_NAME))) {
103
/* Already bound to usbip-host. */
104
status = UNBIND_ST_USBIP_HOST;
105
goto out;
106
}
107
108
/* Unbind device from driver. */
109
snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
110
SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
111
SYSFS_DRIVERS_NAME, driver, attr_name);
112
113
rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
114
if (rc < 0) {
115
err("error unbinding device %s from driver", busid);
116
goto err_close_busid_dev;
117
}
118
119
goto out;
120
121
err_close_busid_dev:
122
status = UNBIND_ST_FAILED;
123
out:
124
udev_device_unref(dev);
125
udev_unref(udev);
126
127
return status;
128
}
129
130
static int bind_device(char *busid)
131
{
132
int rc;
133
struct udev *udev;
134
struct udev_device *dev;
135
const char *devpath;
136
137
/* Check whether the device with this bus ID exists. */
138
udev = udev_new();
139
dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
140
if (!dev) {
141
err("device with the specified bus ID does not exist");
142
return -1;
143
}
144
devpath = udev_device_get_devpath(dev);
145
udev_unref(udev);
146
147
/* If the device is already attached to vhci_hcd - bail out */
148
if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
149
err("bind loop detected: device: %s is attached to %s\n",
150
devpath, USBIP_VHCI_DRV_NAME);
151
return -1;
152
}
153
154
rc = unbind_other(busid);
155
if (rc == UNBIND_ST_FAILED) {
156
err("could not unbind driver from device on busid %s", busid);
157
return -1;
158
} else if (rc == UNBIND_ST_USBIP_HOST) {
159
err("device on busid %s is already bound to %s", busid,
160
USBIP_HOST_DRV_NAME);
161
return -1;
162
}
163
164
rc = modify_match_busid(busid, 1);
165
if (rc < 0) {
166
err("unable to bind device on %s", busid);
167
return -1;
168
}
169
170
rc = bind_usbip(busid);
171
if (rc < 0) {
172
err("could not bind device to %s", USBIP_HOST_DRV_NAME);
173
modify_match_busid(busid, 0);
174
return -1;
175
}
176
177
info("bind device on busid %s: complete", busid);
178
179
return 0;
180
}
181
182
int usbip_bind(int argc, char *argv[])
183
{
184
static const struct option opts[] = {
185
{ "busid", required_argument, NULL, 'b' },
186
{ NULL, 0, NULL, 0 }
187
};
188
189
int opt;
190
int ret = -1;
191
192
for (;;) {
193
opt = getopt_long(argc, argv, "b:", opts, NULL);
194
195
if (opt == -1)
196
break;
197
198
switch (opt) {
199
case 'b':
200
ret = bind_device(optarg);
201
goto out;
202
default:
203
goto err_out;
204
}
205
}
206
207
err_out:
208
usbip_bind_usage();
209
out:
210
return ret;
211
}
212
213