qemu: add usb-serial support

Add an optional 'type' attribute to <target> element of serial port
device. There are two choices for its value, 'isa-serial' and
'usb-serial'. For backward compatibility, when attribute 'type' is
missing the 'isa-serial' will be chosen as before.

Libvirt XML sample

    <serial type='pty'>
      <target type='usb-serial' port='0'/>
      <address type='usb' bus='0' port='1'/>
    </serial>

qemu commandline:

qemu ${other_vm_args}              \
    -chardev pty,id=charserial0    \
    -device usb-serial,chardev=charserial0,id=serial0,bus=usb.0,port=1
This commit is contained in:
Guannan Ren 2013-01-05 13:25:36 +08:00
parent f8d478b6df
commit e3a04455fa
6 changed files with 98 additions and 9 deletions

View File

@ -3688,7 +3688,14 @@ qemu-kvm -net nic,model=? /dev/null
<p> <p>
<code>target</code> can have a <code>port</code> attribute, which <code>target</code> can have a <code>port</code> attribute, which
specifies the port number. Ports are numbered starting from 0. There are specifies the port number. Ports are numbered starting from 0. There are
usually 0, 1 or 2 serial ports. usually 0, 1 or 2 serial ports. There is also an optional
<code>type</code> attribute <span class="since">since 1.0.2</span>
which has two choices for its value, one is< code>isa-serial</code>,
the other is <code>usb-serial</code>. If <code>type</code> is missing,
<code>isa-serial</code> will be used by default. For <code>usb-serial</code>
an optional sub-element <code>&lt;address&gt;</code> with
<code>type='usb'</code> can tie the device to a particular controller,
<a href="#elementsAddress">documented above</a>.
</p> </p>
<h6><a name="elementCharConsole">Console</a></h6> <h6><a name="elementCharConsole">Console</a></h6>

View File

@ -2473,12 +2473,26 @@
</attribute> </attribute>
</define> </define>
<define name='qemucdevSerialTgtType'>
<attribute name='type'>
<choice>
<value>isa-serial</value>
<value>usb-serial</value>
</choice>
</attribute>
</define>
<define name="qemucdevTgtDef"> <define name="qemucdevTgtDef">
<element name="target"> <element name="target">
<interleave> <interleave>
<optional> <choice>
<ref name="qemucdevConsoleTgtType"/> <optional>
</optional> <ref name="qemucdevConsoleTgtType"/>
</optional>
<optional>
<ref name="qemucdevSerialTgtType"/>
</optional>
</choice>
<optional> <optional>
<attribute name="port"/> <attribute name="port"/>
</optional> </optional>

View File

@ -342,6 +342,11 @@ VIR_ENUM_IMPL(virDomainNetInterfaceLinkState, VIR_DOMAIN_NET_INTERFACE_LINK_STAT
"up", "up",
"down") "down")
VIR_ENUM_IMPL(virDomainChrSerialTarget,
VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST,
"isa-serial",
"usb-serial")
VIR_ENUM_IMPL(virDomainChrChannelTarget, VIR_ENUM_IMPL(virDomainChrChannelTarget,
VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST, VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST,
"none", "none",
@ -5466,6 +5471,9 @@ virDomainChrDefaultTargetType(virCapsPtr caps,
break; break;
case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL: case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
target = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA;
break;
case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL: case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
default: default:
/* No target type yet*/ /* No target type yet*/
@ -5478,7 +5486,8 @@ virDomainChrDefaultTargetType(virCapsPtr caps,
static int static int
virDomainChrTargetTypeFromString(virCapsPtr caps, virDomainChrTargetTypeFromString(virCapsPtr caps,
virDomainDefPtr def, virDomainDefPtr vmdef,
virDomainChrDefPtr def,
int devtype, int devtype,
const char *targetType) const char *targetType)
{ {
@ -5486,7 +5495,7 @@ virDomainChrTargetTypeFromString(virCapsPtr caps,
int target = 0; int target = 0;
if (!targetType) { if (!targetType) {
target = virDomainChrDefaultTargetType(caps, def, devtype); target = virDomainChrDefaultTargetType(caps, vmdef, devtype);
goto out; goto out;
} }
@ -5500,12 +5509,17 @@ virDomainChrTargetTypeFromString(virCapsPtr caps,
break; break;
case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL: case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
target = virDomainChrSerialTargetTypeFromString(targetType);
break;
case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL: case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
default: default:
/* No target type yet*/ /* No target type yet*/
break; break;
} }
def->targetTypeAttr = true;
out: out:
ret = target; ret = target;
return ret; return ret;
@ -5524,7 +5538,7 @@ virDomainChrDefParseTargetXML(virCapsPtr caps,
const char *portStr = NULL; const char *portStr = NULL;
if ((def->targetType = if ((def->targetType =
virDomainChrTargetTypeFromString(caps, vmdef, virDomainChrTargetTypeFromString(caps, vmdef, def,
def->deviceType, targetType)) < 0) { def->deviceType, targetType)) < 0) {
virReportError(VIR_ERR_XML_ERROR, virReportError(VIR_ERR_XML_ERROR,
_("unknown target type '%s' specified for character device"), _("unknown target type '%s' specified for character device"),
@ -5957,6 +5971,15 @@ virDomainChrDefParseXML(virCapsPtr caps,
if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0) if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
goto error; goto error;
if (def->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
def->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB &&
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("usb-serial requires address of usb type"));
goto error;
}
cleanup: cleanup:
VIR_FREE(type); VIR_FREE(type);
@ -7960,6 +7983,9 @@ virDomainChrTargetTypeToString(int deviceType,
case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE: case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
type = virDomainChrConsoleTargetTypeToString(targetType); type = virDomainChrConsoleTargetTypeToString(targetType);
break; break;
case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
type = virDomainChrSerialTargetTypeToString(targetType);
break;
default: default:
break; break;
} }
@ -13119,6 +13145,15 @@ virDomainChrDefFormat(virBufferPtr buf,
def->target.port); def->target.port);
break; break;
case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
if (def->targetTypeAttr) {
virBufferAsprintf(buf,
" <target type='%s' port='%d'/>\n",
virDomainChrTargetTypeToString(def->deviceType,
def->targetType),
def->target.port);
break;
}
default: default:
virBufferAsprintf(buf, " <target port='%d'/>\n", virBufferAsprintf(buf, " <target port='%d'/>\n",
def->target.port); def->target.port);
@ -14446,6 +14481,7 @@ virDomainDefFormatInternal(virDomainDefPtr def,
(n < def->nserials)) { (n < def->nserials)) {
memcpy(&console, def->serials[n], sizeof(console)); memcpy(&console, def->serials[n], sizeof(console));
console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE; console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
} else { } else {
memcpy(&console, def->consoles[n], sizeof(console)); memcpy(&console, def->consoles[n], sizeof(console));
} }

View File

@ -918,6 +918,13 @@ enum virDomainChrDeviceType {
VIR_DOMAIN_CHR_DEVICE_TYPE_LAST VIR_DOMAIN_CHR_DEVICE_TYPE_LAST
}; };
enum virDomainChrSerialTargetType {
VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA = 0,
VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB,
VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST
};
enum virDomainChrChannelTargetType { enum virDomainChrChannelTargetType {
VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_NONE = 0, VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_NONE = 0,
VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD, VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD,
@ -1005,6 +1012,8 @@ struct _virDomainChrSourceDef {
/* A complete character device, both host and domain views. */ /* A complete character device, both host and domain views. */
struct _virDomainChrDef { struct _virDomainChrDef {
int deviceType; int deviceType;
bool targetTypeAttr;
int targetType; int targetType;
union { union {
int port; /* parallel, serial, console */ int port; /* parallel, serial, console */
@ -2262,6 +2271,7 @@ VIR_ENUM_DECL(virDomainNetInterfaceLinkState)
VIR_ENUM_DECL(virDomainChrDevice) VIR_ENUM_DECL(virDomainChrDevice)
VIR_ENUM_DECL(virDomainChrChannelTarget) VIR_ENUM_DECL(virDomainChrChannelTarget)
VIR_ENUM_DECL(virDomainChrConsoleTarget) VIR_ENUM_DECL(virDomainChrConsoleTarget)
VIR_ENUM_DECL(virDomainChrSerialTarget)
VIR_ENUM_DECL(virDomainSmartcard) VIR_ENUM_DECL(virDomainSmartcard)
VIR_ENUM_DECL(virDomainChr) VIR_ENUM_DECL(virDomainChr)
VIR_ENUM_DECL(virDomainChrTcpProtocol) VIR_ENUM_DECL(virDomainChrTcpProtocol)

View File

@ -293,6 +293,8 @@ virDomainChrConsoleTargetTypeToString;
virDomainChrDefForeach; virDomainChrDefForeach;
virDomainChrDefFree; virDomainChrDefFree;
virDomainChrDefNew; virDomainChrDefNew;
virDomainChrSerialTargetTypeFromString;
virDomainChrSerialTargetTypeToString;
virDomainChrSourceDefCopy; virDomainChrSourceDefCopy;
virDomainChrSourceDefFree; virDomainChrSourceDefFree;
virDomainChrSpicevmcTypeFromString; virDomainChrSpicevmcTypeFromString;

View File

@ -7035,10 +7035,30 @@ qemuBuildChrDeviceStr(virDomainChrDefPtr serial,
if (qemuBuildDeviceAddressStr(&cmd, &serial->info, caps) < 0) if (qemuBuildDeviceAddressStr(&cmd, &serial->info, caps) < 0)
goto error; goto error;
} }
} else } else {
virBufferAsprintf(&cmd, "isa-serial,chardev=char%s,id=%s", virBufferAsprintf(&cmd, "%s,chardev=char%s,id=%s",
virDomainChrSerialTargetTypeToString(serial->targetType),
serial->info.alias, serial->info.alias); serial->info.alias, serial->info.alias);
if (serial->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB) {
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE_USB_SERIAL)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("usb-serial is not supported in this QEMU binary"));
goto error;
}
if (serial->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
serial->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("usb-serial requires address of usb type"));
goto error;
}
if (qemuBuildDeviceAddressStr(&cmd, &serial->info, caps) < 0)
goto error;
}
}
if (virBufferError(&cmd)) { if (virBufferError(&cmd)) {
virReportOOMError(); virReportOOMError();
goto error; goto error;