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