@@ -1345,6 +1345,47 @@ List pass-through pci devices for a domain.
=back
+=head1 USB PASS-THROUGH
+
+=over 4
+
+=item B<usbctrl-attach> I<domain-id> I[<type=val>] [I<version=val>] [I<ports=number>]
+
+Create a new USB controller for the specified domain.
+B<type=val> is the usb controller type. Currently only 'pv' and 'auto'
+are supported.
+B<version=val> is the usb controller version. Possible values include
+1 (USB1.1) and 2 (USB2.0).
+B<ports=number> is the total ports of the usb controller. The maximum
+number is 31.
+By default, it will create a USB2.0 controller with 8 ports.
+
+=item B<usbctrl-detach> I<domain-id> I<devid>
+
+Destroy a USB controller from the specified domain.
+B<devid> is devid of the USB controller.
+
+=item B<usb-attach> I<domain-id> I<hostbus=busnum> I<hostaddr=devnum> [I<controller=devid> [I<port=number>]]
+
+Hot-plug a new pass-through USB device to the specified domain.
+B<hostbus> and B<hostaddr> are the bus and device number of the physical
+USB device to pass through.
+B<controller=devid> B<port=number> is the USB controller:port to hotplug the
+USB device to. By default, it will find the first available controller:port
+and use it; if there is no controller, a new controller will be created.
+
+=item B<usb-detach> I<domain-id> I<controller=devid> I<port=number>
+
+Hot-unplug a previously assigned USB device from a domain.
+B<controller=devid> and B<port=number> is USB controller:port in guest where the
+USB device is attached to.
+
+=item B<usb-list> I<domain-id>
+
+List pass-through usb devices for a domain.
+
+=back
+
=head1 TMEM
=over 4
@@ -92,6 +92,11 @@ int main_blockdetach(int argc, char **argv);
int main_vtpmattach(int argc, char **argv);
int main_vtpmlist(int argc, char **argv);
int main_vtpmdetach(int argc, char **argv);
+int main_usbctrl_attach(int argc, char **argv);
+int main_usbctrl_detach(int argc, char **argv);
+int main_usbdev_attach(int argc, char **argv);
+int main_usbdev_detach(int argc, char **argv);
+int main_usblist(int argc, char **argv);
int main_uptime(int argc, char **argv);
int main_claims(int argc, char **argv);
int main_tmem_list(int argc, char **argv);
@@ -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,
@@ -3402,6 +3454,197 @@ int main_cd_insert(int argc, char **argv)
return 0;
}
+int main_usbctrl_attach(int argc, char **argv)
+{
+ uint32_t domid;
+ int opt, rc = 0;
+ libxl_device_usbctrl usbctrl;
+
+ SWITCH_FOREACH_OPT(opt, "", NULL, "usbctrl-attach", 1) {
+ /* No options */
+ }
+
+ domid = find_domain(argv[optind++]);
+
+ libxl_device_usbctrl_init(&usbctrl);
+
+ for (argv += optind, argc -= optind; argc > 0; ++argv, --argc) {
+ if (parse_usbctrl_config(&usbctrl, *argv))
+ return 1;
+ }
+
+ rc = libxl_device_usbctrl_add(ctx, domid, &usbctrl, 0);
+ if (rc) {
+ fprintf(stderr, "libxl_device_usbctrl_add failed.\n");
+ rc = 1;
+ }
+
+ libxl_device_usbctrl_dispose(&usbctrl);
+ return rc;
+}
+
+int main_usbctrl_detach(int argc, char **argv)
+{
+ uint32_t domid;
+ int opt, devid, rc;
+ libxl_device_usbctrl usbctrl;
+
+ SWITCH_FOREACH_OPT(opt, "", NULL, "usbctrl-detach", 2) {
+ /* No options */
+ }
+
+ domid = find_domain(argv[optind]);
+ devid = atoi(argv[optind+1]);
+
+ libxl_device_usbctrl_init(&usbctrl);
+ if (libxl_devid_to_device_usbctrl(ctx, domid, devid, &usbctrl)) {
+ fprintf(stderr, "Unknown device %s.\n", argv[optind+1]);
+ return 1;
+ }
+
+ rc = libxl_device_usbctrl_remove(ctx, domid, &usbctrl, 0);
+ if (rc) {
+ fprintf(stderr, "libxl_device_usbctrl_remove failed.\n");
+ rc = 1;
+ }
+
+ libxl_device_usbctrl_dispose(&usbctrl);
+ return rc;
+
+}
+
+int main_usbdev_attach(int argc, char **argv)
+{
+ uint32_t domid;
+ int opt, rc;
+ libxl_device_usbdev usbdev;
+
+ SWITCH_FOREACH_OPT(opt, "", NULL, "usbdev-attach", 2) {
+ /* No options */
+ }
+
+ libxl_device_usbdev_init(&usbdev);
+
+ domid = find_domain(argv[optind++]);
+
+ for (argv += optind, argc -= optind; argc > 0; ++argv, --argc) {
+ if (parse_usbdev_config(&usbdev, *argv))
+ return 1;
+ }
+
+ rc = libxl_device_usbdev_add(ctx, domid, &usbdev, 0);
+ if (rc) {
+ fprintf(stderr, "libxl_device_usbdev_add failed.\n");
+ rc = 1;
+ }
+
+ libxl_device_usbdev_dispose(&usbdev);
+ return rc;
+}
+
+int main_usbdev_detach(int argc, char **argv)
+{
+ uint32_t domid;
+ int ctrl, port;
+ int opt, rc = 1;
+ libxl_device_usbdev usbdev;
+
+ SWITCH_FOREACH_OPT(opt, "", NULL, "usbdev-detach", 3) {
+ /* No options */
+ }
+
+ domid = find_domain(argv[optind]);
+ ctrl = atoi(argv[optind+1]);
+ port = atoi(argv[optind+2]);
+
+ if (argc - optind > 3) {
+ fprintf(stderr, "Invalid arguments.\n");
+ return 1;
+ }
+
+ libxl_device_usbdev_init(&usbdev);
+ if (libxl_ctrlport_to_device_usbdev(ctx, domid, ctrl, port, &usbdev)) {
+ fprintf(stderr, "Unknown device at controller %d port %d.\n",
+ ctrl, port);
+ return 1;
+ }
+
+ rc = libxl_device_usbdev_remove(ctx, domid, &usbdev, 0);
+ if (rc) {
+ fprintf(stderr, "libxl_device_usbdev_remove failed.\n");
+ rc = 1;
+ }
+
+ libxl_device_usbdev_dispose(&usbdev);
+ return rc;
+}
+
+int main_usblist(int argc, char **argv)
+{
+ uint32_t domid;
+ libxl_device_usbctrl *usbctrls;
+ libxl_usbctrlinfo usbctrlinfo;
+ int numctrl, i, j, opt;
+
+ SWITCH_FOREACH_OPT(opt, "", NULL, "usb-list", 1) {
+ /* No options */
+ }
+
+ domid = find_domain(argv[optind++]);
+
+ if (argc > optind) {
+ fprintf(stderr, "Invalid arguments.\n");
+ exit(-1);
+ }
+
+ usbctrls = libxl_device_usbctrl_list(ctx, domid, &numctrl);
+ if (!usbctrls) {
+ return 0;
+ }
+
+ for (i = 0; i < numctrl; ++i) {
+ printf("%-6s %-6s %-3s %-5s %-7s %-5s %-30s\n",
+ "Devid", "Type", "BE", "state", "usb-ver", "ports", "BE-path");
+
+ libxl_usbctrlinfo_init(&usbctrlinfo);
+
+ if (!libxl_device_usbctrl_getinfo(ctx, domid,
+ &usbctrls[i], &usbctrlinfo)) {
+ printf("%-6d %-6s %-3d %-5d %-7d %-5d %-30s\n",
+ usbctrlinfo.devid,
+ libxl_usbctrl_type_to_string(usbctrlinfo.type),
+ usbctrlinfo.backend_id, usbctrlinfo.state,
+ usbctrlinfo.version, usbctrlinfo.ports,
+ usbctrlinfo.backend);
+
+ for (j = 1; j <= usbctrlinfo.ports; j++) {
+ libxl_device_usbdev usbdev;
+
+ libxl_device_usbdev_init(&usbdev);
+
+ printf(" Port %d:", j);
+
+ if (!libxl_ctrlport_to_device_usbdev(ctx, domid,
+ usbctrlinfo.devid,
+ j, &usbdev)) {
+ printf(" Bus %03x Device %03x\n",
+ usbdev.u.hostdev.hostbus,
+ usbdev.u.hostdev.hostaddr);
+ } else {
+ printf("\n");
+ }
+
+ libxl_device_usbdev_dispose(&usbdev);
+ }
+ }
+
+ libxl_usbctrlinfo_dispose(&usbctrlinfo);
+ }
+
+ libxl_device_usbctrl_list_free(usbctrls, numctrl);
+ return 0;
+}
+
int main_console(int argc, char **argv)
{
uint32_t domid;
@@ -553,6 +553,31 @@ struct cmd_spec cmd_table[] = {
},
#endif
+ { "usbctrl-attach",
+ &main_usbctrl_attach, 0, 1,
+ "Create a virtual USB controller for a domain",
+ "<Domain> [type=pv] [version=<version>] [ports=<number>]",
+ },
+ { "usbctrl-detach",
+ &main_usbctrl_detach, 0, 1,
+ "Remove the virtual USB controller specified by <DevId> for a domain",
+ "<Domain> <DevId>",
+ },
+ { "usbdev-attach",
+ &main_usbdev_attach, 0, 1,
+ "Attach a USB device to a domain",
+ "<Domain> hostbus=<busnum> hostaddr=<devnum> [controller=<DevId> [port=<port>]]",
+ },
+ { "usbdev-detach",
+ &main_usbdev_detach, 0, 1,
+ "Detach a USB device from a domain",
+ "<Domain> <controller> <port>",
+ },
+ { "usb-list",
+ &main_usblist, 0, 0,
+ "List information about all USB controllers and devices for a domain",
+ "<Domain>",
+ },
};
int cmdtable_len = sizeof(cmd_table)/sizeof(struct cmd_spec);