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