1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2005-2007 Takahiro Hirofuchi
6 #include "usbip_common.h"
7 #include "vhci_driver.h"
12 #include "sysfs_utils.h"
15 #define PROGNAME "libusbip"
17 struct usbip_vhci_driver
*vhci_driver
;
18 struct udev
*udev_context
;
20 static struct usbip_imported_device
*
21 imported_device_init(struct usbip_imported_device
*idev
, char *busid
)
23 struct udev_device
*sudev
;
25 sudev
= udev_device_new_from_subsystem_sysname(udev_context
,
28 dbg("udev_device_new_from_subsystem_sysname failed: %s", busid
);
31 read_usb_device(sudev
, &idev
->udev
);
32 udev_device_unref(sudev
);
40 static int parse_status(const char *value
)
45 /* skip a header line */
46 c
= strchr(value
, '\n');
52 int port
, status
, speed
, devid
;
54 char lbusid
[SYSFS_BUS_ID_SIZE
];
55 struct usbip_imported_device
*idev
;
58 ret
= sscanf(c
, "%2s %d %d %d %x %u %31s\n",
59 hub
, &port
, &status
, &speed
,
60 &devid
, &sockfd
, lbusid
);
63 dbg("sscanf failed: %d", ret
);
67 dbg("hub %s port %d status %d speed %d devid %x",
68 hub
, port
, status
, speed
, devid
);
69 dbg("sockfd %u lbusid %s", sockfd
, lbusid
);
71 /* if a device is connected, look at it */
72 idev
= &vhci_driver
->idev
[port
];
73 memset(idev
, 0, sizeof(*idev
));
75 if (strncmp("hs", hub
, 2) == 0)
76 idev
->hub
= HUB_SPEED_HIGH
;
77 else /* strncmp("ss", hub, 2) == 0 */
78 idev
->hub
= HUB_SPEED_SUPER
;
81 idev
->status
= status
;
85 idev
->busnum
= (devid
>> 16);
86 idev
->devnum
= (devid
& 0x0000ffff);
88 if (idev
->status
!= VDEV_ST_NULL
89 && idev
->status
!= VDEV_ST_NOTASSIGNED
) {
90 idev
= imported_device_init(idev
, lbusid
);
92 dbg("imported_device_init failed");
97 /* go to the next line */
109 #define MAX_STATUS_NAME 18
111 static int refresh_imported_device_list(void)
113 const char *attr_status
;
114 char status
[MAX_STATUS_NAME
+1] = "status";
117 for (i
= 0; i
< vhci_driver
->ncontrollers
; i
++) {
119 snprintf(status
, sizeof(status
), "status.%d", i
);
121 attr_status
= udev_device_get_sysattr_value(vhci_driver
->hc_device
,
124 err("udev_device_get_sysattr_value failed");
128 dbg("controller %d", i
);
130 ret
= parse_status(attr_status
);
138 static int get_nports(struct udev_device
*hc_device
)
140 const char *attr_nports
;
142 attr_nports
= udev_device_get_sysattr_value(hc_device
, "nports");
144 err("udev_device_get_sysattr_value nports failed");
148 return (int)strtoul(attr_nports
, NULL
, 10);
151 static int vhci_hcd_filter(const struct dirent
*dirent
)
153 return !strncmp(dirent
->d_name
, "vhci_hcd.", 9);
156 static int get_ncontrollers(void)
158 struct dirent
**namelist
;
159 struct udev_device
*platform
;
162 platform
= udev_device_get_parent(vhci_driver
->hc_device
);
163 if (platform
== NULL
)
166 n
= scandir(udev_device_get_syspath(platform
), &namelist
, vhci_hcd_filter
, NULL
);
168 err("scandir failed");
170 for (int i
= 0; i
< n
; i
++)
179 * Read the given port's record.
181 * To avoid buffer overflow we will read the entire line and
182 * validate each part's size. The initial buffer is padded by 4 to
183 * accommodate the 2 spaces, 1 newline and an additional character
184 * which is needed to properly validate the 3rd part without it being
185 * truncated to an acceptable length.
187 static int read_record(int rhport
, char *host
, unsigned long host_len
,
188 char *port
, unsigned long port_len
, char *busid
)
192 char path
[PATH_MAX
+1];
193 char *buffer
, *start
, *end
;
194 char delim
[] = {' ', ' ', '\n'};
195 int max_len
[] = {(int)host_len
, (int)port_len
, SYSFS_BUS_ID_SIZE
};
196 size_t buffer_len
= host_len
+ port_len
+ SYSFS_BUS_ID_SIZE
+ 4;
198 buffer
= malloc(buffer_len
);
202 snprintf(path
, PATH_MAX
, VHCI_STATE_PATH
"/port%d", rhport
);
204 file
= fopen(path
, "r");
211 if (fgets(buffer
, buffer_len
, file
) == NULL
) {
219 /* validate the length of each of the 3 parts */
221 for (part
= 0; part
< 3; part
++) {
222 end
= strchr(start
, delim
[part
]);
223 if (end
== NULL
|| (end
- start
) > max_len
[part
]) {
230 if (sscanf(buffer
, "%s %s %s\n", host
, port
, busid
) != 3) {
241 /* ---------------------------------------------------------------------- */
243 int usbip_vhci_driver_open(void)
246 struct udev_device
*hc_device
;
248 udev_context
= udev_new();
250 err("udev_new failed");
254 /* will be freed in usbip_driver_close() */
256 udev_device_new_from_subsystem_sysname(udev_context
,
258 USBIP_VHCI_DEVICE_NAME
);
260 err("udev_device_new_from_subsystem_sysname failed");
264 nports
= get_nports(hc_device
);
266 err("no available ports");
269 dbg("available ports: %d", nports
);
271 vhci_driver
= calloc(1, sizeof(struct usbip_vhci_driver
) +
272 nports
* sizeof(struct usbip_imported_device
));
274 err("vhci_driver allocation failed");
278 vhci_driver
->nports
= nports
;
279 vhci_driver
->hc_device
= hc_device
;
280 vhci_driver
->ncontrollers
= get_ncontrollers();
281 dbg("available controllers: %d", vhci_driver
->ncontrollers
);
283 if (vhci_driver
->ncontrollers
<=0) {
284 err("no available usb controllers");
288 if (refresh_imported_device_list())
294 udev_device_unref(hc_device
);
301 udev_unref(udev_context
);
307 void usbip_vhci_driver_close(void)
312 udev_device_unref(vhci_driver
->hc_device
);
318 udev_unref(udev_context
);
322 int usbip_vhci_refresh_device_list(void)
325 if (refresh_imported_device_list())
330 dbg("failed to refresh device list");
335 int usbip_vhci_get_free_port(uint32_t speed
)
337 for (int i
= 0; i
< vhci_driver
->nports
; i
++) {
340 case USB_SPEED_SUPER
:
341 if (vhci_driver
->idev
[i
].hub
!= HUB_SPEED_SUPER
)
345 if (vhci_driver
->idev
[i
].hub
!= HUB_SPEED_HIGH
)
350 if (vhci_driver
->idev
[i
].status
== VDEV_ST_NULL
)
351 return vhci_driver
->idev
[i
].port
;
357 int usbip_vhci_attach_device2(uint8_t port
, int sockfd
, uint32_t devid
,
359 char buff
[200]; /* what size should be ? */
360 char attach_attr_path
[SYSFS_PATH_MAX
];
361 char attr_attach
[] = "attach";
365 snprintf(buff
, sizeof(buff
), "%u %d %u %u",
366 port
, sockfd
, devid
, speed
);
367 dbg("writing: %s", buff
);
369 path
= udev_device_get_syspath(vhci_driver
->hc_device
);
370 snprintf(attach_attr_path
, sizeof(attach_attr_path
), "%s/%s",
372 dbg("attach attribute path: %s", attach_attr_path
);
374 ret
= write_sysfs_attribute(attach_attr_path
, buff
, strlen(buff
));
376 dbg("write_sysfs_attribute failed");
380 dbg("attached port: %d", port
);
385 static unsigned long get_devid(uint8_t busnum
, uint8_t devnum
)
387 return (busnum
<< 16) | devnum
;
390 /* will be removed */
391 int usbip_vhci_attach_device(uint8_t port
, int sockfd
, uint8_t busnum
,
392 uint8_t devnum
, uint32_t speed
)
394 int devid
= get_devid(busnum
, devnum
);
396 return usbip_vhci_attach_device2(port
, sockfd
, devid
, speed
);
399 int usbip_vhci_detach_device(uint8_t port
)
401 char detach_attr_path
[SYSFS_PATH_MAX
];
402 char attr_detach
[] = "detach";
403 char buff
[200]; /* what size should be ? */
407 snprintf(buff
, sizeof(buff
), "%u", port
);
408 dbg("writing: %s", buff
);
410 path
= udev_device_get_syspath(vhci_driver
->hc_device
);
411 snprintf(detach_attr_path
, sizeof(detach_attr_path
), "%s/%s",
413 dbg("detach attribute path: %s", detach_attr_path
);
415 ret
= write_sysfs_attribute(detach_attr_path
, buff
, strlen(buff
));
417 dbg("write_sysfs_attribute failed");
421 dbg("detached port: %d", port
);
426 int usbip_vhci_imported_device_dump(struct usbip_imported_device
*idev
)
428 char product_name
[100];
429 char host
[NI_MAXHOST
] = "unknown host";
430 char serv
[NI_MAXSERV
] = "unknown port";
431 char remote_busid
[SYSFS_BUS_ID_SIZE
];
433 int read_record_error
= 0;
435 if (idev
->status
== VDEV_ST_NULL
|| idev
->status
== VDEV_ST_NOTASSIGNED
)
438 ret
= read_record(idev
->port
, host
, sizeof(host
), serv
, sizeof(serv
),
442 read_record_error
= 1;
445 printf("Port %02d: <%s> at %s\n", idev
->port
,
446 usbip_status_string(idev
->status
),
447 usbip_speed_string(idev
->udev
.speed
));
449 usbip_names_get_product(product_name
, sizeof(product_name
),
450 idev
->udev
.idVendor
, idev
->udev
.idProduct
);
452 printf(" %s\n", product_name
);
454 if (!read_record_error
) {
455 printf("%10s -> usbip://%s:%s/%s\n", idev
->udev
.busid
,
456 host
, serv
, remote_busid
);
457 printf("%10s -> remote bus/dev %03d/%03d\n", " ",
458 idev
->busnum
, idev
->devnum
);
460 printf("%10s -> unknown host, remote port and remote busid\n",
462 printf("%10s -> remote bus/dev %03d/%03d\n", " ",
463 idev
->busnum
, idev
->devnum
);