1 /*
2  * Copyright (C) 2005-2007 Takahiro Hirofuchi
3  */
4 
5 #include "usbip_common.h"
6 #include "vhci_driver.h"
7 
8 #undef  PROGNAME
9 #define PROGNAME "libusbip"
10 
11 struct usbip_vhci_driver *vhci_driver;
12 
imported_device_init(struct usbip_imported_device * idev,char * busid)13 static struct usbip_imported_device *imported_device_init(struct usbip_imported_device *idev, char *busid)
14 {
15 	struct sysfs_device *sudev;
16 
17 	sudev = sysfs_open_device("usb", busid);
18 	if (!sudev) {
19 		dbg("sysfs_open_device failed: %s", busid);
20 		goto err;
21 	}
22 	read_usb_device(sudev, &idev->udev);
23 	sysfs_close_device(sudev);
24 
25 	/* add class devices of this imported device */
26 	struct usbip_class_device *cdev;
27 	dlist_for_each_data(vhci_driver->cdev_list, cdev,
28 			    struct usbip_class_device) {
29 		if (!strncmp(cdev->dev_path, idev->udev.path,
30 			     strlen(idev->udev.path))) {
31 			struct usbip_class_device *new_cdev;
32 
33 			/* alloc and copy because dlist is linked from only one list */
34 			new_cdev = calloc(1, sizeof(*new_cdev));
35 			if (!new_cdev)
36 				goto err;
37 
38 			memcpy(new_cdev, cdev, sizeof(*new_cdev));
39 			dlist_unshift(idev->cdev_list, (void*) new_cdev);
40 		}
41 	}
42 
43 	return idev;
44 
45 err:
46 	return NULL;
47 }
48 
49 
50 
parse_status(char * value)51 static int parse_status(char *value)
52 {
53 	int ret = 0;
54 	char *c;
55 
56 
57 	for (int i = 0; i < vhci_driver->nports; i++)
58 		memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
59 
60 
61 	/* skip a header line */
62 	c = strchr(value, '\n') + 1;
63 
64 	while (*c != '\0') {
65 		int port, status, speed, devid;
66 		unsigned long socket;
67 		char lbusid[SYSFS_BUS_ID_SIZE];
68 
69 		ret = sscanf(c, "%d %d %d %x %lx %s\n",
70 				&port, &status, &speed,
71 				&devid, &socket, lbusid);
72 
73 		if (ret < 5) {
74 			dbg("sscanf failed: %d", ret);
75 			BUG();
76 		}
77 
78 		dbg("port %d status %d speed %d devid %x",
79 				port, status, speed, devid);
80 		dbg("socket %lx lbusid %s", socket, lbusid);
81 
82 
83 		/* if a device is connected, look at it */
84 		{
85 			struct usbip_imported_device *idev = &vhci_driver->idev[port];
86 
87 			idev->port	= port;
88 			idev->status	= status;
89 
90 			idev->devid	= devid;
91 
92 			idev->busnum	= (devid >> 16);
93 			idev->devnum	= (devid & 0x0000ffff);
94 
95 			idev->cdev_list = dlist_new(sizeof(struct usbip_class_device));
96 			if (!idev->cdev_list) {
97 				dbg("dlist_new failed");
98 				return -1;
99 			}
100 
101 			if (idev->status != VDEV_ST_NULL && idev->status != VDEV_ST_NOTASSIGNED) {
102 				idev = imported_device_init(idev, lbusid);
103 				if (!idev) {
104 					dbg("imported_device_init failed");
105 					return -1;
106 				}
107 			}
108 		}
109 
110 
111 		/* go to the next line */
112 		c = strchr(c, '\n') + 1;
113 	}
114 
115 	dbg("exit");
116 
117 	return 0;
118 }
119 
120 
check_usbip_device(struct sysfs_class_device * cdev)121 static int check_usbip_device(struct sysfs_class_device *cdev)
122 {
123 	char class_path[SYSFS_PATH_MAX]; /* /sys/class/video4linux/video0/device */
124 	char dev_path[SYSFS_PATH_MAX];	 /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */
125 	int ret;
126 	struct usbip_class_device *usbip_cdev;
127 
128 	snprintf(class_path, sizeof(class_path), "%s/device", cdev->path);
129 
130 	ret = sysfs_get_link(class_path, dev_path, sizeof(dev_path));
131 	if (ret == 0) {
132 		if (!strncmp(dev_path, vhci_driver->hc_device->path,
133 			     strlen(vhci_driver->hc_device->path))) {
134 			/* found usbip device */
135 			usbip_cdev = calloc(1, sizeof(*usbip_cdev));
136 			if (!usbip_cdev) {
137 				dbg("calloc failed");
138 				return -1;
139 			}
140 			dlist_unshift(vhci_driver->cdev_list, usbip_cdev);
141 			strncpy(usbip_cdev->class_path, class_path,
142 				sizeof(usbip_cdev->class_path));
143 			strncpy(usbip_cdev->dev_path, dev_path,
144 				sizeof(usbip_cdev->dev_path));
145 			dbg("found: %s %s", class_path, dev_path);
146 		}
147 	}
148 
149 	return 0;
150 }
151 
152 
search_class_for_usbip_device(char * cname)153 static int search_class_for_usbip_device(char *cname)
154 {
155 	struct sysfs_class *class;
156 	struct dlist *cdev_list;
157 	struct sysfs_class_device *cdev;
158 	int ret = 0;
159 
160 	class = sysfs_open_class(cname);
161 	if (!class) {
162 		dbg("sysfs_open_class failed");
163 		return -1;
164 	}
165 
166 	dbg("class: %s", class->name);
167 
168 	cdev_list = sysfs_get_class_devices(class);
169 	if (!cdev_list)
170 		/* nothing */
171 		goto out;
172 
173 	dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) {
174 		dbg("cdev: %s", cdev->name);
175 		ret = check_usbip_device(cdev);
176 		if (ret < 0)
177 			goto out;
178 	}
179 
180 out:
181 	sysfs_close_class(class);
182 
183 	return ret;
184 }
185 
186 
refresh_class_device_list(void)187 static int refresh_class_device_list(void)
188 {
189 	int ret;
190 	struct dlist *cname_list;
191 	char *cname;
192 	char sysfs_mntpath[SYSFS_PATH_MAX];
193 	char class_path[SYSFS_PATH_MAX];
194 
195 	ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
196 	if (ret < 0) {
197 		dbg("sysfs_get_mnt_path failed");
198 		return -1;
199 	}
200 
201 	snprintf(class_path, sizeof(class_path), "%s/%s", sysfs_mntpath,
202 		 SYSFS_CLASS_NAME);
203 
204 	/* search under /sys/class */
205 	cname_list = sysfs_open_directory_list(class_path);
206 	if (!cname_list) {
207 		dbg("sysfs_open_directory failed");
208 		return -1;
209 	}
210 
211 	dlist_for_each_data(cname_list, cname, char) {
212 		ret = search_class_for_usbip_device(cname);
213 		if (ret < 0) {
214 			sysfs_close_list(cname_list);
215 			return -1;
216 		}
217 	}
218 
219 	sysfs_close_list(cname_list);
220 
221 	/* seach under /sys/block */
222 	ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);
223 	if (ret < 0)
224 		return -1;
225 
226 	return 0;
227 }
228 
229 
refresh_imported_device_list(void)230 static int refresh_imported_device_list(void)
231 {
232 	struct sysfs_attribute *attr_status;
233 
234 
235 	attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
236 	if (!attr_status) {
237 		dbg("sysfs_get_device_attr(\"status\") failed: %s",
238 		    vhci_driver->hc_device->name);
239 		return -1;
240 	}
241 
242 	dbg("name: %s  path: %s  len: %d  method: %d  value: %s",
243 	    attr_status->name, attr_status->path, attr_status->len,
244 	    attr_status->method, attr_status->value);
245 
246 	return parse_status(attr_status->value);
247 }
248 
get_nports(void)249 static int get_nports(void)
250 {
251 	char *c;
252 	int nports = 0;
253 	struct sysfs_attribute *attr_status;
254 
255 	attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
256 	if (!attr_status) {
257 		dbg("sysfs_get_device_attr(\"status\") failed: %s",
258 		    vhci_driver->hc_device->name);
259 		return -1;
260 	}
261 
262 	dbg("name: %s  path: %s  len: %d  method: %d  value: %s",
263 	    attr_status->name, attr_status->path, attr_status->len,
264 	    attr_status->method, attr_status->value);
265 
266 	/* skip a header line */
267 	c = strchr(attr_status->value, '\n') + 1;
268 
269 	while (*c != '\0') {
270 		/* go to the next line */
271 		c = strchr(c, '\n') + 1;
272 		nports += 1;
273 	}
274 
275 	return nports;
276 }
277 
get_hc_busid(char * sysfs_mntpath,char * hc_busid)278 static int get_hc_busid(char *sysfs_mntpath, char *hc_busid)
279 {
280         struct sysfs_driver *sdriver;
281         char sdriver_path[SYSFS_PATH_MAX];
282 
283 	struct sysfs_device *hc_dev;
284 	struct dlist *hc_devs;
285 
286 	int found = 0;
287 
288         snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", sysfs_mntpath,
289 		 SYSFS_BUS_NAME, USBIP_VHCI_BUS_TYPE, SYSFS_DRIVERS_NAME,
290 		 USBIP_VHCI_DRV_NAME);
291 
292         sdriver = sysfs_open_driver_path(sdriver_path);
293         if (!sdriver) {
294 		dbg("sysfs_open_driver_path failed: %s", sdriver_path);
295                 dbg("make sure " USBIP_CORE_MOD_NAME ".ko and "
296 		    USBIP_VHCI_DRV_NAME ".ko are loaded!");
297                 return -1;
298         }
299 
300 	hc_devs = sysfs_get_driver_devices(sdriver);
301 	if (!hc_devs) {
302 		dbg("sysfs_get_driver failed");
303 		goto err;
304 	}
305 
306 	/* assume only one vhci_hcd */
307 	dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) {
308 		strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE);
309 		found = 1;
310 	}
311 
312 err:
313 	sysfs_close_driver(sdriver);
314 
315 	if (found)
316 		return 0;
317 
318 	dbg("%s not found", hc_busid);
319 	return -1;
320 }
321 
322 
323 /* ---------------------------------------------------------------------- */
324 
usbip_vhci_driver_open(void)325 int usbip_vhci_driver_open(void)
326 {
327 	int ret;
328 	char hc_busid[SYSFS_BUS_ID_SIZE];
329 
330 	vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver));
331 	if (!vhci_driver) {
332 		dbg("calloc failed");
333 		return -1;
334 	}
335 
336 	ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX);
337 	if (ret < 0) {
338 		dbg("sysfs_get_mnt_path failed");
339 		goto err;
340 	}
341 
342 	ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid);
343 	if (ret < 0)
344 		goto err;
345 
346 	/* will be freed in usbip_driver_close() */
347 	vhci_driver->hc_device = sysfs_open_device(USBIP_VHCI_BUS_TYPE,
348 						   hc_busid);
349 	if (!vhci_driver->hc_device) {
350 		dbg("sysfs_open_device failed");
351 		goto err;
352 	}
353 
354 	vhci_driver->nports = get_nports();
355 
356 	dbg("available ports: %d", vhci_driver->nports);
357 
358 	vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
359 	if (!vhci_driver->cdev_list)
360 		goto err;
361 
362 	if (refresh_class_device_list())
363 		goto err;
364 
365 	if (refresh_imported_device_list())
366 		goto err;
367 
368 
369 	return 0;
370 
371 
372 err:
373 	if (vhci_driver->cdev_list)
374 		dlist_destroy(vhci_driver->cdev_list);
375 	if (vhci_driver->hc_device)
376 		sysfs_close_device(vhci_driver->hc_device);
377 	if (vhci_driver)
378 		free(vhci_driver);
379 
380 	vhci_driver = NULL;
381 	return -1;
382 }
383 
384 
usbip_vhci_driver_close()385 void usbip_vhci_driver_close()
386 {
387 	if (!vhci_driver)
388 		return;
389 
390 	if (vhci_driver->cdev_list)
391 		dlist_destroy(vhci_driver->cdev_list);
392 
393 	for (int i = 0; i < vhci_driver->nports; i++) {
394 		if (vhci_driver->idev[i].cdev_list)
395 			dlist_destroy(vhci_driver->idev[i].cdev_list);
396 	}
397 
398 	if (vhci_driver->hc_device)
399 		sysfs_close_device(vhci_driver->hc_device);
400 	free(vhci_driver);
401 
402 	vhci_driver = NULL;
403 }
404 
405 
usbip_vhci_refresh_device_list(void)406 int usbip_vhci_refresh_device_list(void)
407 {
408 	if (vhci_driver->cdev_list)
409 		dlist_destroy(vhci_driver->cdev_list);
410 
411 
412 	for (int i = 0; i < vhci_driver->nports; i++) {
413 		if (vhci_driver->idev[i].cdev_list)
414 			dlist_destroy(vhci_driver->idev[i].cdev_list);
415 	}
416 
417 	vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
418 	if (!vhci_driver->cdev_list)
419 		goto err;
420 
421 	if (refresh_class_device_list())
422 		goto err;
423 
424 	if (refresh_imported_device_list())
425 		goto err;
426 
427 	return 0;
428 err:
429 	if (vhci_driver->cdev_list)
430 		dlist_destroy(vhci_driver->cdev_list);
431 
432 	for (int i = 0; i < vhci_driver->nports; i++) {
433 		if (vhci_driver->idev[i].cdev_list)
434 			dlist_destroy(vhci_driver->idev[i].cdev_list);
435 	}
436 
437 	dbg("failed to refresh device list");
438 	return -1;
439 }
440 
441 
usbip_vhci_get_free_port(void)442 int usbip_vhci_get_free_port(void)
443 {
444 	for (int i = 0; i < vhci_driver->nports; i++) {
445 		if (vhci_driver->idev[i].status == VDEV_ST_NULL)
446 			return i;
447 	}
448 
449 	return -1;
450 }
451 
usbip_vhci_attach_device2(uint8_t port,int sockfd,uint32_t devid,uint32_t speed)452 int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
453 		uint32_t speed) {
454 	struct sysfs_attribute *attr_attach;
455 	char buff[200]; /* what size should be ? */
456 	int ret;
457 
458 	attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach");
459 	if (!attr_attach) {
460 		dbg("sysfs_get_device_attr(\"attach\") failed: %s",
461 		    vhci_driver->hc_device->name);
462 		return -1;
463 	}
464 
465 	snprintf(buff, sizeof(buff), "%u %u %u %u",
466 			port, sockfd, devid, speed);
467 	dbg("writing: %s", buff);
468 
469 	ret = sysfs_write_attribute(attr_attach, buff, strlen(buff));
470 	if (ret < 0) {
471 		dbg("sysfs_write_attribute failed");
472 		return -1;
473 	}
474 
475 	dbg("attached port: %d", port);
476 
477 	return 0;
478 }
479 
get_devid(uint8_t busnum,uint8_t devnum)480 static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
481 {
482 	return (busnum << 16) | devnum;
483 }
484 
485 /* will be removed */
usbip_vhci_attach_device(uint8_t port,int sockfd,uint8_t busnum,uint8_t devnum,uint32_t speed)486 int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
487 		uint8_t devnum, uint32_t speed)
488 {
489 	int devid = get_devid(busnum, devnum);
490 
491 	return usbip_vhci_attach_device2(port, sockfd, devid, speed);
492 }
493 
usbip_vhci_detach_device(uint8_t port)494 int usbip_vhci_detach_device(uint8_t port)
495 {
496 	struct sysfs_attribute  *attr_detach;
497 	char buff[200]; /* what size should be ? */
498 	int ret;
499 
500 	attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach");
501 	if (!attr_detach) {
502 		dbg("sysfs_get_device_attr(\"detach\") failed: %s",
503 		    vhci_driver->hc_device->name);
504 		return -1;
505 	}
506 
507 	snprintf(buff, sizeof(buff), "%u", port);
508 	dbg("writing: %s", buff);
509 
510 	ret = sysfs_write_attribute(attr_detach, buff, strlen(buff));
511 	if (ret < 0) {
512 		dbg("sysfs_write_attribute failed");
513 		return -1;
514 	}
515 
516 	dbg("detached port: %d", port);
517 
518 	return 0;
519 }
520