diff --git a/ChangeLog b/ChangeLog index 0586adb64a..c8d3a17876 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Wed Jul 18 16:42:08 EST 2007 Daniel P. Berrange + + * src/qemu_conf.c, src/qemu_conf.h, src/xm_internal.c, + src/xend_internal.c, src/xml.c: Added support for input devices + using element. + * tests/sexpr2xmltest.c, tests/xmconfigtest.c, + tests/xml2sexprtest.c: Add new tests for input devices + * tests/test_utils.c, src/test_utils.h: the virTestRun callback + uses a const void * instead of void * + * tests/virshtest.c, tests/xencaptest.c: Switch to const void * + * tests/sexpr2xmldata/*, tests/xmconfigdata/*, tests/xml2sexprdata/* + Updated data files to take account of new input device syntax + Wed Jul 18 12:10:08 CEST 2007 Daniel Veillard * src/test.c include/libvirt/libvirt.h include/libvirt/libvirt.h.in: diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 666c3aeaac..fcedc12c0e 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -806,6 +806,74 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(virConnectPtr conn, } +/* Parse the XML definition for a network interface */ +static struct qemud_vm_input_def *qemudParseInputXML(virConnectPtr conn, + struct qemud_driver *driver ATTRIBUTE_UNUSED, + xmlNodePtr node) { + struct qemud_vm_input_def *input = calloc(1, sizeof(struct qemud_vm_input_def)); + xmlChar *type = NULL; + xmlChar *bus = NULL; + + if (!input) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "input"); + return NULL; + } + + type = xmlGetProp(node, BAD_CAST "type"); + bus = xmlGetProp(node, BAD_CAST "bus"); + + if (!type) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "no type provide for input device"); + goto error; + } + + if (!strcmp((const char *)type, "mouse")) { + input->type = QEMU_INPUT_TYPE_MOUSE; + } else if (!strcmp((const char *)type, "tablet")) { + input->type = QEMU_INPUT_TYPE_TABLET; + } else { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "unsupported input device type %s", (const char*)type); + goto error; + } + + if (bus) { + if (!strcmp((const char*)bus, "ps2")) { /* Only allow mouse */ + if (input->type == QEMU_INPUT_TYPE_TABLET) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "ps2 bus does not support %s input device", (const char*)type); + goto error; + } + input->bus = QEMU_INPUT_BUS_PS2; + } else if (!strcmp((const char *)bus, "usb")) { /* Allow mouse & keyboard */ + input->bus = QEMU_INPUT_BUS_USB; + } else { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "unsupported input bus %s", (const char*)bus); + goto error; + } + } else { + if (input->type == QEMU_INPUT_TYPE_MOUSE) + input->bus = QEMU_INPUT_BUS_PS2; + else + input->bus = QEMU_INPUT_BUS_USB; + } + + if (type) + xmlFree(type); + if (bus) + xmlFree(bus); + + return input; + + error: + if (type) + xmlFree(type); + if (bus) + xmlFree(bus); + + free(input); + return NULL; +} + + /* * Parses a libvirt XML definition of a guest, and populates the * the qemud_vm struct with matching data about the guests config @@ -1193,6 +1261,61 @@ static struct qemud_vm_def *qemudParseXML(virConnectPtr conn, } } xmlXPathFreeObject(obj); + + /* analysis of the input devices */ + obj = xmlXPathEval(BAD_CAST "/domain/devices/input", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { + struct qemud_vm_input_def *prev = NULL; + for (i = 0; i < obj->nodesetval->nodeNr; i++) { + struct qemud_vm_input_def *input; + if (!(input = qemudParseInputXML(conn, driver, obj->nodesetval->nodeTab[i]))) { + goto error; + } + /* Mouse + PS/2 is implicit with graphics, so don't store it */ + if (input->bus == QEMU_INPUT_BUS_PS2 && + input->type == QEMU_INPUT_TYPE_MOUSE) { + free(input); + continue; + } + def->ninputs++; + input->next = NULL; + if (i == 0) { + def->inputs = input; + } else { + prev->next = input; + } + prev = input; + } + } + xmlXPathFreeObject(obj); + obj = NULL; + + /* If graphics are enabled, there's an implicit PS2 mouse */ + if (def->graphicsType != QEMUD_GRAPHICS_NONE) { + int hasPS2mouse = 0; + struct qemud_vm_input_def *input = def->inputs; + while (input) { + if (input->type == QEMU_INPUT_TYPE_MOUSE && + input->bus == QEMU_INPUT_BUS_PS2) + hasPS2mouse = 1; + input = input->next; + } + + if (!hasPS2mouse) { + input = calloc(1, sizeof(struct qemud_vm_input_def)); + if (!input) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "input"); + goto error; + } + input->type = QEMU_INPUT_TYPE_MOUSE; + input->bus = QEMU_INPUT_BUS_PS2; + input->next = def->inputs; + def->inputs = input; + def->ninputs++; + } + } + xmlXPathFreeContext(ctxt); return def; @@ -1307,6 +1430,7 @@ int qemudBuildCommandLine(virConnectPtr conn, struct stat sb; struct qemud_vm_disk_def *disk = vm->def->disks; struct qemud_vm_net_def *net = vm->def->nets; + struct qemud_vm_input_def *input = vm->def->inputs; struct utsname ut; int disableKQEMU = 0; @@ -1348,6 +1472,8 @@ int qemudBuildCommandLine(virConnectPtr conn, disableKQEMU + /* Disable kqemu */ 2 * vm->def->ndisks + /* disks*/ (vm->def->nnets > 0 ? (4 * vm->def->nnets) : 2) + /* networks */ + 1 + /* usb */ + 2 * vm->def->ninputs + /* input devices */ 2 + /* memory*/ 2 + /* cpus */ 2 + /* boot device */ @@ -1561,6 +1687,19 @@ int qemudBuildCommandLine(virConnectPtr conn, } } + if (!((*argv)[++n] = strdup("-usb"))) + goto no_memory; + while (input) { + if (input->bus == QEMU_INPUT_BUS_USB) { + if (!((*argv)[++n] = strdup("-usbdevice"))) + goto no_memory; + if (!((*argv)[++n] = strdup(input->type == QEMU_INPUT_TYPE_MOUSE ? "mouse" : "tablet"))) + goto no_memory; + } + + input = input->next; + } + if (vm->def->graphicsType == QEMUD_GRAPHICS_VNC) { char port[10]; int ret; @@ -2541,6 +2680,7 @@ char *qemudGenerateXML(virConnectPtr conn, unsigned char *uuid; struct qemud_vm_disk_def *disk; struct qemud_vm_net_def *net; + struct qemud_vm_input_def *input; const char *type = NULL; int n; @@ -2769,6 +2909,19 @@ char *qemudGenerateXML(virConnectPtr conn, net = net->next; } + input = def->inputs; + while (input) { + if (input->bus != QEMU_INPUT_BUS_PS2 && + virBufferVSprintf(buf, " \n", + input->type == QEMU_INPUT_TYPE_MOUSE ? "mouse" : "tablet") < 0) + goto no_memory; + input = input->next; + } + /* If graphics is enable, add implicit mouse */ + if (def->graphicsType != QEMUD_GRAPHICS_NONE) + if (virBufferAdd(buf, " \n", -1) < 0) + goto no_memory; + switch (def->graphicsType) { case QEMUD_GRAPHICS_VNC: if (virBufferAdd(buf, " \n", hvm ? "ps2": "xen"); virBufferAdd(&buf, " \n", 27); } else if (tmp && !strcmp(tmp, "vnc")) { int port = xenStoreDomainGetVNCPort(conn, domid); const char *listenAddr = sexpr_node(node, "device/vfb/vnclisten"); const char *keymap = sexpr_node(node, "device/vfb/keymap"); + virBufferVSprintf(&buf, " \n", hvm ? "ps2": "xen"); virBufferVSprintf(&buf, " kind == SEXPR_CONS; cur = cur->cdr) { + node = cur->car; + if (sexpr_lookup(node, "usbdevice")) { + tmp = sexpr_node(node, "usbdevice"); + if (tmp && *tmp) { + if (!strcmp(tmp, "usbtablet")) + virBufferAdd(&buf, " \n", 37); + else if (!strcmp(tmp, "usbmouse")) + virBufferAdd(&buf, " \n", 36); + } + } + } + } + /* Graphics device (HVM <= 3.0.4, or PV <= 3.0.3) vnc config */ if ((hvm && xendConfigVersion < 4) || (!hvm && xendConfigVersion < 3)) { @@ -1713,6 +1731,7 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, int xendConfigVersi */ if (port == -1 && xendConfigVersion < 2) port = 5900 + domid; + virBufferVSprintf(&buf, " \n", hvm ? "ps2" : "xen"); virBufferVSprintf(&buf, " \n", hvm ? "ps2" : "xen"); virBufferAdd(&buf, " \n", 27 ); + } } } diff --git a/src/xm_internal.c b/src/xm_internal.c index c8fc1e35e1..e559e4e47d 100644 --- a/src/xm_internal.c +++ b/src/xm_internal.c @@ -913,6 +913,17 @@ char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf) { } } + if (hvm) { + if (xenXMConfigGetString(conf, "usbdevice", &str) == 0 && str) { + if (!strcmp(str, "tablet")) + virBufferAdd(buf, " \n", 37); + else if (!strcmp(str, "mouse")) + virBufferAdd(buf, " \n", 36); + /* Ignore else branch - probably some other non-input device we don't + support in libvirt yet */ + } + } + /* HVM guests, or old PV guests use this config format */ if (hvm || priv->xendConfigVersion < 3) { if (xenXMConfigGetInt(conf, "vnc", &val) == 0 && val) { @@ -980,6 +991,9 @@ char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf) { } } + if (vnc || sdl) { + virBufferVSprintf(buf, " \n", hvm ? "ps2":"xen"); + } if (vnc) { virBufferVSprintf(buf, " xendConfigVersion < 3) { diff --git a/src/xml.c b/src/xml.c index ae3c0cb359..d202d502f7 100644 --- a/src/xml.c +++ b/src/xml.c @@ -416,11 +416,12 @@ static int virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf, xmlXPathContextPtr ctxt, int vcpus, int xendConfigVersion) { xmlNodePtr cur, txt; + xmlNodePtr *nodes = NULL; xmlChar *type = NULL; xmlChar *loader = NULL; char bootorder[5]; int nbootorder = 0; - int res; + int res, nb_nodes; char *str; cur = node->children; @@ -540,6 +541,57 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf if (virXPathNode("/domain/features/pae", ctxt) != NULL) virBufferAdd(buf, "(pae 1)", 7); + virBufferAdd(buf, "(usb 1)", 7); + nb_nodes = virXPathNodeSet("/domain/devices/input", ctxt, &nodes); + if (nb_nodes > 0) { + int i; + for (i = 0; i < nb_nodes; i++) { + xmlChar *itype = NULL, *bus = NULL; + int isMouse = 1; + + itype = xmlGetProp(nodes[i], (xmlChar *)"type"); + + if (!itype) { + goto error; + } + if (!strcmp((const char *)itype, "tablet")) + isMouse = 0; + else if (strcmp((const char*)itype, "mouse")) { + xmlFree(itype); + virXMLError(conn, VIR_ERR_XML_ERROR, "input", 0); + goto error; + } + xmlFree(itype); + + bus = xmlGetProp(nodes[i], (xmlChar *)"bus"); + if (!bus) { + if (!isMouse) { + /* Nothing - implicit ps2 */ + } else { + virBufferAdd(buf, "(usbdevice tablet)", 13); + } + } else { + if (!strcmp((const char*)bus, "ps2")) { + if (!isMouse) { + xmlFree(bus); + virXMLError(conn, VIR_ERR_XML_ERROR, "input", 0); + goto error; + } + /* Nothing - implicit ps2 */ + } else if (!strcmp((const char*)bus, "usb")) { + if (isMouse) + virBufferAdd(buf, "(usbdevice mouse)", 17); + else + virBufferAdd(buf, "(usbdevice tablet)", 18); + } + } + xmlFree(bus); + } + free(nodes); + nodes = NULL; + } + + res = virXPathBoolean("count(domain/devices/console) > 0", ctxt); if (res < 0) { virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0); @@ -572,6 +624,8 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf return (0); error: + if (nodes) + free(nodes); return(-1); } diff --git a/tests/sexpr2xmldata/sexpr2xml-curmem.xml b/tests/sexpr2xmldata/sexpr2xml-curmem.xml index 55d49d32eb..d8f662d49d 100644 --- a/tests/sexpr2xmldata/sexpr2xml-curmem.xml +++ b/tests/sexpr2xmldata/sexpr2xml-curmem.xml @@ -25,6 +25,7 @@ + diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml b/tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml index 512580eb6a..4b58de74ec 100644 --- a/tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml +++ b/tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml @@ -33,6 +33,7 @@ + diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.sexpr b/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.sexpr new file mode 100644 index 0000000000..a93488fcdb --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.sexpr @@ -0,0 +1 @@ +(domain (domid 3)(name 'fvtest')(memory 400)(maxmem 400)(vcpus 1)(uuid 'b5d70dd275cdaca517769660b059d8bc')(on_poweroff 'destroy')(on_reboot 'restart')(on_crash 'restart')(image (hvm (kernel '/usr/lib/xen/boot/hvmloader')(device_model '/usr/lib64/xen/bin/qemu-dm')(boot c)(cdrom '/root/boot.iso')(acpi 1)(usbdevice usbmouse)(vnc 1)(keymap ja)))(device (vbd (dev 'ioemu:hda')(uname 'file:/root/foo.img')(mode 'w')))(device (vif (mac '00:16:3e:1b:b1:47')(bridge 'xenbr0')(script 'vif-bridge')(type ioemu)))) diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.xml b/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.xml new file mode 100644 index 0000000000..e96ecfab5c --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.xml @@ -0,0 +1,40 @@ + + fvtest + b5d70dd275cdaca517769660b059d8bc + + hvm + /usr/lib/xen/boot/hvmloader + + + 409600 + 1 + destroy + restart + restart + + + + + + /usr/lib64/xen/bin/qemu-dm + + + + + + + + +