@@ -722,6 +722,90 @@ Note this may be overridden by rdm_policy option in PCI device configuration.
=back
+=item B<usbctrl=[ "USBCTRL_SPEC_STRING", "USBCTRL_SPEC_STRING", ... ]>
+
+Specifies the USB controllers created for this guest. Each
+B<USB_SPEC_STRING> has the form C<KEY=VALUE,KEY=VALUE,...> where:
+
+=over 4
+
+=item B<KEY=VALUE>
+
+Possible B<KEY>s are:
+
+=over 4
+
+=item B<type=TYPE>
+
+Specifies the usb controller type. Currently only 'pv' and 'auto'
+are supported.
+
+=item B<version=VERSION>
+
+Specifies the usb controller version. Possible values include
+1 (USB1.1) and 2 (USB2.0). Default is 2 (USB2.0).
+
+=item B<ports=PORTS>
+
+Specifies the total ports of the usb controller. The maximum
+number is 31. Default is 8.
+
+USB controler ids start from 0. In line with the USB spec, however,
+ports on a controller start from 1.
+
+E.g.
+usbctrl=["version=1,ports=4", "version=2,ports=8",]
+The first controller has:
+controller id = 0, and port 1,2,3,4.
+The second controller has:
+controller id = 1, and port 1,2,3,4,5,6,7,8.
+
+=back
+
+=back
+
+=item B<usbdev=[ "USB_SPEC_STRING", "USB_SPEC_STRING", ... ]>
+
+Specifies the USB devices to be attached to the guest at boot. Each
+B<USB_SPEC_STRING> has the form C<KEY=VALUE,KEY=VALUE,...> where:
+
+=over 4
+
+=item B<KEY=VALUE>
+
+Possible B<KEY>s are:
+
+=over 4
+
+=item B<devtype=hostdev>
+
+Specifies USB device type. Currently only support 'hostdev'.
+
+=item B<hostbus=busnum>
+
+Specifies busnum of the USB device from the host perspective.
+
+=item B<hostaddr=devnum>
+
+Specifies devnum of the USB device from the host perspective.
+
+=item B<controller=CONTROLLER>
+
+Specifies USB controller id, to which controller the USB device is attached.
+
+=item B<port=PORT>
+
+Specifies USB port, to which port the USB device is attached. B<port=PORT>
+is valid only when B<controller=CONTROLLER> is specified.
+
+=back
+
+If no controller is specified, an available controller:port combination
+will be used. If there are no available controller:port options,
+a new controller will be created.
+
+=back
+
=item B<pci=[ "PCI_SPEC_STRING", "PCI_SPEC_STRING", ... ]>
Specifies the host PCI devices to passthrough to this guest. Each B<PCI_SPEC_STRING>
@@ -733,6 +733,10 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *aodevs,
static void domcreate_attach_vtpms(libxl__egc *egc, libxl__multidev *multidev,
int ret);
+static void domcreate_attach_usbctrls(libxl__egc *egc,
+ libxl__multidev *multidev, int ret);
+static void domcreate_attach_usbdevs(libxl__egc *egc, libxl__multidev *multidev,
+ int ret);
static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *aodevs,
int ret);
static void domcreate_attach_dtdev(libxl__egc *egc,
@@ -1398,13 +1402,13 @@ static void domcreate_attach_vtpms(libxl__egc *egc,
if (d_config->num_vtpms > 0) {
/* Attach vtpms */
libxl__multidev_begin(ao, &dcs->multidev);
- dcs->multidev.callback = domcreate_attach_pci;
+ dcs->multidev.callback = domcreate_attach_usbctrls;
libxl__add_vtpms(egc, ao, domid, d_config, &dcs->multidev);
libxl__multidev_prepared(egc, &dcs->multidev, 0);
return;
}
- domcreate_attach_pci(egc, multidev, 0);
+ domcreate_attach_usbctrls(egc, multidev, 0);
return;
error_out:
@@ -1412,6 +1416,69 @@ error_out:
domcreate_complete(egc, dcs, ret);
}
+static void domcreate_attach_usbctrls(libxl__egc *egc,
+ libxl__multidev *multidev, int ret)
+{
+ libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
+ STATE_AO_GC(dcs->ao);
+ int domid = dcs->guest_domid;
+
+ libxl_domain_config *const d_config = dcs->guest_config;
+
+ if (ret) {
+ LOG(ERROR, "unable to add vtpm devices");
+ goto error_out;
+ }
+
+ if (d_config->num_usbctrls > 0) {
+ /* Attach usbctrls */
+ libxl__multidev_begin(ao, &dcs->multidev);
+ dcs->multidev.callback = domcreate_attach_usbdevs;
+ libxl__add_usbctrls(egc, ao, domid, d_config, &dcs->multidev);
+ libxl__multidev_prepared(egc, &dcs->multidev, 0);
+ return;
+ }
+
+ domcreate_attach_usbdevs(egc, multidev, 0);
+ return;
+
+error_out:
+ assert(ret);
+ domcreate_complete(egc, dcs, ret);
+}
+
+
+static void domcreate_attach_usbdevs(libxl__egc *egc, libxl__multidev *multidev,
+ int ret)
+{
+ libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
+ STATE_AO_GC(dcs->ao);
+ int domid = dcs->guest_domid;
+
+ libxl_domain_config *const d_config = dcs->guest_config;
+
+ if (ret) {
+ LOG(ERROR, "unable to add usbctrl devices");
+ goto error_out;
+ }
+
+ if (d_config->num_usbdevs > 0) {
+ /* Attach usbctrls */
+ libxl__multidev_begin(ao, &dcs->multidev);
+ dcs->multidev.callback = domcreate_attach_pci;
+ libxl__add_usbdevs(egc, ao, domid, d_config, &dcs->multidev);
+ libxl__multidev_prepared(egc, &dcs->multidev, 0);
+ return;
+ }
+
+ domcreate_attach_pci(egc, multidev, 0);
+ return;
+
+error_out:
+ assert(ret);
+ domcreate_complete(egc, dcs, ret);
+}
+
static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *multidev,
int ret)
{
@@ -1424,7 +1491,7 @@ static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *multidev,
libxl_domain_config *const d_config = dcs->guest_config;
if (ret) {
- LOG(ERROR, "unable to add vtpm devices");
+ LOG(ERROR, "unable to add usb devices");
goto error_out;
}
@@ -544,6 +544,8 @@ void libxl__multidev_prepared(libxl__egc *egc,
* libxl__add_disks
* libxl__add_nics
* libxl__add_vtpms
+ * libxl__add_usbctrls
+ * libxl__add_usbs
*/
#define DEFINE_DEVICES_ADD(type) \
@@ -563,6 +565,8 @@ void libxl__multidev_prepared(libxl__egc *egc,
DEFINE_DEVICES_ADD(disk)
DEFINE_DEVICES_ADD(nic)
DEFINE_DEVICES_ADD(vtpm)
+DEFINE_DEVICES_ADD(usbctrl)
+DEFINE_DEVICES_ADD(usbdev)
#undef DEFINE_DEVICES_ADD
@@ -3319,6 +3319,14 @@ _hidden void libxl__add_vtpms(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
libxl_domain_config *d_config,
libxl__multidev *multidev);
+_hidden void libxl__add_usbctrls(libxl__egc *egc, libxl__ao *ao,
+ uint32_t domid, libxl_domain_config *d_config,
+ libxl__multidev *multidev);
+
+_hidden void libxl__add_usbdevs(libxl__egc *egc, libxl__ao *ao,
+ uint32_t domid, libxl_domain_config *d_config,
+ libxl__multidev *multidev);
+
/*----- device model creation -----*/
/* First layer; wraps libxl__spawn_spawn. */
@@ -1255,6 +1255,58 @@ static void parse_vnuma_config(const XLU_Config *config,
free(vcpu_parsed);
}
+/* Parses usbctrl data and adds info into usbctrl
+ * Returns 1 if the input token does not match one of the keys
+ * or parsed values are not correct. Successful parse returns 0 */
+static int parse_usbctrl_config(libxl_device_usbctrl *usbctrl, char *token)
+{
+ char *oparg;
+
+ if (MATCH_OPTION("type", token, oparg)) {
+ if (libxl_usbctrl_type_from_string(oparg, &usbctrl->type)) {
+ fprintf(stderr, "Invalid usb controller type '%s'\n", oparg);
+ return 1;
+ }
+ } else if (MATCH_OPTION("version", token, oparg)) {
+ usbctrl->version = atoi(oparg);
+ } else if (MATCH_OPTION("ports", token, oparg)) {
+ usbctrl->ports = atoi(oparg);
+ } else {
+ fprintf(stderr, "Unknown string `%s' in usbctrl spec\n", token);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Parses usbdev data and adds info into usbdev
+ * Returns 1 if the input token does not match one of the keys
+ * or parsed values are not correct. Successful parse returns 0 */
+static int parse_usbdev_config(libxl_device_usbdev *usbdev, char *token)
+{
+ char *oparg;
+
+ if (MATCH_OPTION("type", token, oparg)) {
+ if (libxl_usbdev_type_from_string(oparg, &usbdev->type)) {
+ fprintf(stderr, "Invalid usb device type: %s\n", optarg);
+ return 1;
+ }
+ } else if (MATCH_OPTION("hostbus", token, oparg)) {
+ usbdev->u.hostdev.hostbus = strtoul(oparg, NULL, 0);
+ } else if (MATCH_OPTION("hostaddr", token, oparg)) {
+ usbdev->u.hostdev.hostaddr = strtoul(oparg, NULL, 0);
+ } else if (MATCH_OPTION("controller", token, oparg)) {
+ usbdev->ctrl = atoi(oparg);
+ } else if (MATCH_OPTION("port", token, oparg)) {
+ usbdev->port = atoi(oparg);
+ } else {
+ fprintf(stderr, "Unknown string `%s' in usbdev spec\n", token);
+ return 1;
+ }
+
+ return 0;
+}
+
static void parse_config_data(const char *config_source,
const char *config_data,
int config_len,
@@ -1263,7 +1315,8 @@ static void parse_config_data(const char *config_source,
const char *buf;
long l, vcpus = 0;
XLU_Config *config;
- XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms;
+ XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
+ *usbctrls, *usbdevs;
XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs;
int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian;
int pci_power_mgmt = 0;
@@ -2080,6 +2133,58 @@ skip_vfb:
}
}
+ if (!xlu_cfg_get_list(config, "usbctrl", &usbctrls, 0, 0)) {
+ d_config->num_usbctrls = 0;
+ d_config->usbctrls = NULL;
+ while ((buf = xlu_cfg_get_listitem(usbctrls, d_config->num_usbctrls))
+ != NULL) {
+ libxl_device_usbctrl *usbctrl;
+ char *buf2 = strdup(buf);
+ char *p;
+
+ usbctrl = ARRAY_EXTEND_INIT(d_config->usbctrls,
+ d_config->num_usbctrls,
+ libxl_device_usbctrl_init);
+ p = strtok(buf2, ",");
+ if (!p)
+ goto skip_usbctrl;
+ do {
+ while (*p == ' ')
+ p++;
+ if (parse_usbctrl_config(usbctrl, p))
+ exit(1);
+ } while ((p = strtok(NULL, ",")) != NULL);
+skip_usbctrl:
+ free(buf2);
+ }
+ }
+
+ if (!xlu_cfg_get_list(config, "usbdev", &usbdevs, 0, 0)) {
+ d_config->num_usbdevs = 0;
+ d_config->usbdevs = NULL;
+ while ((buf = xlu_cfg_get_listitem(usbdevs, d_config->num_usbdevs))
+ != NULL) {
+ libxl_device_usbdev *usbdev;
+ char *buf2 = strdup(buf);
+ char *p;
+
+ usbdev = ARRAY_EXTEND_INIT_NODEVID(d_config->usbdevs,
+ d_config->num_usbdevs,
+ libxl_device_usbdev_init);
+ p = strtok(buf2, ",");
+ if (!p)
+ goto skip_usbdev;
+ do {
+ while (*p == ' ')
+ p++;
+ if (parse_usbdev_config(usbdev, p))
+ exit(1);
+ } while ((p = strtok(NULL, ",")) != NULL);
+skip_usbdev:
+ free(buf2);
+ }
+ }
+
switch (xlu_cfg_get_list(config, "cpuid", &cpuids, 0, 1)) {
case 0:
{