1 /*
2 * Copyright (C) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
3 * Author Chunyan Liu <cyliu@suse.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; version 2.1 only. with the special
8 * exception on linking described in file LICENSE.
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 Lesser General Public License for more details.
14 */
15
16 #include "libxl_osdeps.h" /* must come before any other headers */
17
18 #include "libxl_internal.h"
19 #include <inttypes.h>
20 #include <xen/io/usbif.h>
21
22 #define USBBACK_INFO_PATH "/libxl/usbback"
23
24 #define USBHUB_CLASS_CODE 9
25
usbback_is_loaded(libxl__gc * gc)26 static int usbback_is_loaded(libxl__gc *gc)
27 {
28 int r;
29 struct stat st;
30
31 r = lstat(SYSFS_USBBACK_DRIVER, &st);
32
33 if (r == 0)
34 return 1;
35 if (r < 0 && errno == ENOENT)
36 return 0;
37 LOGE(ERROR, "Accessing %s", SYSFS_USBBACK_DRIVER);
38 return ERROR_FAIL;
39 }
40
libxl__device_usbctrl_setdefault(libxl__gc * gc,uint32_t domid,libxl_device_usbctrl * usbctrl,bool hotplug)41 static int libxl__device_usbctrl_setdefault(libxl__gc *gc, uint32_t domid,
42 libxl_device_usbctrl *usbctrl,
43 bool hotplug)
44 {
45 int rc;
46 libxl_domain_type domtype = libxl__domain_type(gc, domid);
47
48 if (usbctrl->type == LIBXL_USBCTRL_TYPE_AUTO) {
49 if (domtype != LIBXL_DOMAIN_TYPE_HVM) {
50 rc = usbback_is_loaded(gc);
51 if (rc < 0)
52 goto out;
53 usbctrl->type = rc ? LIBXL_USBCTRL_TYPE_PV
54 : LIBXL_USBCTRL_TYPE_QUSB;
55 } else {
56 /* FIXME: See if we can detect PV frontend */
57 usbctrl->type = LIBXL_USBCTRL_TYPE_DEVICEMODEL;
58 }
59 }
60
61 switch (usbctrl->type) {
62 case LIBXL_USBCTRL_TYPE_PV:
63 case LIBXL_USBCTRL_TYPE_QUSB:
64 if (!usbctrl->version)
65 usbctrl->version = 2;
66 if (usbctrl->version < 1 || usbctrl->version > 2) {
67 LOG(ERROR,
68 "USB version for paravirtualized devices must be 1 or 2");
69 rc = ERROR_INVAL;
70 goto out;
71 }
72 if (!usbctrl->ports)
73 usbctrl->ports = 8;
74 if (usbctrl->ports < 1 || usbctrl->ports > USBIF_MAX_PORTNR) {
75 LOG(ERROR, "Number of ports for USB controller is limited to %u",
76 USBIF_MAX_PORTNR);
77 rc = ERROR_INVAL;
78 goto out;
79 }
80 break;
81 case LIBXL_USBCTRL_TYPE_DEVICEMODEL:
82 if (!usbctrl->version)
83 usbctrl->version = 2;
84 switch (usbctrl->version) {
85 case 1:
86 /* uhci controller in qemu has fixed number of ports. */
87 if (usbctrl->ports && usbctrl->ports != 2) {
88 LOG(ERROR,
89 "Number of ports for USB controller of version 1 is always 2");
90 rc = ERROR_INVAL;
91 goto out;
92 }
93 usbctrl->ports = 2;
94 break;
95 case 2:
96 /* ehci controller in qemu has fixed number of ports. */
97 if (usbctrl->ports && usbctrl->ports != 6) {
98 LOG(ERROR,
99 "Number of ports for USB controller of version 2 is always 6");
100 rc = ERROR_INVAL;
101 goto out;
102 }
103 usbctrl->ports = 6;
104 break;
105 case 3:
106 if (!usbctrl->ports)
107 usbctrl->ports = 8;
108 /* xhci controller in qemu supports up to 15 ports. */
109 if (usbctrl->ports > 15) {
110 LOG(ERROR,
111 "Number of ports for USB controller of version 3 is limited to 15");
112 rc = ERROR_INVAL;
113 goto out;
114 }
115 break;
116 default:
117 LOG(ERROR, "Illegal USB version");
118 rc = ERROR_INVAL;
119 goto out;
120 }
121 break;
122 default:
123 break;
124 }
125
126 rc = libxl__resolve_domid(gc, usbctrl->backend_domname,
127 &usbctrl->backend_domid);
128
129 out:
130 return rc;
131 }
132
libxl__device_from_usbctrl(libxl__gc * gc,uint32_t domid,libxl_device_usbctrl * usbctrl,libxl__device * device)133 static int libxl__device_from_usbctrl(libxl__gc *gc, uint32_t domid,
134 libxl_device_usbctrl *usbctrl,
135 libxl__device *device)
136 {
137 device->backend_devid = usbctrl->devid;
138 device->backend_domid = usbctrl->backend_domid;
139 switch (usbctrl->type) {
140 case LIBXL_USBCTRL_TYPE_PV:
141 device->backend_kind = LIBXL__DEVICE_KIND_VUSB;
142 break;
143 case LIBXL_USBCTRL_TYPE_QUSB:
144 device->backend_kind = LIBXL__DEVICE_KIND_QUSB;
145 break;
146 case LIBXL_USBCTRL_TYPE_DEVICEMODEL:
147 device->backend_kind = LIBXL__DEVICE_KIND_NONE;
148 break;
149 default:
150 assert(0); /* can't really happen. */
151 break;
152 }
153 device->devid = usbctrl->devid;
154 device->domid = domid;
155 device->kind = LIBXL__DEVICE_KIND_VUSB;
156
157 return 0;
158 }
159
vusb_be_from_xs_libxl_type(libxl__gc * gc,const char * libxl_path,libxl_usbctrl_type type)160 static const char *vusb_be_from_xs_libxl_type(libxl__gc *gc,
161 const char *libxl_path,
162 libxl_usbctrl_type type)
163 {
164 const char *be_path = NULL, *tmp;
165 int r;
166
167 if (type == LIBXL_USBCTRL_TYPE_AUTO) {
168 r = libxl__xs_read_checked(gc, XBT_NULL,
169 GCSPRINTF("%s/type", libxl_path), &tmp);
170 if (r || libxl_usbctrl_type_from_string(tmp, &type))
171 goto out;
172 }
173
174 if (type == LIBXL_USBCTRL_TYPE_DEVICEMODEL) {
175 be_path = libxl_path;
176 goto out;
177 }
178
179 r = libxl__xs_read_checked(gc, XBT_NULL,
180 GCSPRINTF("%s/backend", libxl_path),
181 &be_path);
182 if (r)
183 be_path = NULL;
184
185 out:
186 return be_path;
187 }
188
189 /* Add usbctrl information to xenstore.
190 *
191 * Adding a usb controller will add a new 'qusb' or 'vusb' device in xenstore,
192 * and add corresponding frontend, backend information to it. According to
193 * "update_json", decide whether to update json config file.
194 */
libxl__device_usbctrl_add_xenstore(libxl__gc * gc,uint32_t domid,libxl_device_usbctrl * usbctrl,bool update_json)195 static int libxl__device_usbctrl_add_xenstore(libxl__gc *gc, uint32_t domid,
196 libxl_device_usbctrl *usbctrl,
197 bool update_json)
198 {
199 libxl__device *device;
200 flexarray_t *front = NULL;
201 flexarray_t *back;
202 xs_transaction_t t = XBT_NULL;
203 int i, rc;
204 libxl_domain_config d_config;
205 libxl_device_usbctrl usbctrl_saved;
206 libxl__domain_userdata_lock *lock = NULL;
207
208 libxl_domain_config_init(&d_config);
209 libxl_device_usbctrl_init(&usbctrl_saved);
210 libxl_device_usbctrl_copy(CTX, &usbctrl_saved, usbctrl);
211
212 GCNEW(device);
213 rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
214 if (rc) goto out;
215
216 back = flexarray_make(gc, 12, 1);
217
218 if (device->backend_kind != LIBXL__DEVICE_KIND_NONE) {
219 front = flexarray_make(gc, 4, 1);
220
221 flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
222 flexarray_append_pair(back, "online", "1");
223 flexarray_append_pair(back, "state",
224 GCSPRINTF("%d", XenbusStateInitialising));
225 flexarray_append_pair(front, "backend-id",
226 GCSPRINTF("%d", usbctrl->backend_domid));
227 flexarray_append_pair(front, "state",
228 GCSPRINTF("%d", XenbusStateInitialising));
229 }
230
231 flexarray_append_pair(back, "type",
232 (char *)libxl_usbctrl_type_to_string(usbctrl->type));
233 flexarray_append_pair(back, "usb-ver", GCSPRINTF("%d", usbctrl->version));
234 flexarray_append_pair(back, "num-ports", GCSPRINTF("%d", usbctrl->ports));
235 flexarray_append_pair(back, "port", "");
236 for (i = 0; i < usbctrl->ports; i++)
237 flexarray_append_pair(back, GCSPRINTF("port/%d", i + 1), "");
238
239 if (update_json) {
240 lock = libxl__lock_domain_userdata(gc, domid);
241 if (!lock) {
242 rc = ERROR_LOCK_FAIL;
243 goto out;
244 }
245
246 rc = libxl__get_domain_configuration(gc, domid, &d_config);
247 if (rc) goto out;
248
249 device_add_domain_config(gc, &d_config, &libxl__usbctrl_devtype,
250 &usbctrl_saved);
251
252 rc = libxl__dm_check_start(gc, &d_config, domid);
253 if (rc) goto out;
254
255 if (usbctrl->type == LIBXL_USBCTRL_TYPE_QUSB) {
256 if (!libxl__query_qemu_backend(gc, domid, usbctrl->backend_domid,
257 "qusb", false)) {
258 LOGD(ERROR, domid, "backend type not supported by device model");
259 rc = ERROR_FAIL;
260 goto out;
261 }
262 }
263 }
264
265 for (;;) {
266 rc = libxl__xs_transaction_start(gc, &t);
267 if (rc) goto out;
268
269 rc = libxl__device_exists(gc, t, device);
270 if (rc < 0) goto out;
271 if (rc == 1) {
272 /* already exists in xenstore */
273 LOGD(ERROR, domid, "device already exists in xenstore");
274 rc = ERROR_DEVICE_EXISTS;
275 goto out;
276 }
277
278 if (update_json) {
279 rc = libxl__set_domain_configuration(gc, domid, &d_config);
280 if (rc) goto out;
281 }
282
283 libxl__device_generic_add(gc, t, device,
284 libxl__xs_kvs_of_flexarray(gc, back),
285 libxl__xs_kvs_of_flexarray(gc, front),
286 NULL);
287
288 rc = libxl__xs_transaction_commit(gc, &t);
289 if (!rc) break;
290 if (rc < 0) goto out;
291 }
292
293 out:
294 libxl__xs_transaction_abort(gc, &t);
295 if (lock) libxl__unlock_domain_userdata(lock);
296 libxl_device_usbctrl_dispose(&usbctrl_saved);
297 libxl_domain_config_dispose(&d_config);
298 return rc;
299 }
300
vusb_be_from_xs_libxl(libxl__gc * gc,const char * libxl_path)301 static const char *vusb_be_from_xs_libxl(libxl__gc *gc, const char *libxl_path)
302 {
303 return vusb_be_from_xs_libxl_type(gc, libxl_path, LIBXL_USBCTRL_TYPE_AUTO);
304 }
305
libxl__device_usbctrl_del_xenstore(libxl__gc * gc,uint32_t domid,libxl_device_usbctrl * usbctrl)306 static void libxl__device_usbctrl_del_xenstore(libxl__gc *gc, uint32_t domid,
307 libxl_device_usbctrl *usbctrl)
308 {
309 const char *libxl_path, *be_path;
310 xs_transaction_t t = XBT_NULL;
311 int rc;
312
313 libxl_path = GCSPRINTF("%s/device/vusb/%d",
314 libxl__xs_libxl_path(gc, domid), usbctrl->devid);
315 be_path = vusb_be_from_xs_libxl_type(gc, libxl_path, usbctrl->type);
316
317 for (;;) {
318 rc = libxl__xs_transaction_start(gc, &t);
319 if (rc) goto out;
320
321 libxl__xs_path_cleanup(gc, t, be_path);
322
323 rc = libxl__xs_transaction_commit(gc, &t);
324 if (!rc) break;
325 if (rc < 0) goto out;
326 }
327
328 return;
329
330 out:
331 libxl__xs_transaction_abort(gc, &t);
332 }
333
pvusb_get_device_type(libxl_usbctrl_type type)334 static char *pvusb_get_device_type(libxl_usbctrl_type type)
335 {
336 switch (type) {
337 case LIBXL_USBCTRL_TYPE_PV:
338 return "vusb";
339 case LIBXL_USBCTRL_TYPE_QUSB:
340 return "qusb";
341 default:
342 return NULL;
343 }
344 }
345
346 /* Send qmp commands to create a usb controller in qemu.
347 *
348 * Depending on the speed (usbctrl->version) we create:
349 * - piix3-usb-uhci (version=1), always 2 ports
350 * - usb-ehci (version=2), always 6 ports
351 * - nec-usb-xhci (version=3), up to 15 ports
352 */
libxl__device_usbctrl_add_hvm(libxl__gc * gc,uint32_t domid,libxl_device_usbctrl * usbctrl)353 static int libxl__device_usbctrl_add_hvm(libxl__gc *gc, uint32_t domid,
354 libxl_device_usbctrl *usbctrl)
355 {
356 flexarray_t *qmp_args;
357
358 qmp_args = flexarray_make(gc, 8, 1);
359
360 switch (usbctrl->version) {
361 case 1:
362 flexarray_append_pair(qmp_args, "driver", "piix3-usb-uhci");
363 break;
364 case 2:
365 flexarray_append_pair(qmp_args, "driver", "usb-ehci");
366 break;
367 case 3:
368 flexarray_append_pair(qmp_args, "driver", "nec-usb-xhci");
369 flexarray_append_pair(qmp_args, "p2", GCSPRINTF("%d", usbctrl->ports));
370 flexarray_append_pair(qmp_args, "p3", GCSPRINTF("%d", usbctrl->ports));
371 break;
372 default:
373 assert(0); /* Should not be possible. */
374 break;
375 }
376
377 flexarray_append_pair(qmp_args, "id",
378 GCSPRINTF("xenusb-%d", usbctrl->devid));
379
380 return libxl__qmp_run_command_flexarray(gc, domid, "device_add", qmp_args);
381 }
382
383 /* Send qmp commands to delete a usb controller in qemu. */
libxl__device_usbctrl_del_hvm(libxl__gc * gc,uint32_t domid,int devid)384 static int libxl__device_usbctrl_del_hvm(libxl__gc *gc, uint32_t domid,
385 int devid)
386 {
387 flexarray_t *qmp_args;
388
389 qmp_args = flexarray_make(gc, 2, 1);
390 flexarray_append_pair(qmp_args, "id", GCSPRINTF("xenusb-%d", devid));
391
392 return libxl__qmp_run_command_flexarray(gc, domid, "device_del", qmp_args);
393 }
394
395 /* Send qmp commands to create a usb device in qemu. */
libxl__device_usbdev_add_hvm(libxl__gc * gc,uint32_t domid,libxl_device_usbdev * usbdev)396 static int libxl__device_usbdev_add_hvm(libxl__gc *gc, uint32_t domid,
397 libxl_device_usbdev *usbdev)
398 {
399 flexarray_t *qmp_args;
400
401 qmp_args = flexarray_make(gc, 12, 1);
402 flexarray_append_pair(qmp_args, "id",
403 GCSPRINTF("xenusb-%d-%d",
404 usbdev->u.hostdev.hostbus,
405 usbdev->u.hostdev.hostaddr));
406 flexarray_append_pair(qmp_args, "driver", "usb-host");
407 flexarray_append_pair(qmp_args, "bus",
408 GCSPRINTF("xenusb-%d.0", usbdev->ctrl));
409 flexarray_append_pair(qmp_args, "port", GCSPRINTF("%d", usbdev->port));
410 flexarray_append_pair(qmp_args, "hostbus",
411 GCSPRINTF("%d", usbdev->u.hostdev.hostbus));
412 flexarray_append_pair(qmp_args, "hostaddr",
413 GCSPRINTF("%d", usbdev->u.hostdev.hostaddr));
414
415 return libxl__qmp_run_command_flexarray(gc, domid, "device_add", qmp_args);
416 }
417
418 /* Send qmp commands to delete a usb device in qemu. */
libxl__device_usbdev_del_hvm(libxl__gc * gc,uint32_t domid,libxl_device_usbdev * usbdev)419 static int libxl__device_usbdev_del_hvm(libxl__gc *gc, uint32_t domid,
420 libxl_device_usbdev *usbdev)
421 {
422 flexarray_t *qmp_args;
423
424 qmp_args = flexarray_make(gc, 2, 1);
425 flexarray_append_pair(qmp_args, "id",
426 GCSPRINTF("xenusb-%d-%d",
427 usbdev->u.hostdev.hostbus,
428 usbdev->u.hostdev.hostaddr));
429
430 return libxl__qmp_run_command_flexarray(gc, domid, "device_del", qmp_args);
431 }
432
433 static LIBXL_DEFINE_UPDATE_DEVID(usbctrl, "vusb")
434
435 /* AO operation to add a usb controller.
436 *
437 * Generally, it does:
438 * 1) fill in necessary usb controler information with default value
439 * 2) write usb controller frontend/backend info to xenstore, update json
440 * config file if necessary.
441 * 3) wait for device connection. PVUSB frontend and backend driver will
442 * probe xenstore paths and build connection between frontend and backend.
443 *
444 * Before calling this function, aodev should be properly filled:
445 * aodev->ao, aodev->callback, aodev->update_json, ...
446 */
libxl__device_usbctrl_add(libxl__egc * egc,uint32_t domid,libxl_device_usbctrl * usbctrl,libxl__ao_device * aodev)447 static void libxl__device_usbctrl_add(libxl__egc *egc, uint32_t domid,
448 libxl_device_usbctrl *usbctrl,
449 libxl__ao_device *aodev)
450 {
451 STATE_AO_GC(aodev->ao);
452 libxl__device *device;
453 int rc;
454
455 rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl,
456 aodev->update_json);
457 if (rc < 0) goto out;
458
459 rc = libxl__device_usbctrl_update_devid(gc, domid, usbctrl);
460 if (rc) goto out;
461
462 rc = libxl__device_usbctrl_add_xenstore(gc, domid, usbctrl,
463 aodev->update_json);
464 if (rc) goto out;
465
466 GCNEW(device);
467 rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
468 if (rc) goto outrm;
469
470 if (device->backend_kind == LIBXL__DEVICE_KIND_NONE) {
471 rc = libxl__device_usbctrl_add_hvm(gc, domid, usbctrl);
472 if (rc) goto outrm;
473 goto out;
474 }
475
476 aodev->dev = device;
477 aodev->action = LIBXL__DEVICE_ACTION_ADD;
478 libxl__wait_device_connection(egc, aodev);
479 return;
480
481 outrm:
482 libxl__device_usbctrl_del_xenstore(gc, domid, usbctrl);
483 out:
484 aodev->rc = rc;
485 aodev->callback(egc, aodev);
486 return;
487 }
488
489 LIBXL_DEFINE_DEVICE_ADD(usbctrl)
490 static LIBXL_DEFINE_DEVICES_ADD(usbctrl)
491 LIBXL_DEFINE_DEVICE_REMOVE_CUSTOM(usbctrl)
492
493 static int libxl__device_usbdev_list_for_usbctrl(libxl__gc *gc, uint32_t domid,
494 libxl_devid usbctrl,
495 libxl_device_usbdev **usbdevs,
496 int *num);
497
498 static int libxl__device_usbdev_remove(libxl__gc *gc, uint32_t domid,
499 libxl_device_usbdev *usbdev);
500
501 /* AO function to remove a usb controller.
502 *
503 * Generally, it does:
504 * 1) check if the usb controller exists or not
505 * 2) remove all usb devices under controller
506 * 3) remove usb controller information from xenstore
507 *
508 * Before calling this function, aodev should be properly filled:
509 * aodev->ao, aodev->dev, aodev->callback, ...
510 */
libxl__initiate_device_usbctrl_remove(libxl__egc * egc,libxl__ao_device * aodev)511 void libxl__initiate_device_usbctrl_remove(libxl__egc *egc,
512 libxl__ao_device *aodev)
513 {
514 STATE_AO_GC(aodev->ao);
515 libxl_device_usbdev *usbdevs = NULL;
516 int num_usbdev = 0;
517 int i, rc;
518 uint32_t domid = ao->domid;
519 int usbctrl_devid = aodev->dev->devid;
520 libxl_device_usbctrl usbctrl;
521 libxl_usbctrlinfo usbctrlinfo;
522
523 libxl_device_usbctrl_init(&usbctrl);
524 libxl_usbctrlinfo_init(&usbctrlinfo);
525 usbctrl.devid = usbctrl_devid;
526
527 rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
528 if (rc) goto out;
529
530 /* Remove usb devices first */
531 rc = libxl__device_usbdev_list_for_usbctrl(gc, domid, usbctrl_devid,
532 &usbdevs, &num_usbdev);
533 if (rc) goto out;
534
535 for (i = 0; i < num_usbdev; i++) {
536 rc = libxl__device_usbdev_remove(gc, domid, &usbdevs[i]);
537 if (rc) {
538 LOGD(ERROR, domid, "libxl__device_usbdev_remove failed: controller %d, "
539 "port %d", usbdevs[i].ctrl, usbdevs[i].port);
540 goto out;
541 }
542 }
543
544 if (usbctrlinfo.type == LIBXL_USBCTRL_TYPE_DEVICEMODEL) {
545 rc = libxl__device_usbctrl_del_hvm(gc, domid, usbctrl_devid);
546 if (!rc)
547 libxl__device_usbctrl_del_xenstore(gc, domid, &usbctrl);
548 goto out;
549 }
550
551 libxl_device_usbctrl_dispose(&usbctrl);
552 libxl_usbctrlinfo_dispose(&usbctrlinfo);
553
554 /* Remove usbctrl */
555 libxl__initiate_device_generic_remove(egc, aodev);
556 return;
557
558 out:
559 libxl_device_usbctrl_dispose(&usbctrl);
560 libxl_usbctrlinfo_dispose(&usbctrlinfo);
561 aodev->rc = rc;
562 aodev->callback(egc, aodev);
563 return;
564 }
565
566 libxl_device_usbctrl *
libxl_device_usbctrl_list(libxl_ctx * ctx,uint32_t domid,int * num)567 libxl_device_usbctrl_list(libxl_ctx *ctx, uint32_t domid, int *num)
568 {
569 GC_INIT(ctx);
570 libxl_device_usbctrl *usbctrls = NULL;
571 char *libxl_vusbs_path = NULL;
572 char **entry = NULL;
573 unsigned int nentries = 0;
574
575 *num = 0;
576
577 libxl_vusbs_path = GCSPRINTF("%s/device/vusb",
578 libxl__xs_libxl_path(gc, domid));
579 entry = libxl__xs_directory(gc, XBT_NULL, libxl_vusbs_path, &nentries);
580
581 if (entry && nentries) {
582 usbctrls = libxl__zalloc(NOGC, sizeof(*usbctrls) * nentries);
583 libxl_device_usbctrl *usbctrl;
584 libxl_device_usbctrl *end = usbctrls + nentries;
585 for (usbctrl = usbctrls;
586 usbctrl < end;
587 usbctrl++, entry++, (*num)++) {
588 const char *tmp, *be_path, *libxl_path;
589 int ret;
590
591 libxl_device_usbctrl_init(usbctrl);
592 usbctrl->devid = atoi(*entry);
593
594 #define READ_SUBPATH(path, subpath) ({ \
595 ret = libxl__xs_read_checked(gc, XBT_NULL, \
596 GCSPRINTF("%s/" subpath, path), \
597 &tmp); \
598 if (ret) goto out; \
599 (char *)tmp; \
600 })
601
602 #define READ_SUBPATH_INT(path, subpath) ({ \
603 ret = libxl__xs_read_checked(gc, XBT_NULL, \
604 GCSPRINTF("%s/" subpath, path), \
605 &tmp); \
606 if (ret) goto out; \
607 tmp ? atoi(tmp) : -1; \
608 })
609
610 libxl_path = GCSPRINTF("%s/%s", libxl_vusbs_path, *entry);
611 libxl_usbctrl_type_from_string(READ_SUBPATH(libxl_path, "type"),
612 &usbctrl->type);
613 if (usbctrl->type == LIBXL_USBCTRL_TYPE_DEVICEMODEL) {
614 be_path = libxl_path;
615 ret = libxl__get_domid(gc, &usbctrl->backend_domid);
616 } else {
617 be_path = READ_SUBPATH(libxl_path, "backend");
618 if (!be_path) goto out;
619 ret = libxl__backendpath_parse_domid(gc, be_path,
620 &usbctrl->backend_domid);
621 }
622 if (ret) goto out;
623 usbctrl->version = READ_SUBPATH_INT(be_path, "usb-ver");
624 usbctrl->ports = READ_SUBPATH_INT(be_path, "num-ports");
625
626 #undef READ_SUBPATH
627 #undef READ_SUBPATH_INT
628 }
629 }
630
631 GC_FREE;
632 return usbctrls;
633
634 out:
635 LOGD(ERROR, domid, "Unable to list USB Controllers");
636 libxl_device_usbctrl_list_free(usbctrls, *num);
637 GC_FREE;
638 *num = 0;
639 return NULL;
640 }
641
libxl_device_usbctrl_getinfo(libxl_ctx * ctx,uint32_t domid,libxl_device_usbctrl * usbctrl,libxl_usbctrlinfo * usbctrlinfo)642 int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,
643 libxl_device_usbctrl *usbctrl,
644 libxl_usbctrlinfo *usbctrlinfo)
645 {
646 GC_INIT(ctx);
647 const char *dompath, *fe_path, *be_path, *tmp;
648 const char *libxl_dom_path, *libxl_path;
649 int rc;
650
651 usbctrlinfo->devid = usbctrl->devid;
652
653 #define READ_SUBPATH(path, subpath) ({ \
654 rc = libxl__xs_read_mandatory(gc, XBT_NULL, \
655 GCSPRINTF("%s/" subpath, path), \
656 &tmp); \
657 if (rc) goto out; \
658 (char *)tmp; \
659 })
660
661 #define READ_SUBPATH_INT(path, subpath) ({ \
662 rc = libxl__xs_read_checked(gc, XBT_NULL, \
663 GCSPRINTF("%s/" subpath, path), \
664 &tmp); \
665 if (rc) goto out; \
666 tmp ? atoi(tmp) : -1; \
667 })
668
669 libxl_dom_path = libxl__xs_libxl_path(gc, domid);
670 libxl_path = GCSPRINTF("%s/device/vusb/%d", libxl_dom_path, usbctrl->devid);
671 libxl_usbctrl_type_from_string(READ_SUBPATH(libxl_path, "type"),
672 &usbctrlinfo->type);
673
674 if (usbctrlinfo->type != LIBXL_USBCTRL_TYPE_DEVICEMODEL) {
675 dompath = libxl__xs_get_dompath(gc, domid);
676 fe_path = GCSPRINTF("%s/device/vusb/%d", dompath, usbctrl->devid);
677 be_path = READ_SUBPATH(libxl_path, "backend");
678 usbctrlinfo->backend = libxl__strdup(NOGC, be_path);
679 rc = libxl__backendpath_parse_domid(gc, be_path,
680 &usbctrl->backend_domid);
681 if (rc) goto out;
682 usbctrlinfo->state = READ_SUBPATH_INT(fe_path, "state");
683 usbctrlinfo->evtch = READ_SUBPATH_INT(fe_path, "event-channel");
684 usbctrlinfo->ref_urb = READ_SUBPATH_INT(fe_path, "urb-ring-ref");
685 usbctrlinfo->ref_conn = READ_SUBPATH_INT(fe_path, "urb-ring-ref");
686 usbctrlinfo->frontend = libxl__strdup(NOGC, fe_path);
687 usbctrlinfo->frontend_id = domid;
688 usbctrlinfo->ports = READ_SUBPATH_INT(be_path, "num-ports");
689 usbctrlinfo->version = READ_SUBPATH_INT(be_path, "usb-ver");
690 } else {
691 usbctrlinfo->ports = READ_SUBPATH_INT(libxl_path, "num-ports");
692 usbctrlinfo->version = READ_SUBPATH_INT(libxl_path, "usb-ver");
693 rc = libxl__get_domid(gc, &usbctrl->backend_domid);
694 if (rc) goto out;
695 }
696
697 #undef READ_SUBPATH
698 #undef READ_SUBPATH_INT
699
700 rc = 0;
701
702 out:
703 GC_FREE;
704 return rc;
705 }
706
libxl_devid_to_device_usbctrl(libxl_ctx * ctx,uint32_t domid,int devid,libxl_device_usbctrl * usbctrl)707 int libxl_devid_to_device_usbctrl(libxl_ctx *ctx,
708 uint32_t domid,
709 int devid,
710 libxl_device_usbctrl *usbctrl)
711 {
712 libxl_device_usbctrl *usbctrls;
713 int nb = 0;
714 int i, rc;
715
716 usbctrls = libxl_device_usbctrl_list(ctx, domid, &nb);
717 if (!usbctrls) return ERROR_FAIL;
718
719 rc = ERROR_FAIL;
720 for (i = 0; i < nb; i++) {
721 if (devid == usbctrls[i].devid) {
722 libxl_device_usbctrl_copy(ctx, usbctrl, &usbctrls[i]);
723 rc = 0;
724 break;
725 }
726 }
727
728 libxl_device_usbctrl_list_free(usbctrls, nb);
729 return rc;
730 }
731
usbdev_busaddr_to_busid(libxl__gc * gc,int bus,int addr)732 static char *usbdev_busaddr_to_busid(libxl__gc *gc, int bus, int addr)
733 {
734 DIR *dir;
735 char *busid = NULL;
736 struct dirent *de;
737
738 /* invalid hostbus or hostaddr */
739 if (bus < 1 || addr < 1)
740 return NULL;
741
742 dir = opendir(SYSFS_USB_DEV);
743 if (!dir) {
744 LOGE(ERROR, "opendir failed: '%s'", SYSFS_USB_DEV);
745 return NULL;
746 }
747
748 for (;;) {
749 char *filename;
750 void *buf;
751 int busnum = -1;
752 int devnum = -1;
753
754 errno = 0;
755 de = readdir(dir);
756 if (!de && errno) {
757 LOGE(ERROR, "failed to readdir %s", SYSFS_USB_DEV);
758 break;
759 }
760 if (!de)
761 break;
762
763 if (!strcmp(de->d_name, ".") ||
764 !strcmp(de->d_name, ".."))
765 continue;
766
767 filename = GCSPRINTF(SYSFS_USB_DEV "/%s/devnum", de->d_name);
768 if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
769 devnum = atoi(buf);
770
771 filename = GCSPRINTF(SYSFS_USB_DEV "/%s/busnum", de->d_name);
772 if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
773 busnum = atoi(buf);
774
775 if (bus == busnum && addr == devnum) {
776 busid = libxl__strdup(gc, de->d_name);
777 break;
778 }
779 }
780
781 closedir(dir);
782 return busid;
783 }
784
usbdev_busaddr_from_busid(libxl__gc * gc,const char * busid,uint8_t * bus,uint8_t * addr)785 static int usbdev_busaddr_from_busid(libxl__gc *gc, const char *busid,
786 uint8_t *bus, uint8_t *addr)
787 {
788 char *filename;
789 void *buf;
790
791 filename = GCSPRINTF(SYSFS_USB_DEV "/%s/busnum", busid);
792 if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
793 *bus = atoi(buf);
794 else
795 return ERROR_FAIL;
796
797 filename = GCSPRINTF(SYSFS_USB_DEV "/%s/devnum", busid);
798 if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
799 *addr = atoi(buf);
800 else
801 return ERROR_FAIL;
802
803 return 0;
804 }
805
get_assigned_devices(libxl__gc * gc,libxl_device_usbdev ** list,int * num)806 static int get_assigned_devices(libxl__gc *gc,
807 libxl_device_usbdev **list, int *num)
808 {
809 char **domlist;
810 unsigned int ndom = 0;
811 int i, j, k;
812 int rc;
813
814 *list = NULL;
815 *num = 0;
816
817 domlist = libxl__xs_directory(gc, XBT_NULL, "/local/domain", &ndom);
818 for (i = 0; i < ndom; i++) {
819 char *libxl_vusbs_path;
820 char **usbctrls;
821 unsigned int nc = 0;
822 uint32_t domid = atoi(domlist[i]);
823
824 libxl_vusbs_path = GCSPRINTF("%s/device/vusb",
825 libxl__xs_libxl_path(gc, domid));
826 usbctrls = libxl__xs_directory(gc, XBT_NULL,
827 libxl_vusbs_path, &nc);
828
829 for (j = 0; j < nc; j++) {
830 libxl_device_usbdev *tmp = NULL;
831 int nd = 0;
832
833 rc = libxl__device_usbdev_list_for_usbctrl(gc, domid,
834 atoi(usbctrls[j]),
835 &tmp, &nd);
836 if (rc) goto out;
837
838 if (!nd) continue;
839
840 GCREALLOC_ARRAY(*list, *num + nd);
841 for (k = 0; k < nd; k++) {
842 libxl_device_usbdev_copy(CTX, *list + *num, tmp + k);
843 (*num)++;
844 }
845 }
846 }
847
848 return 0;
849
850 out:
851 LOG(ERROR, "fail to get assigned devices");
852 return rc;
853 }
854
is_usbdev_in_array(libxl_device_usbdev * usbdevs,int num,libxl_device_usbdev * usbdev)855 static bool is_usbdev_in_array(libxl_device_usbdev *usbdevs, int num,
856 libxl_device_usbdev *usbdev)
857 {
858 int i;
859
860 for (i = 0; i < num; i++) {
861 if (usbdevs[i].u.hostdev.hostbus == usbdev->u.hostdev.hostbus &&
862 usbdevs[i].u.hostdev.hostaddr == usbdev->u.hostdev.hostaddr)
863 return true;
864 }
865
866 return false;
867 }
868
869 /* check if USB device type is assignable */
is_usbdev_assignable(libxl__gc * gc,libxl_device_usbdev * usbdev)870 static bool is_usbdev_assignable(libxl__gc *gc, libxl_device_usbdev *usbdev)
871 {
872 int classcode;
873 char *filename;
874 void *buf = NULL;
875 char *busid = NULL;
876
877 busid = usbdev_busaddr_to_busid(gc, usbdev->u.hostdev.hostbus,
878 usbdev->u.hostdev.hostaddr);
879 if (!busid) return false;
880
881 filename = GCSPRINTF(SYSFS_USB_DEV "/%s/bDeviceClass", busid);
882 if (libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
883 return false;
884
885 classcode = atoi(buf);
886 return classcode != USBHUB_CLASS_CODE;
887 }
888
889 /* get usb devices under certain usb controller */
890 static int
libxl__device_usbdev_list_for_usbctrl(libxl__gc * gc,uint32_t domid,libxl_devid usbctrl,libxl_device_usbdev ** usbdevs,int * num)891 libxl__device_usbdev_list_for_usbctrl(libxl__gc *gc,
892 uint32_t domid,
893 libxl_devid usbctrl,
894 libxl_device_usbdev **usbdevs,
895 int *num)
896 {
897 const char *libxl_path, *be_path, *num_devs;
898 int n, i, rc;
899
900 *usbdevs = NULL;
901 *num = 0;
902
903 libxl_path = GCSPRINTF("%s/device/vusb/%d",
904 libxl__xs_libxl_path(gc, domid), usbctrl);
905
906 be_path = vusb_be_from_xs_libxl(gc, libxl_path);
907 if (!be_path) {
908 rc = ERROR_FAIL;
909 goto out;
910 }
911
912 rc = libxl__xs_read_checked(gc, XBT_NULL,
913 GCSPRINTF("%s/num-ports", be_path),
914 &num_devs);
915 if (rc) goto out;
916
917 n = num_devs ? atoi(num_devs) : 0;
918
919 for (i = 0; i < n; i++) {
920 const char *busid;
921 libxl_device_usbdev *usbdev;
922
923 rc = libxl__xs_read_checked(gc, XBT_NULL,
924 GCSPRINTF("%s/port/%d", be_path, i + 1),
925 &busid);
926 if (rc) goto out;
927
928 if (busid && strcmp(busid, "")) {
929 GCREALLOC_ARRAY(*usbdevs, *num + 1);
930 usbdev = *usbdevs + *num;
931 (*num)++;
932 libxl_device_usbdev_init(usbdev);
933 usbdev->ctrl = usbctrl;
934 usbdev->port = i + 1;
935 usbdev->type = LIBXL_USBDEV_TYPE_HOSTDEV;
936 rc = usbdev_busaddr_from_busid(gc, busid,
937 &usbdev->u.hostdev.hostbus,
938 &usbdev->u.hostdev.hostaddr);
939 if (rc) goto out;
940 }
941 }
942
943 rc = 0;
944
945 out:
946 return rc;
947 }
948
949 /* get all usb devices of the domain */
950 libxl_device_usbdev *
libxl_device_usbdev_list(libxl_ctx * ctx,uint32_t domid,int * num)951 libxl_device_usbdev_list(libxl_ctx *ctx, uint32_t domid, int *num)
952 {
953 GC_INIT(ctx);
954 libxl_device_usbdev *usbdevs = NULL;
955 const char *libxl_vusbs_path;
956 char **usbctrls;
957 unsigned int nc = 0;
958 int i, j;
959
960 *num = 0;
961
962 libxl_vusbs_path = GCSPRINTF("%s/device/vusb",
963 libxl__xs_libxl_path(gc, domid));
964 usbctrls = libxl__xs_directory(gc, XBT_NULL, libxl_vusbs_path, &nc);
965
966 for (i = 0; i < nc; i++) {
967 int rc, nd = 0;
968 libxl_device_usbdev *tmp = NULL;
969
970 rc = libxl__device_usbdev_list_for_usbctrl(gc, domid,
971 atoi(usbctrls[i]),
972 &tmp, &nd);
973 if (rc || !nd) continue;
974
975 usbdevs = libxl__realloc(NOGC, usbdevs,
976 sizeof(*usbdevs) * (*num + nd));
977 for (j = 0; j < nd; j++) {
978 libxl_device_usbdev_copy(ctx, usbdevs + *num, tmp + j);
979 (*num)++;
980 }
981 }
982
983 GC_FREE;
984 return usbdevs;
985 }
986
vusb_get_port_path(libxl__gc * gc,uint32_t domid,libxl_usbctrl_type type,int ctrl,int port)987 static char *vusb_get_port_path(libxl__gc *gc, uint32_t domid,
988 libxl_usbctrl_type type, int ctrl, int port)
989 {
990 char *path;
991
992 if (type == LIBXL_USBCTRL_TYPE_DEVICEMODEL)
993 path = GCSPRINTF("%s/device/vusb", libxl__xs_libxl_path(gc, domid));
994 else
995 path = GCSPRINTF("%s/backend/%s/%d",
996 libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID),
997 pvusb_get_device_type(type), domid);
998
999 return GCSPRINTF("%s/%d/port/%d", path, ctrl, port);
1000 }
1001
1002 /* find first unused controller:port and give that to usb device */
1003 static int
libxl__device_usbdev_set_default_usbctrl(libxl__gc * gc,uint32_t domid,libxl_device_usbdev * usbdev)1004 libxl__device_usbdev_set_default_usbctrl(libxl__gc *gc, uint32_t domid,
1005 libxl_device_usbdev *usbdev)
1006 {
1007 libxl_device_usbctrl *usbctrls = NULL;
1008 int numctrl = 0;
1009 int i, j, rc;
1010
1011 usbctrls = libxl_device_usbctrl_list(CTX, domid, &numctrl);
1012 if (!numctrl || !usbctrls) {
1013 rc = ERROR_FAIL;
1014 goto out;
1015 }
1016
1017 for (i = 0; i < numctrl; i++) {
1018 for (j = 0; j < usbctrls[i].ports; j++) {
1019 const char *path, *tmp;
1020
1021 path = vusb_get_port_path(gc, domid, usbctrls[i].type,
1022 usbctrls[i].devid, j + 1);
1023 rc = libxl__xs_read_checked(gc, XBT_NULL, path, &tmp);
1024 if (rc) goto out;
1025
1026 if (tmp && !strcmp(tmp, "")) {
1027 usbdev->ctrl = usbctrls[i].devid;
1028 usbdev->port = j + 1;
1029 rc = 0;
1030 goto out;
1031 }
1032 }
1033 }
1034
1035 /* no available controller:port */
1036 rc = ERROR_FAIL;
1037
1038 out:
1039 libxl_device_usbctrl_list_free(usbctrls, numctrl);
1040 return rc;
1041 }
1042
1043 /* Fill in usb information with default value.
1044 *
1045 * Generally, it does:
1046 * 1) if "controller" is not specified:
1047 * - if "port" is not specified, try to find an available controller:port,
1048 * if found, use that; otherwise, create a new controller, use this
1049 * controller and its first port
1050 * - if "port" is specified, report error.
1051 * 2) if "controller" is specified, but port is not specified:
1052 * try to find an available port under this controller, if found, use
1053 * that, otherwise, report error.
1054 * 3) if both "controller" and "port" are specified:
1055 * check the controller:port is available, if not, report error.
1056 */
libxl__device_usbdev_setdefault(libxl__gc * gc,uint32_t domid,libxl_device_usbdev * usbdev,bool update_json)1057 static int libxl__device_usbdev_setdefault(libxl__gc *gc,
1058 uint32_t domid,
1059 libxl_device_usbdev *usbdev,
1060 bool update_json)
1061 {
1062 int rc;
1063
1064 if (!usbdev->type)
1065 usbdev->type = LIBXL_USBDEV_TYPE_HOSTDEV;
1066
1067 if (usbdev->ctrl == -1) {
1068 if (usbdev->port) {
1069 LOGD(ERROR, domid,
1070 "USB controller must be specified if you specify port");
1071 return ERROR_INVAL;
1072 }
1073
1074 rc = libxl__device_usbdev_set_default_usbctrl(gc, domid, usbdev);
1075 /* If no existing controller to host this usb device, add a new one */
1076 if (rc) {
1077 libxl_device_usbctrl *usbctrl;
1078
1079 GCNEW(usbctrl);
1080 libxl_device_usbctrl_init(usbctrl);
1081 rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl,
1082 update_json);
1083 if (rc < 0) goto out;
1084
1085 rc = libxl__device_usbctrl_update_devid(gc, domid, usbctrl);
1086 if (rc) goto out;
1087
1088 rc = libxl__device_usbctrl_add_xenstore(gc, domid, usbctrl,
1089 update_json);
1090 if (rc) goto out;
1091
1092 usbdev->ctrl = usbctrl->devid;
1093 usbdev->port = 1;
1094 }
1095 } else {
1096 /* A controller was specified; look it up */
1097 const char *libxl_path, *be_path, *tmp;
1098
1099 libxl_path = GCSPRINTF("%s/device/vusb/%d",
1100 libxl__xs_libxl_path(gc, domid),
1101 usbdev->ctrl);
1102
1103 be_path = vusb_be_from_xs_libxl(gc, libxl_path);
1104 if (!be_path) {
1105 rc = ERROR_FAIL;
1106 goto out;
1107 }
1108
1109 if (usbdev->port) {
1110 /* A specific port was requested; see if it's available */
1111 rc = libxl__xs_read_checked(gc, XBT_NULL,
1112 GCSPRINTF("%s/port/%d",
1113 be_path, usbdev->port),
1114 &tmp);
1115 if (rc) goto out;
1116
1117 if (tmp && strcmp(tmp, "")) {
1118 LOGD(ERROR, domid, "The controller port isn't available");
1119 rc = ERROR_FAIL;
1120 goto out;
1121 }
1122 } else {
1123 /* No port was requested. Choose free port. */
1124 int i, ports;
1125
1126 rc = libxl__xs_read_checked(gc, XBT_NULL,
1127 GCSPRINTF("%s/num-ports", be_path), &tmp);
1128 if (rc) goto out;
1129
1130 ports = tmp ? atoi(tmp) : 0;
1131
1132 for (i = 0; i < ports; i++) {
1133 rc = libxl__xs_read_checked(gc, XBT_NULL,
1134 GCSPRINTF("%s/port/%d", be_path, i + 1),
1135 &tmp);
1136 if (rc) goto out;
1137
1138 if (tmp && !strcmp(tmp, "")) {
1139 usbdev->port = i + 1;
1140 break;
1141 }
1142 }
1143
1144 if (!usbdev->port) {
1145 LOGD(ERROR, domid, "No available port under specified controller");
1146 rc = ERROR_FAIL;
1147 goto out;
1148 }
1149 }
1150 }
1151
1152 rc = 0;
1153
1154 out:
1155 return rc;
1156 }
1157
1158 /* Add usb information to xenstore
1159 *
1160 * Adding a usb device won't create new 'qusb'/'vusb' device, but only write
1161 * the device busid to the controller:port in xenstore.
1162 */
libxl__device_usbdev_add_xenstore(libxl__gc * gc,uint32_t domid,libxl_device_usbdev * usbdev,libxl_usbctrl_type type,bool update_json)1163 static int libxl__device_usbdev_add_xenstore(libxl__gc *gc, uint32_t domid,
1164 libxl_device_usbdev *usbdev,
1165 libxl_usbctrl_type type,
1166 bool update_json)
1167 {
1168 char *be_path, *busid;
1169 int rc;
1170 xs_transaction_t t = XBT_NULL;
1171 libxl_domain_config d_config;
1172 libxl_device_usbdev usbdev_saved;
1173 libxl__domain_userdata_lock *lock = NULL;
1174
1175 libxl_domain_config_init(&d_config);
1176 libxl_device_usbdev_init(&usbdev_saved);
1177 libxl_device_usbdev_copy(CTX, &usbdev_saved, usbdev);
1178
1179 busid = usbdev_busaddr_to_busid(gc, usbdev->u.hostdev.hostbus,
1180 usbdev->u.hostdev.hostaddr);
1181 if (!busid) {
1182 LOGD(DEBUG, domid, "Fail to get busid of usb device");
1183 rc = ERROR_FAIL;
1184 goto out;
1185 }
1186
1187 if (update_json) {
1188 lock = libxl__lock_domain_userdata(gc, domid);
1189 if (!lock) {
1190 rc = ERROR_LOCK_FAIL;
1191 goto out;
1192 }
1193
1194 rc = libxl__get_domain_configuration(gc, domid, &d_config);
1195 if (rc) goto out;
1196
1197 device_add_domain_config(gc, &d_config, &libxl__usbdev_devtype,
1198 &usbdev_saved);
1199
1200 rc = libxl__dm_check_start(gc, &d_config, domid);
1201 if (rc) goto out;
1202 }
1203
1204 for (;;) {
1205 rc = libxl__xs_transaction_start(gc, &t);
1206 if (rc) goto out;
1207
1208 if (update_json) {
1209 rc = libxl__set_domain_configuration(gc, domid, &d_config);
1210 if (rc) goto out;
1211 }
1212
1213 be_path = vusb_get_port_path(gc, domid, type, usbdev->ctrl,
1214 usbdev->port);
1215
1216 LOGD(DEBUG, domid, "Adding usb device %s to xenstore: controller %d, port %d",
1217 busid, usbdev->ctrl, usbdev->port);
1218
1219 rc = libxl__xs_write_checked(gc, t, be_path, busid);
1220 if (rc) goto out;
1221
1222 rc = libxl__xs_transaction_commit(gc, &t);
1223 if (!rc) break;
1224 if (rc < 0) goto out;
1225 }
1226
1227 rc = 0;
1228
1229 out:
1230 if (lock) libxl__unlock_domain_userdata(lock);
1231 libxl_device_usbdev_dispose(&usbdev_saved);
1232 libxl_domain_config_dispose(&d_config);
1233 return rc;
1234 }
1235
libxl__device_usbdev_remove_xenstore(libxl__gc * gc,uint32_t domid,libxl_device_usbdev * usbdev,libxl_usbctrl_type type)1236 static int libxl__device_usbdev_remove_xenstore(libxl__gc *gc, uint32_t domid,
1237 libxl_device_usbdev *usbdev,
1238 libxl_usbctrl_type type)
1239 {
1240 char *be_path;
1241
1242 be_path = vusb_get_port_path(gc, domid, type, usbdev->ctrl, usbdev->port);
1243
1244 LOGD(DEBUG, domid, "Removing usb device from xenstore: controller %d, port %d",
1245 usbdev->ctrl, usbdev->port);
1246
1247 return libxl__xs_write_checked(gc, XBT_NULL, be_path, "");
1248 }
1249
usbdev_busid_from_ctrlport(libxl__gc * gc,uint32_t domid,libxl_device_usbdev * usbdev,libxl_usbctrl_type type)1250 static char *usbdev_busid_from_ctrlport(libxl__gc *gc, uint32_t domid,
1251 libxl_device_usbdev *usbdev,
1252 libxl_usbctrl_type type)
1253 {
1254 return libxl__xs_read(gc, XBT_NULL,
1255 vusb_get_port_path(gc, domid, type, usbdev->ctrl,
1256 usbdev->port));
1257 }
1258
1259 /* get original driver path of usb interface, stored in @drvpath */
usbintf_get_drvpath(libxl__gc * gc,const char * intf,char ** drvpath)1260 static int usbintf_get_drvpath(libxl__gc *gc, const char *intf, char **drvpath)
1261 {
1262 char *spath, *dp = NULL;
1263
1264 spath = GCSPRINTF(SYSFS_USB_DEV "/%s/driver", intf);
1265
1266 /* Find the canonical path to the driver. */
1267 dp = libxl__zalloc(gc, PATH_MAX);
1268 dp = realpath(spath, dp);
1269 if (!dp && errno != ENOENT) {
1270 LOGE(ERROR, "get realpath failed: '%s'", spath);
1271 return ERROR_FAIL;
1272 }
1273
1274 *drvpath = dp;
1275
1276 return 0;
1277 }
1278
unbind_usbintf(libxl__gc * gc,const char * intf)1279 static int unbind_usbintf(libxl__gc *gc, const char *intf)
1280 {
1281 char *path;
1282 int fd = -1;
1283 int rc;
1284
1285 path = GCSPRINTF(SYSFS_USB_DEV "/%s/driver/unbind", intf);
1286
1287 fd = open(path, O_WRONLY);
1288 if (fd < 0) {
1289 LOGE(ERROR, "open file failed: '%s'", path);
1290 rc = ERROR_FAIL;
1291 goto out;
1292 }
1293
1294 if (libxl_write_exactly(CTX, fd, intf, strlen(intf), path, intf)) {
1295 rc = ERROR_FAIL;
1296 goto out;
1297 }
1298
1299 rc = 0;
1300
1301 out:
1302 if (fd >= 0) close(fd);
1303 return rc;
1304 }
1305
bind_usbintf(libxl__gc * gc,const char * intf,const char * drvpath)1306 static int bind_usbintf(libxl__gc *gc, const char *intf, const char *drvpath)
1307 {
1308 char *bind_path, *intf_path;
1309 struct stat st;
1310 int fd = -1;
1311 int rc, r;
1312
1313 intf_path = GCSPRINTF("%s/%s", drvpath, intf);
1314
1315 /* check through lstat, if intf already exists under drvpath,
1316 * it's already bound, return directly; if it doesn't exist,
1317 * continue to do bind work; otherwise, return error.
1318 */
1319 r = lstat(intf_path, &st);
1320 if (r == 0)
1321 return 0;
1322 if (r < 0 && errno != ENOENT)
1323 return ERROR_FAIL;
1324
1325 bind_path = GCSPRINTF("%s/bind", drvpath);
1326
1327 fd = open(bind_path, O_WRONLY);
1328 if (fd < 0) {
1329 LOGE(ERROR, "open file failed: '%s'", bind_path);
1330 rc = ERROR_FAIL;
1331 goto out;
1332 }
1333
1334 if (libxl_write_exactly(CTX, fd, intf, strlen(intf), bind_path, intf)) {
1335 rc = ERROR_FAIL;
1336 goto out;
1337 }
1338
1339 rc = 0;
1340
1341 out:
1342 if (fd >= 0) close(fd);
1343 return rc;
1344 }
1345
1346 /* Is usb interface bound to usbback? */
usbintf_is_assigned(libxl__gc * gc,char * intf)1347 static int usbintf_is_assigned(libxl__gc *gc, char *intf)
1348 {
1349 char *spath;
1350 int r;
1351 struct stat st;
1352
1353 spath = GCSPRINTF(SYSFS_USBBACK_DRIVER "/%s", intf);
1354 r = lstat(spath, &st);
1355
1356 if (r == 0)
1357 return 1;
1358 if (r < 0 && errno == ENOENT)
1359 return 0;
1360 LOGE(ERROR, "Accessing %s", spath);
1361 return -1;
1362 }
1363
usbdev_get_all_interfaces(libxl__gc * gc,const char * busid,char *** intfs,int * num)1364 static int usbdev_get_all_interfaces(libxl__gc *gc, const char *busid,
1365 char ***intfs, int *num)
1366 {
1367 DIR *dir;
1368 char *buf;
1369 struct dirent *de;
1370 int rc;
1371
1372 *intfs = NULL;
1373 *num = 0;
1374
1375 buf = GCSPRINTF("%s:", busid);
1376
1377 dir = opendir(SYSFS_USB_DEV);
1378 if (!dir) {
1379 LOGE(ERROR, "opendir failed: '%s'", SYSFS_USB_DEV);
1380 return ERROR_FAIL;
1381 }
1382
1383 for (;;) {
1384 errno = 0;
1385 de = readdir(dir);
1386
1387 if (!de && errno) {
1388 LOGE(ERROR, "failed to readdir %s", SYSFS_USB_DEV);
1389 rc = ERROR_FAIL;
1390 goto out;
1391 }
1392 if (!de)
1393 break;
1394
1395 if (!strcmp(de->d_name, ".") ||
1396 !strcmp(de->d_name, ".."))
1397 continue;
1398
1399 if (!strncmp(de->d_name, buf, strlen(buf))) {
1400 GCREALLOC_ARRAY(*intfs, *num + 1);
1401 (*intfs)[*num] = libxl__strdup(gc, de->d_name);
1402 (*num)++;
1403 }
1404 }
1405
1406 rc = 0;
1407
1408 out:
1409 closedir(dir);
1410 return rc;
1411 }
1412
1413 /* Encode usb interface so that it could be written to xenstore as a key.
1414 *
1415 * Since xenstore key cannot include '.' or ':', we'll change '.' to '_',
1416 * change ':' to '@'. For example, 3-1:2.1 will be encoded to 3-1@2_1.
1417 * This will be used to save original driver of USB device to xenstore.
1418 */
usb_interface_xenstore_encode(libxl__gc * gc,const char * busid)1419 static char *usb_interface_xenstore_encode(libxl__gc *gc, const char *busid)
1420 {
1421 char *str = libxl__strdup(gc, busid);
1422 int i, len = strlen(str);
1423
1424 for (i = 0; i < len; i++) {
1425 if (str[i] == '.') str[i] = '_';
1426 if (str[i] == ':') str[i] = '@';
1427 }
1428 return str;
1429 }
1430
1431 /* Unbind USB device from "usbback" driver.
1432 *
1433 * If there are many interfaces under USB device, check each interface,
1434 * unbind from "usbback" driver.
1435 */
usbback_dev_unassign(libxl__gc * gc,const char * busid)1436 static int usbback_dev_unassign(libxl__gc *gc, const char *busid)
1437 {
1438 char **intfs = NULL;
1439 int i, num = 0;
1440 int rc;
1441
1442 rc = usbdev_get_all_interfaces(gc, busid, &intfs, &num);
1443 if (rc) goto out;
1444
1445 for (i = 0; i < num; i++) {
1446 char *intf = intfs[i];
1447
1448 /* check if the USB interface is already bound to "usbback" */
1449 if (usbintf_is_assigned(gc, intf) > 0) {
1450 /* unbind interface from usbback driver */
1451 rc = unbind_usbintf(gc, intf);
1452 if (rc) {
1453 LOGE(ERROR, "Couldn't unbind %s from usbback", intf);
1454 goto out;
1455 }
1456 }
1457 }
1458
1459 rc = 0;
1460
1461 out:
1462 return rc;
1463 }
1464
1465 /* rebind USB device to original driver.
1466 *
1467 * If there are many interfaces under USB device, for reach interface,
1468 * read driver_path from xenstore (if there is) and rebind to its
1469 * original driver, then remove driver_path information from xenstore.
1470 */
usbdev_rebind(libxl__gc * gc,const char * busid)1471 static int usbdev_rebind(libxl__gc *gc, const char *busid)
1472 {
1473 char **intfs = NULL;
1474 char *usbdev_encode = NULL;
1475 char *path = NULL;
1476 int i, num = 0;
1477 int rc;
1478
1479 rc = usbdev_get_all_interfaces(gc, busid, &intfs, &num);
1480 if (rc) goto out;
1481
1482 usbdev_encode = usb_interface_xenstore_encode(gc, busid);
1483
1484 for (i = 0; i < num; i++) {
1485 char *intf = intfs[i];
1486 char *usbintf_encode = NULL;
1487 const char *drvpath;
1488
1489 /* rebind USB interface to its originial driver */
1490 usbintf_encode = usb_interface_xenstore_encode(gc, intf);
1491 path = GCSPRINTF(USBBACK_INFO_PATH "/%s/%s/driver_path",
1492 usbdev_encode, usbintf_encode);
1493 rc = libxl__xs_read_checked(gc, XBT_NULL, path, &drvpath);
1494 if (rc) goto out;
1495
1496 if (drvpath) {
1497 rc = bind_usbintf(gc, intf, drvpath);
1498 if (rc) {
1499 LOGE(ERROR, "Couldn't rebind %s to %s", intf, drvpath);
1500 goto out;
1501 }
1502 }
1503 }
1504
1505 out:
1506 path = GCSPRINTF(USBBACK_INFO_PATH "/%s", usbdev_encode);
1507 libxl__xs_rm_checked(gc, XBT_NULL, path);
1508 return rc;
1509 }
1510
1511
1512 /* Bind USB device to "usbback" driver.
1513 *
1514 * If there are many interfaces under USB device, check each interface,
1515 * unbind from original driver and bind to "usbback" driver.
1516 */
usbback_dev_assign(libxl__gc * gc,const char * busid)1517 static int usbback_dev_assign(libxl__gc *gc, const char *busid)
1518 {
1519 char **intfs = NULL;
1520 int num = 0, i;
1521 int rc;
1522 char *usbdev_encode = NULL;
1523
1524 rc = usbdev_get_all_interfaces(gc, busid, &intfs, &num);
1525 if (rc) return rc;
1526
1527 usbdev_encode = usb_interface_xenstore_encode(gc, busid);
1528
1529 for (i = 0; i < num; i++) {
1530 char *intf = intfs[i];
1531 char *drvpath = NULL;
1532
1533 /* already assigned to usbback */
1534 if (usbintf_is_assigned(gc, intf) > 0)
1535 continue;
1536
1537 rc = usbintf_get_drvpath(gc, intf, &drvpath);
1538 if (rc) goto out;
1539
1540 if (drvpath) {
1541 /* write driver path to xenstore for later rebinding */
1542 char *usbintf_encode = NULL;
1543 char *path;
1544
1545 usbintf_encode = usb_interface_xenstore_encode(gc, intf);
1546 path = GCSPRINTF(USBBACK_INFO_PATH "/%s/%s/driver_path",
1547 usbdev_encode, usbintf_encode);
1548 rc = libxl__xs_write_checked(gc, XBT_NULL, path, drvpath);
1549 if (rc) goto out;
1550
1551 /* unbind interface from original driver */
1552 rc = unbind_usbintf(gc, intf);
1553 if (rc) goto out;
1554 }
1555
1556 /* bind interface to usbback */
1557 rc = bind_usbintf(gc, intf, SYSFS_USBBACK_DRIVER);
1558 if (rc) {
1559 LOG(ERROR, "Couldn't bind %s to %s", intf, SYSFS_USBBACK_DRIVER);
1560 goto out;
1561 }
1562 }
1563
1564 return 0;
1565
1566 out:
1567 /* some interfaces might be bound to usbback, unbind it and
1568 * rebind it to its original driver
1569 */
1570 usbback_dev_unassign(gc, busid);
1571 usbdev_rebind(gc, busid);
1572 return rc;
1573 }
1574
do_usbdev_add(libxl__gc * gc,uint32_t domid,libxl_device_usbdev * usbdev,bool update_json)1575 static int do_usbdev_add(libxl__gc *gc, uint32_t domid,
1576 libxl_device_usbdev *usbdev,
1577 bool update_json)
1578 {
1579 int rc;
1580 char *busid;
1581 libxl_device_usbctrl usbctrl;
1582 libxl_usbctrlinfo usbctrlinfo;
1583
1584 libxl_device_usbctrl_init(&usbctrl);
1585 libxl_usbctrlinfo_init(&usbctrlinfo);
1586 usbctrl.devid = usbdev->ctrl;
1587
1588 rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
1589 if (rc) goto out;
1590
1591 switch (usbctrlinfo.type) {
1592 case LIBXL_USBCTRL_TYPE_PV:
1593 busid = usbdev_busaddr_to_busid(gc, usbdev->u.hostdev.hostbus,
1594 usbdev->u.hostdev.hostaddr);
1595 if (!busid) {
1596 rc = ERROR_FAIL;
1597 goto out;
1598 }
1599
1600 rc = libxl__device_usbdev_add_xenstore(gc, domid, usbdev,
1601 LIBXL_USBCTRL_TYPE_PV,
1602 update_json);
1603 if (rc) goto out;
1604
1605 rc = usbback_dev_assign(gc, busid);
1606 if (rc) {
1607 libxl__device_usbdev_remove_xenstore(gc, domid, usbdev,
1608 LIBXL_USBCTRL_TYPE_PV);
1609 goto out;
1610 }
1611 break;
1612 case LIBXL_USBCTRL_TYPE_QUSB:
1613 rc = libxl__device_usbdev_add_xenstore(gc, domid, usbdev,
1614 LIBXL_USBCTRL_TYPE_QUSB,
1615 update_json);
1616 if (rc) goto out;
1617
1618 break;
1619 case LIBXL_USBCTRL_TYPE_DEVICEMODEL:
1620 rc = libxl__device_usbdev_add_xenstore(gc, domid, usbdev,
1621 LIBXL_USBCTRL_TYPE_DEVICEMODEL,
1622 update_json);
1623 if (rc) goto out;
1624
1625 rc = libxl__device_usbdev_add_hvm(gc, domid, usbdev);
1626 if (rc) {
1627 libxl__device_usbdev_remove_xenstore(gc, domid, usbdev,
1628 LIBXL_USBCTRL_TYPE_DEVICEMODEL);
1629 goto out;
1630 }
1631 break;
1632 default:
1633 LOGD(ERROR, domid, "Unsupported usb controller type");
1634 rc = ERROR_FAIL;
1635 goto out;
1636 }
1637
1638 rc = 0;
1639
1640 out:
1641 libxl_device_usbctrl_dispose(&usbctrl);
1642 libxl_usbctrlinfo_dispose(&usbctrlinfo);
1643 return rc;
1644 }
1645
1646 /* AO operation to add a usb device.
1647 *
1648 * Generally, it does:
1649 * 1) check if the usb device type is assignable
1650 * 2) check if the usb device is already assigned to a domain
1651 * 3) add 'busid' of the usb device to xenstore contoller/port/.
1652 * (PVUSB driver watches the xenstore changes and will detect that.)
1653 * 4) unbind usb device from original driver and bind to usbback.
1654 * If usb device has many interfaces, then:
1655 * - unbind each interface from its original driver and bind to usbback.
1656 * - store the original driver to xenstore for later rebinding when
1657 * detaching the device.
1658 *
1659 * Before calling this function, aodev should be properly filled:
1660 * aodev->ao, aodev->callback, aodev->update_json, ...
1661 */
libxl__device_usbdev_add(libxl__egc * egc,uint32_t domid,libxl_device_usbdev * usbdev,libxl__ao_device * aodev)1662 static void libxl__device_usbdev_add(libxl__egc *egc, uint32_t domid,
1663 libxl_device_usbdev *usbdev,
1664 libxl__ao_device *aodev)
1665 {
1666 STATE_AO_GC(aodev->ao);
1667 int rc;
1668 libxl_device_usbdev *assigned;
1669 int num_assigned;
1670 libxl_device_usbctrl usbctrl;
1671 libxl_usbctrlinfo usbctrlinfo;
1672
1673 libxl_device_usbctrl_init(&usbctrl);
1674 libxl_usbctrlinfo_init(&usbctrlinfo);
1675
1676 /* Currently only support adding USB device from Dom0 backend.
1677 * So, if USB controller is specified, check its backend domain,
1678 * if it's not Dom0, report error.
1679 */
1680 if (usbdev->ctrl != -1) {
1681 usbctrl.devid = usbdev->ctrl;
1682 rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
1683 if (rc) goto out;
1684
1685 if (usbctrlinfo.backend_id != LIBXL_TOOLSTACK_DOMID) {
1686 LOGD(ERROR, domid,
1687 "Don't support adding USB device from non-Dom0 backend");
1688 rc = ERROR_INVAL;
1689 goto out;
1690 }
1691 }
1692
1693 /* check usb device is assignable type */
1694 if (!is_usbdev_assignable(gc, usbdev)) {
1695 LOGD(ERROR, domid, "USB device is not assignable.");
1696 rc = ERROR_FAIL;
1697 goto out;
1698 }
1699
1700 /* check usb device is already assigned */
1701 rc = get_assigned_devices(gc, &assigned, &num_assigned);
1702 if (rc) {
1703 LOGD(ERROR, domid, "cannot determine if device is assigned,"
1704 " refusing to continue");
1705 goto out;
1706 }
1707
1708 if (is_usbdev_in_array(assigned, num_assigned, usbdev)) {
1709 LOGD(ERROR, domid, "USB device already attached to a domain");
1710 rc = ERROR_INVAL;
1711 goto out;
1712 }
1713
1714 /* fill default values, e.g, if usbdev->ctrl and usbdev->port
1715 * not specified, choose available controller:port and fill in. */
1716 rc = libxl__device_usbdev_setdefault(gc, domid, usbdev,
1717 aodev->update_json);
1718 if (rc) goto out;
1719
1720 /* do actual adding usb device operation */
1721 rc = do_usbdev_add(gc, domid, usbdev, aodev->update_json);
1722
1723 out:
1724 libxl_device_usbctrl_dispose(&usbctrl);
1725 libxl_usbctrlinfo_dispose(&usbctrlinfo);
1726 aodev->rc = rc;
1727 aodev->callback(egc, aodev);
1728 return;
1729 }
1730
1731 LIBXL_DEFINE_DEVICE_ADD(usbdev)
LIBXL_DEFINE_DEVICES_ADD(usbdev)1732 static LIBXL_DEFINE_DEVICES_ADD(usbdev)
1733
1734 static int do_usbdev_remove(libxl__gc *gc, uint32_t domid,
1735 libxl_device_usbdev *usbdev)
1736 {
1737 int rc;
1738 char *busid;
1739 libxl_device_usbctrl usbctrl;
1740 libxl_usbctrlinfo usbctrlinfo;
1741
1742 libxl_device_usbctrl_init(&usbctrl);
1743 libxl_usbctrlinfo_init(&usbctrlinfo);
1744 usbctrl.devid = usbdev->ctrl;
1745
1746 rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
1747 if (rc) goto out;
1748
1749 switch (usbctrlinfo.type) {
1750 case LIBXL_USBCTRL_TYPE_PV:
1751 busid = usbdev_busid_from_ctrlport(gc, domid, usbdev, usbctrlinfo.type);
1752 if (!busid) {
1753 rc = ERROR_FAIL;
1754 goto out;
1755 }
1756
1757 /* Things are done in order of:
1758 * unbind USB device from usbback,
1759 * remove USB device from xenstore,
1760 * rebind USB device to original driver.
1761 * It is to balance simplicity with robustness in case of failure:
1762 * - We unbind all interfaces before rebinding any interfaces, so
1763 * that we never get into a situation where some interfaces are
1764 * assigned to usbback and some are assigned to the original drivers.
1765 * - We also unbind the interfaces before removing the pvusb xenstore
1766 * nodes, so that if the unbind fails in the middle, the device still
1767 * shows up in xl usb-list, and the user can re-try removing it.
1768 */
1769 rc = usbback_dev_unassign(gc, busid);
1770 if (rc) {
1771 LOGD(ERROR, domid, "Error removing device from guest."
1772 " Try running usbdev-detach again.");
1773 goto out;
1774 }
1775
1776 rc = libxl__device_usbdev_remove_xenstore(gc, domid, usbdev,
1777 LIBXL_USBCTRL_TYPE_PV);
1778 if (rc) {
1779 LOGD(ERROR, domid, "Error removing device from guest."
1780 " Try running usbdev-detach again.");
1781 goto out;
1782 }
1783
1784 rc = usbdev_rebind(gc, busid);
1785 if (rc) {
1786 LOGD(ERROR, domid, "USB device removed from guest, but couldn't"
1787 " re-bind to domain 0. Try removing and re-inserting"
1788 " the USB device or reloading the driver modules.");
1789 goto out;
1790 }
1791
1792 break;
1793 case LIBXL_USBCTRL_TYPE_QUSB:
1794 rc = libxl__device_usbdev_remove_xenstore(gc, domid, usbdev,
1795 LIBXL_USBCTRL_TYPE_QUSB);
1796 if (rc) goto out;
1797
1798 break;
1799 case LIBXL_USBCTRL_TYPE_DEVICEMODEL:
1800 rc = libxl__device_usbdev_remove_xenstore(gc, domid, usbdev,
1801 LIBXL_USBCTRL_TYPE_DEVICEMODEL);
1802 if (rc) goto out;
1803
1804 rc = libxl__device_usbdev_del_hvm(gc, domid, usbdev);
1805 if (rc) {
1806 libxl__device_usbdev_add_xenstore(gc, domid, usbdev,
1807 LIBXL_USBCTRL_TYPE_DEVICEMODEL,
1808 false);
1809 goto out;
1810 }
1811
1812 break;
1813 default:
1814 LOGD(ERROR, domid, "Unsupported usb controller type");
1815 rc = ERROR_FAIL;
1816 goto out;
1817 }
1818
1819 rc = 0;
1820
1821 out:
1822 libxl_device_usbctrl_dispose(&usbctrl);
1823 libxl_usbctrlinfo_dispose(&usbctrlinfo);
1824 return rc;
1825 }
1826
1827 /* Operation to remove usb device.
1828 *
1829 * Generally, it does:
1830 * 1) check if the usb device is assigned to the domain
1831 * 2) remove the usb device from xenstore controller/port.
1832 * 3) unbind usb device from usbback and rebind to its original driver.
1833 * If usb device has many interfaces, do it to each interface.
1834 */
libxl__device_usbdev_remove(libxl__gc * gc,uint32_t domid,libxl_device_usbdev * usbdev)1835 static int libxl__device_usbdev_remove(libxl__gc *gc, uint32_t domid,
1836 libxl_device_usbdev *usbdev)
1837 {
1838 libxl_usbctrlinfo usbctrlinfo;
1839 libxl_device_usbctrl usbctrl;
1840 int rc;
1841
1842 if (usbdev->ctrl < 0 || usbdev->port < 1) {
1843 LOGD(ERROR, domid, "Invalid USB device");
1844 return ERROR_FAIL;
1845 }
1846
1847 libxl_device_usbctrl_init(&usbctrl);
1848 libxl_usbctrlinfo_init(&usbctrlinfo);
1849 usbctrl.devid = usbdev->ctrl;
1850
1851 rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
1852 if (rc) goto out;
1853
1854 if (usbctrlinfo.backend_id != LIBXL_TOOLSTACK_DOMID) {
1855 LOGD(ERROR, domid,
1856 "Don't support removing USB device from non-Dom0 backend");
1857 rc = ERROR_INVAL;
1858 goto out;
1859 }
1860
1861 /* do actual removing usb device operation */
1862 rc = do_usbdev_remove(gc, domid, usbdev);
1863
1864 out:
1865 libxl_device_usbctrl_dispose(&usbctrl);
1866 libxl_usbctrlinfo_dispose(&usbctrlinfo);
1867 return rc;
1868 }
1869
libxl_device_usbdev_remove(libxl_ctx * ctx,uint32_t domid,libxl_device_usbdev * usbdev,const libxl_asyncop_how * ao_how)1870 int libxl_device_usbdev_remove(libxl_ctx *ctx, uint32_t domid,
1871 libxl_device_usbdev *usbdev,
1872 const libxl_asyncop_how *ao_how)
1873
1874 {
1875 AO_CREATE(ctx, domid, ao_how);
1876 int rc;
1877
1878 rc = libxl__device_usbdev_remove(gc, domid, usbdev);
1879
1880 libxl__ao_complete(egc, ao, rc);
1881 return AO_INPROGRESS;
1882 }
1883
libxl_ctrlport_to_device_usbdev(libxl_ctx * ctx,uint32_t domid,int ctrl,int port,libxl_device_usbdev * usbdev)1884 int libxl_ctrlport_to_device_usbdev(libxl_ctx *ctx,
1885 uint32_t domid,
1886 int ctrl,
1887 int port,
1888 libxl_device_usbdev *usbdev)
1889 {
1890 GC_INIT(ctx);
1891 const char *libxl_dom_path, *libxl_path, *be_path, *busid;
1892 int rc;
1893
1894 libxl_dom_path = libxl__xs_libxl_path(gc, domid);
1895
1896 libxl_path = GCSPRINTF("%s/device/vusb/%d", libxl_dom_path, ctrl);
1897 be_path = vusb_be_from_xs_libxl(gc, libxl_path);
1898 if (!be_path) {
1899 rc = ERROR_FAIL;
1900 goto out;
1901 }
1902
1903 rc = libxl__xs_read_checked(gc, XBT_NULL,
1904 GCSPRINTF("%s/port/%d", be_path, port),
1905 &busid);
1906 if (rc) goto out;
1907
1908 if (!busid || !strcmp(busid, "")) {
1909 rc = ERROR_FAIL;
1910 goto out;
1911 }
1912
1913 usbdev->ctrl = ctrl;
1914 usbdev->port = port;
1915 usbdev->type = LIBXL_USBDEV_TYPE_HOSTDEV;
1916 rc = usbdev_busaddr_from_busid(gc, busid,
1917 &usbdev->u.hostdev.hostbus,
1918 &usbdev->u.hostdev.hostaddr);
1919
1920 out:
1921 GC_FREE;
1922 return rc;
1923 }
1924
libxl_device_usbctrl_compare(libxl_device_usbctrl * d1,libxl_device_usbctrl * d2)1925 static int libxl_device_usbctrl_compare(libxl_device_usbctrl *d1,
1926 libxl_device_usbctrl *d2)
1927 {
1928 return COMPARE_USBCTRL(d1, d2);
1929 }
1930
libxl_device_usbctrl_dm_needed(void * e,unsigned domid)1931 static int libxl_device_usbctrl_dm_needed(void *e, unsigned domid)
1932 {
1933 libxl_device_usbctrl *elem = e;
1934
1935 return elem->type == LIBXL_USBCTRL_TYPE_QUSB &&
1936 elem->backend_domid == domid;
1937 }
1938
libxl_device_usbdev_compare(libxl_device_usbdev * d1,libxl_device_usbdev * d2)1939 static int libxl_device_usbdev_compare(libxl_device_usbdev *d1,
1940 libxl_device_usbdev *d2)
1941 {
1942 return COMPARE_USB(d1, d2);
1943 }
1944
libxl_device_usbctrl_list_free(libxl_device_usbctrl * list,int nr)1945 void libxl_device_usbctrl_list_free(libxl_device_usbctrl *list, int nr)
1946 {
1947 int i;
1948
1949 for (i = 0; i < nr; i++)
1950 libxl_device_usbctrl_dispose(&list[i]);
1951 free(list);
1952 }
1953
libxl_device_usbdev_list_free(libxl_device_usbdev * list,int nr)1954 void libxl_device_usbdev_list_free(libxl_device_usbdev *list, int nr)
1955 {
1956 int i;
1957
1958 for (i = 0; i < nr; i++)
1959 libxl_device_usbdev_dispose(&list[i]);
1960 free(list);
1961 }
1962
1963 #define libxl__device_usbctrl_update_devid NULL
1964
1965 DEFINE_DEVICE_TYPE_STRUCT(usbctrl,
1966 .dm_needed = libxl_device_usbctrl_dm_needed
1967 );
1968
1969 #define libxl__device_from_usbdev NULL
1970 #define libxl__device_usbdev_update_devid NULL
1971
1972 DEFINE_DEVICE_TYPE_STRUCT(usbdev);
1973
1974 /*
1975 * Local variables:
1976 * mode: C
1977 * c-basic-offset: 4
1978 * indent-tabs-mode: nil
1979 * End:
1980 */
1981