diff options
Diffstat (limited to 'tools/usb/usbip/src/usbip_unbind.c')
-rw-r--r-- | tools/usb/usbip/src/usbip_unbind.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/tools/usb/usbip/src/usbip_unbind.c b/tools/usb/usbip/src/usbip_unbind.c new file mode 100644 index 000000000000..a4a496c9cbaf --- /dev/null +++ b/tools/usb/usbip/src/usbip_unbind.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
3 | * 2005-2007 Takahiro Hirofuchi | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <libudev.h> | ||
20 | |||
21 | #include <errno.h> | ||
22 | #include <stdio.h> | ||
23 | #include <string.h> | ||
24 | |||
25 | #include <getopt.h> | ||
26 | |||
27 | #include "usbip_common.h" | ||
28 | #include "utils.h" | ||
29 | #include "usbip.h" | ||
30 | #include "sysfs_utils.h" | ||
31 | |||
32 | static const char usbip_unbind_usage_string[] = | ||
33 | "usbip unbind <args>\n" | ||
34 | " -b, --busid=<busid> Unbind " USBIP_HOST_DRV_NAME ".ko from " | ||
35 | "device on <busid>\n"; | ||
36 | |||
37 | void usbip_unbind_usage(void) | ||
38 | { | ||
39 | printf("usage: %s", usbip_unbind_usage_string); | ||
40 | } | ||
41 | |||
42 | static int unbind_device(char *busid) | ||
43 | { | ||
44 | char bus_type[] = "usb"; | ||
45 | int rc, ret = -1; | ||
46 | |||
47 | char unbind_attr_name[] = "unbind"; | ||
48 | char unbind_attr_path[SYSFS_PATH_MAX]; | ||
49 | char rebind_attr_name[] = "rebind"; | ||
50 | char rebind_attr_path[SYSFS_PATH_MAX]; | ||
51 | |||
52 | struct udev *udev; | ||
53 | struct udev_device *dev; | ||
54 | const char *driver; | ||
55 | |||
56 | /* Create libudev context. */ | ||
57 | udev = udev_new(); | ||
58 | |||
59 | /* Check whether the device with this bus ID exists. */ | ||
60 | dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); | ||
61 | if (!dev) { | ||
62 | err("device with the specified bus ID does not exist"); | ||
63 | goto err_close_udev; | ||
64 | } | ||
65 | |||
66 | /* Check whether the device is using usbip-host driver. */ | ||
67 | driver = udev_device_get_driver(dev); | ||
68 | if (!driver || strcmp(driver, "usbip-host")) { | ||
69 | err("device is not bound to usbip-host driver"); | ||
70 | goto err_close_udev; | ||
71 | } | ||
72 | |||
73 | /* Unbind device from driver. */ | ||
74 | snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", | ||
75 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, | ||
76 | USBIP_HOST_DRV_NAME, unbind_attr_name); | ||
77 | |||
78 | rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid)); | ||
79 | if (rc < 0) { | ||
80 | err("error unbinding device %s from driver", busid); | ||
81 | goto err_close_udev; | ||
82 | } | ||
83 | |||
84 | /* Notify driver of unbind. */ | ||
85 | rc = modify_match_busid(busid, 0); | ||
86 | if (rc < 0) { | ||
87 | err("unable to unbind device on %s", busid); | ||
88 | goto err_close_udev; | ||
89 | } | ||
90 | |||
91 | /* Trigger new probing. */ | ||
92 | snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", | ||
93 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, | ||
94 | USBIP_HOST_DRV_NAME, rebind_attr_name); | ||
95 | |||
96 | rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid)); | ||
97 | if (rc < 0) { | ||
98 | err("error rebinding"); | ||
99 | goto err_close_udev; | ||
100 | } | ||
101 | |||
102 | ret = 0; | ||
103 | info("unbind device on busid %s: complete", busid); | ||
104 | |||
105 | err_close_udev: | ||
106 | udev_device_unref(dev); | ||
107 | udev_unref(udev); | ||
108 | |||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | int usbip_unbind(int argc, char *argv[]) | ||
113 | { | ||
114 | static const struct option opts[] = { | ||
115 | { "busid", required_argument, NULL, 'b' }, | ||
116 | { NULL, 0, NULL, 0 } | ||
117 | }; | ||
118 | |||
119 | int opt; | ||
120 | int ret = -1; | ||
121 | |||
122 | for (;;) { | ||
123 | opt = getopt_long(argc, argv, "b:", opts, NULL); | ||
124 | |||
125 | if (opt == -1) | ||
126 | break; | ||
127 | |||
128 | switch (opt) { | ||
129 | case 'b': | ||
130 | ret = unbind_device(optarg); | ||
131 | goto out; | ||
132 | default: | ||
133 | goto err_out; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | err_out: | ||
138 | usbip_unbind_usage(); | ||
139 | out: | ||
140 | return ret; | ||
141 | } | ||