From 6b3e4e2bea91b1247485da0987f98ccbe30e0629 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
Date: Wed, 12 Aug 2015 16:52:16 +0200
Subject: [PATCH] Add functions for adding USB controllers to addrs

Walk through all the usb controllers in the domain definition
and create the corresponding structures in the virDomainUSBAddressSet.
---
 src/conf/domain_addr.c   | 121 +++++++++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_addr.h   |   4 ++
 src/libvirt_private.syms |   1 +
 3 files changed, 126 insertions(+)

Index: libvirt-2.0.0/src/conf/domain_addr.c
===================================================================
--- libvirt-2.0.0.orig/src/conf/domain_addr.c
+++ libvirt-2.0.0/src/conf/domain_addr.c
@@ -1326,3 +1326,124 @@ virDomainUSBAddressSetFree(virDomainUSBA
     VIR_FREE(addrs->buses);
     VIR_FREE(addrs);
 }
+
+
+static size_t
+virDomainUSBAddressControllerModelToPorts(virDomainControllerDefPtr cont)
+{
+    int model = cont->model;
+
+    if (model == -1)
+        model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI;
+
+    switch ((virDomainControllerModelUSB) model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI:
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI:
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI:
+        return 2;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI:
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
+        return 6;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
+        /* These have two ports each and are used to provide USB1.1
+         * ports while ICH9_EHCI1 provides 6 USB2.0 ports.
+         * Ignore these since we will add the EHCI1 too. */
+        return 0;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI:
+        return 3;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI:
+        if (cont->opts.usbopts.ports != -1)
+            return cont->opts.usbopts.ports;
+        return 4;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST:
+        break;
+    }
+    return 0;
+}
+
+
+static virDomainUSBAddressHubPtr
+virDomainUSBAddressHubNew(size_t nports)
+{
+    virDomainUSBAddressHubPtr hub = NULL, ret = NULL;
+
+    if (VIR_ALLOC(hub) < 0)
+        goto cleanup;
+
+    if (!(hub->portmap = virBitmapNew(nports)))
+        goto cleanup;
+
+    if (VIR_ALLOC_N(hub->ports, nports) < 0)
+        goto cleanup;
+    hub->nports = nports;
+
+    ret = hub;
+    hub = NULL;
+ cleanup:
+    virDomainUSBAddressHubFree(hub);
+    return ret;
+}
+
+
+static int
+virDomainUSBAddressSetAddController(virDomainUSBAddressSetPtr addrs,
+                                    virDomainControllerDefPtr cont)
+{
+    size_t nports = virDomainUSBAddressControllerModelToPorts(cont);
+    virDomainUSBAddressHubPtr hub = NULL;
+    int ret = -1;
+
+    VIR_DEBUG("Adding a USB controller model=%s with %zu ports",
+              virDomainControllerModelUSBTypeToString(cont->model),
+              nports);
+
+    /* Skip UHCI{1,2,3} companions; only add the EHCI1 */
+    if (nports == 0)
+        return 0;
+
+    if (addrs->nbuses <= cont->idx) {
+        if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, cont->idx - addrs->nbuses + 1) < 0)
+            goto cleanup;
+    } else if (addrs->buses[cont->idx]) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("Duplicate USB controllers with index %u"),
+                       cont->idx);
+        goto cleanup;
+    }
+
+    if (!(hub = virDomainUSBAddressHubNew(nports)))
+        goto cleanup;
+
+    addrs->buses[cont->idx] = hub;
+    hub = NULL;
+
+    ret = 0;
+ cleanup:
+    virDomainUSBAddressHubFree(hub);
+    return ret;
+}
+
+
+int
+virDomainUSBAddressSetAddControllers(virDomainUSBAddressSetPtr addrs,
+                                     virDomainDefPtr def)
+{
+    size_t i;
+
+    for (i = 0; i < def->ncontrollers; i++) {
+        virDomainControllerDefPtr cont = def->controllers[i];
+        if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
+            if (virDomainUSBAddressSetAddController(addrs, cont) < 0)
+                return -1;
+        }
+    }
+    return 0;
+}
Index: libvirt-2.0.0/src/conf/domain_addr.h
===================================================================
--- libvirt-2.0.0.orig/src/conf/domain_addr.h
+++ libvirt-2.0.0/src/conf/domain_addr.h
@@ -269,6 +269,10 @@ typedef struct _virDomainUSBAddressSet v
 typedef virDomainUSBAddressSet *virDomainUSBAddressSetPtr;
 
 virDomainUSBAddressSetPtr virDomainUSBAddressSetCreate(void);
+
+int virDomainUSBAddressSetAddControllers(virDomainUSBAddressSetPtr addrs,
+                                         virDomainDefPtr def)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 void virDomainUSBAddressSetFree(virDomainUSBAddressSetPtr addrs);
 
 #endif /* __DOMAIN_ADDR_H__ */
Index: libvirt-2.0.0/src/libvirt_private.syms
===================================================================
--- libvirt-2.0.0.orig/src/libvirt_private.syms
+++ libvirt-2.0.0/src/libvirt_private.syms
@@ -110,6 +110,7 @@ virDomainPCIControllerModelToConnectType
 virDomainUSBAddressPortFormat;
 virDomainUSBAddressPortFormatBuf;
 virDomainUSBAddressPortIsValid;
+virDomainUSBAddressSetAddControllers;
 virDomainUSBAddressSetCreate;
 virDomainUSBAddressSetFree;
 virDomainVirtioSerialAddrAssign;
