[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] PATCH: Video device config



I recently posted a patch on the RedHat bugzilla (bug #467038) to add a model attribute to the graphics element so that the different graphics cards supported by QEMU could be selected.

Apparently that approach has been rejected in the past however, and the preferred approach is to add a separate video element.

I've taken the patch that Daniel Berrange posted here a few months ago that added the necessary XML handling for the new element and extended it by filling in the QEMU driver code to make it use the model details as well as fixing the default video model for XEN domains as per the list of outstanding issues given with the original patch.

The updated patch is attached, and based on the list of outstanding tasks given before what remains to be done is:

 - Add RNG XML schemas & website docs
 - Make Xen drivers use this info for setting stdvga=1|0 config arg
 - Make VirtualBox use this info in whatever way it needs

Tom

--
Tom Hughes (tom compton nu)
http://www.compton.nu/
diff --git a/src/domain_conf.c b/src/domain_conf.c
index ffa2aef..0f1f249 100644
--- a/src/domain_conf.c
+++ b/src/domain_conf.c
@@ -82,6 +82,7 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
               "interface",
               "input",
               "sound",
+              "video",
               "hostdev")
 
 VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
@@ -142,6 +143,12 @@ VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
               "pcspk",
               "ac97")
 
+VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
+              "vga",
+              "cirrus",
+              "vmvga",
+              "xen")
+
 VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
               "mouse",
               "tablet")
@@ -374,6 +381,14 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def)
     VIR_FREE(def);
 }
 
+void virDomainVideoDefFree(virDomainVideoDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def);
+}
+
 void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
 {
     if (!def)
@@ -401,6 +416,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
     case VIR_DOMAIN_DEVICE_SOUND:
         virDomainSoundDefFree(def->data.sound);
         break;
+    case VIR_DOMAIN_DEVICE_VIDEO:
+        virDomainVideoDefFree(def->data.video);
+        break;
     case VIR_DOMAIN_DEVICE_HOSTDEV:
         virDomainHostdevDefFree(def->data.hostdev);
         break;
@@ -458,6 +476,10 @@ void virDomainDefFree(virDomainDefPtr def)
         virDomainSoundDefFree(def->sounds[i]);
     VIR_FREE(def->sounds);
 
+    for (i = 0 ; i < def->nvideos ; i++)
+        virDomainVideoDefFree(def->videos[i]);
+    VIR_FREE(def->videos);
+
     for (i = 0 ; i < def->nhostdevs ; i++)
         virDomainHostdevDefFree(def->hostdevs[i]);
     VIR_FREE(def->hostdevs);
@@ -1653,6 +1675,84 @@ error:
     goto cleanup;
 }
 
+static virDomainVideoDefPtr
+virDomainVideoDefParseXML(virConnectPtr conn,
+                          const xmlNodePtr node,
+                          int flags ATTRIBUTE_UNUSED) {
+    virDomainVideoDefPtr def;
+    xmlNodePtr cur;
+    char *type = NULL;
+    char *heads = NULL;
+    char *vram = NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError(conn);
+        return NULL;
+    }
+
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            if ((type == NULL) && (vram == NULL) && (heads == NULL) &&
+                xmlStrEqual(cur->name, BAD_CAST "model")) {
+                type = virXMLPropString(cur, "type");
+                vram = virXMLPropString(cur, "vram");
+                heads = virXMLPropString(cur, "heads");
+            }
+        }
+        cur = cur->next;
+    }
+
+    if (type &&
+        (def->type = virDomainVideoTypeFromString(type)) < 0) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                             _("unknown video model '%s'"), type);
+        goto error;
+    }
+
+    if (vram &&
+        virStrToLong_ui(vram, NULL, 10, &def->vram) < 0) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot parse video ram '%s'"), vram);
+        goto error;
+    } else {
+        switch (def->type) {
+            /* Wierd, QEMU defaults to 9 MB ??! */
+        case VIR_DOMAIN_VIDEO_TYPE_VGA:
+        case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
+        case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
+            def->vram = 9 * 1024;
+            break;
+        case VIR_DOMAIN_VIDEO_TYPE_XEN:
+            /* Original PVFB hardcoded to 4 MB */
+            def->vram = 4 * 1024;
+            break;
+        }
+    }
+
+    if (heads &&
+        virStrToLong_ui(heads, NULL, 10, &def->heads) < 0) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot parse video heads '%s'"), heads);
+        goto error;
+    } else {
+        def->heads = 1;
+    }
+
+    VIR_FREE(type);
+    VIR_FREE(vram);
+    VIR_FREE(heads);
+
+    return def;
+
+error:
+    virDomainVideoDefFree(def);
+    VIR_FREE(type);
+    VIR_FREE(vram);
+    VIR_FREE(heads);
+    return NULL;
+}
+
 static int
 virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn,
                                      const xmlNodePtr node,
@@ -2091,6 +2191,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
         dev->type = VIR_DOMAIN_DEVICE_SOUND;
         if (!(dev->data.sound = virDomainSoundDefParseXML(conn, node, flags)))
             goto error;
+    } else if (xmlStrEqual(node->name, BAD_CAST "video")) {
+        dev->type = VIR_DOMAIN_DEVICE_VIDEO;
+        if (!(dev->data.video = virDomainVideoDefParseXML(conn, node, flags)))
+            goto error;
     } else if (xmlStrEqual(node->name, BAD_CAST "hostdev")) {
         dev->type = VIR_DOMAIN_DEVICE_HOSTDEV;
         if (!(dev->data.hostdev = virDomainHostdevDefParseXML(conn, node, flags)))
@@ -2649,6 +2753,49 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
     }
     VIR_FREE(nodes);
 
+    /* analysis of the video devices */
+    if ((n = virXPathNodeSet(conn, "./devices/video", ctxt, &nodes)) < 0) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("cannot extract video devices"));
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->videos, n) < 0)
+        goto no_memory;
+    for (i = 0 ; i < n ; i++) {
+        virDomainVideoDefPtr video = virDomainVideoDefParseXML(conn,
+                                                               nodes[i],
+                                                               flags);
+        if (!video)
+            goto error;
+        def->videos[def->nvideos++] = video;
+    }
+    VIR_FREE(nodes);
+
+    /* For backwards compatability, if no <video> tag is set but there
+     * is a <graphics> tag, then we add a single video tag */
+    if (def->ngraphics && !def->nvideos) {
+        virDomainVideoDefPtr video;
+        if (VIR_ALLOC(video) < 0)
+            goto no_memory;
+        switch (def->virtType) {
+        case VIR_DOMAIN_VIRT_XEN:
+            video->type = VIR_DOMAIN_VIDEO_TYPE_XEN;
+            video->vram = 1 * 1024;
+            video->heads = 1;
+            break;
+        default:
+            video->type = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
+            video->vram = 9 * 1024;
+            video->heads = 1;
+            break;
+        }
+        if (VIR_ALLOC_N(def->videos, 1) < 0) {
+            virDomainVideoDefFree(video);
+            goto no_memory;
+        }
+        def->videos[def->nvideos++] = video;
+    }
+
     /* analysis of the host devices */
     if ((n = virXPathNodeSet(conn, "./devices/hostdev", ctxt, &nodes)) < 0) {
         virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
@@ -3486,6 +3633,32 @@ virDomainSoundDefFormat(virConnectPtr conn,
 }
 
 static int
+virDomainVideoDefFormat(virConnectPtr conn,
+                        virBufferPtr buf,
+                        virDomainVideoDefPtr def)
+{
+    const char *model = virDomainVideoTypeToString(def->type);
+
+    if (!model) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                             _("unexpected video model %d"), def->type);
+        return -1;
+    }
+
+    virBufferAddLit(buf, "    <video>\n");
+    virBufferVSprintf(buf, "      <model type='%s'",
+                      model);
+    if (def->vram)
+        virBufferVSprintf(buf, " vram='%u'", def->vram);
+    if (def->heads)
+        virBufferVSprintf(buf, " heads='%u'", def->heads);
+    virBufferAddLit(buf, "/>\n");
+    virBufferAddLit(buf, "    </video>\n");
+
+    return 0;
+}
+
+static int
 virDomainInputDefFormat(virConnectPtr conn,
                         virBufferPtr buf,
                         virDomainInputDefPtr def)
@@ -3860,6 +4033,10 @@ char *virDomainDefFormat(virConnectPtr conn,
         if (virDomainSoundDefFormat(conn, &buf, def->sounds[n]) < 0)
             goto cleanup;
 
+    for (n = 0 ; n < def->nvideos ; n++)
+        if (virDomainVideoDefFormat(conn, &buf, def->videos[n]) < 0)
+            goto cleanup;
+
     for (n = 0 ; n < def->nhostdevs ; n++)
         if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n]) < 0)
             goto cleanup;
diff --git a/src/domain_conf.h b/src/domain_conf.h
index 51310c1..c150c9a 100644
--- a/src/domain_conf.h
+++ b/src/domain_conf.h
@@ -265,6 +265,25 @@ struct _virDomainSoundDef {
     int model;
 };
 
+
+enum virDomainVideoType {
+    VIR_DOMAIN_VIDEO_TYPE_VGA,
+    VIR_DOMAIN_VIDEO_TYPE_CIRRUS,
+    VIR_DOMAIN_VIDEO_TYPE_VMVGA,
+    VIR_DOMAIN_VIDEO_TYPE_XEN,
+
+    VIR_DOMAIN_VIDEO_TYPE_LAST
+};
+
+
+typedef struct _virDomainVideoDef virDomainVideoDef;
+typedef virDomainVideoDef *virDomainVideoDefPtr;
+struct _virDomainVideoDef {
+    int type;
+    unsigned int vram;
+    unsigned int heads;
+};
+
 /* 3 possible graphics console modes */
 enum virDomainGraphicsType {
     VIR_DOMAIN_GRAPHICS_TYPE_SDL,
@@ -361,6 +380,7 @@ enum virDomainDeviceType {
     VIR_DOMAIN_DEVICE_NET,
     VIR_DOMAIN_DEVICE_INPUT,
     VIR_DOMAIN_DEVICE_SOUND,
+    VIR_DOMAIN_DEVICE_VIDEO,
     VIR_DOMAIN_DEVICE_HOSTDEV,
 
     VIR_DOMAIN_DEVICE_LAST,
@@ -376,6 +396,7 @@ struct _virDomainDeviceDef {
         virDomainNetDefPtr net;
         virDomainInputDefPtr input;
         virDomainSoundDefPtr sound;
+        virDomainVideoDefPtr video;
         virDomainHostdevDefPtr hostdev;
     } data;
 };
@@ -492,6 +513,9 @@ struct _virDomainDef {
     int nsounds;
     virDomainSoundDefPtr *sounds;
 
+    int nvideos;
+    virDomainVideoDefPtr *videos;
+
     int nhostdevs;
     virDomainHostdevDefPtr *hostdevs;
 
@@ -557,6 +581,7 @@ void virDomainFSDefFree(virDomainFSDefPtr def);
 void virDomainNetDefFree(virDomainNetDefPtr def);
 void virDomainChrDefFree(virDomainChrDefPtr def);
 void virDomainSoundDefFree(virDomainSoundDefPtr def);
+void virDomainVideoDefFree(virDomainVideoDefPtr def);
 void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
 void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
 void virDomainDefFree(virDomainDefPtr vm);
@@ -683,6 +708,7 @@ VIR_ENUM_DECL(virDomainFS)
 VIR_ENUM_DECL(virDomainNet)
 VIR_ENUM_DECL(virDomainChr)
 VIR_ENUM_DECL(virDomainSoundModel)
+VIR_ENUM_DECL(virDomainVideo)
 VIR_ENUM_DECL(virDomainHostdevMode)
 VIR_ENUM_DECL(virDomainHostdevSubsys)
 VIR_ENUM_DECL(virDomainInput)
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index bbb4a3f..90ef42f 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -1530,6 +1530,27 @@ int qemudBuildCommandLine(virConnectPtr conn,
             ADD_ARG_LIT("-full-screen");
     }
 
+    /* Add video hardware */
+    if (def->nvideos == 1) {
+        const char *model = NULL;
+        switch (def->videos[0]->type) {
+        case VIR_DOMAIN_VIDEO_TYPE_VGA:
+            model = "std";
+            break;
+        case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
+            model = "cirrus";
+            break;
+        case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
+            model = "vmware";
+            break;
+        }
+
+        if (model) {
+            ADD_ARG_LIT("-vga");
+            ADD_ARG(model);
+        }
+    }
+
     /* Add sound hardware */
     if (def->nsounds) {
         int size = 100;

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]