diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 8002512c..1b5f81fb 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -727,16 +727,31 @@ my $alldrive_fmt = { %queues_fmt, }; +my $usbformat = { + host => { + default_key => 1, + type => 'string', format => 'pve-qm-usb-device', + format_description => 'HOSTUSBDEVICE|spice', + description => 'The Host USB device or port or the value spice', + }, + usb3 => { + optional => 1, + type => 'boolean', + format_description => 'yes|no', + description => 'Specifies whether if given host option is a USB3 device or port', + }, +}; + my $usbdesc = { optional => 1, - type => 'string', format => 'pve-qm-usb-device', - typetext => 'host=HOSTUSBDEVICE [,usb3=yes|no]|spice', + type => 'string', format => $usbformat, description => <{vendorid} = $2; - $res->{productid} = $4; - } elsif ($v =~ m/^host=(\d+)\-(\d+(\.\d+)*)$/) { - $found = 1; - $res->{hostbus} = $1; - $res->{hostport} = $2; - } elsif ($v =~ m/^spice$/) { - $found = 1; - $res->{spice} = 1; - } elsif ($v =~ m/^usb3=yes$/) { - $res->{usb3} = 1; - } else { - return undef; - } + if ($value =~ m/^(0x)?([0-9A-Fa-f]{4}):(0x)?([0-9A-Fa-f]{4})$/) { + $res->{vendorid} = $2; + $res->{productid} = $4; + } elsif ($value =~ m/^(\d+)\-(\d+(\.\d+)*)$/) { + $res->{hostbus} = $1; + $res->{hostport} = $2; + } elsif ($value =~ m/^spice$/i) { + $res->{spice} = 1; + } else { + return undef; } - return undef if !$found; return $res; } @@ -2847,8 +2851,8 @@ sub config_to_command { my $use_usb2 = 0; for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) { next if !$conf->{"usb$i"}; - my $d = parse_usb_device($conf->{"usb$i"}); - next if $d->{usb3}; # do not add usb2 controller if we have only usb3 devices + my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format},$conf->{"usb$i"}) }; + next if !$d || $d->{usb3}; # do not add usb2 controller if we have only usb3 devices $use_usb2 = 1; } # include usb device config @@ -2860,8 +2864,8 @@ sub config_to_command { my $use_usb3 = 0; for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) { next if !$conf->{"usb$i"}; - my $d = parse_usb_device($conf->{"usb$i"}); - next if !$d->{usb3}; + my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format},$conf->{"usb$i"}) }; + next if !$d || !$d->{usb3}; $use_usb3 = 1; } @@ -2944,23 +2948,27 @@ sub config_to_command { # usb devices for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) { - my $d = parse_usb_device($conf->{"usb$i"}); + next if !$conf->{"usb$i"}; + my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format},$conf->{"usb$i"}) }; next if !$d; # if it is a usb3 device, attach it to the xhci controller, else omit the bus option my $usbbus = ''; - if ($d->{usb3}) { + if (defined($d->{usb3}) && $d->{usb3}) { $usbbus = ',bus=xhci.0'; } - if ($d->{vendorid} && $d->{productid}) { - push @$devices, '-device', "usb-host$usbbus,vendorid=0x$d->{vendorid},productid=0x$d->{productid}"; - } elsif (defined($d->{hostbus}) && defined($d->{hostport})) { - push @$devices, '-device', "usb-host$usbbus,hostbus=$d->{hostbus},hostport=$d->{hostport}"; - } elsif ($d->{spice}) { - # usb redir support for spice, currently no usb3 - push @$devices, '-chardev', "spicevmc,id=usbredirchardev$i,name=usbredir"; - push @$devices, '-device', "usb-redir,chardev=usbredirchardev$i,id=usbredirdev$i,bus=ehci.0"; + if (defined($d->{host})) { + $d = parse_usb_device($d->{host}); + if (defined($d->{vendorid}) && defined($d->{productid})) { + push @$devices, '-device', "usb-host$usbbus,vendorid=0x$d->{vendorid},productid=0x$d->{productid}"; + } elsif (defined($d->{hostbus}) && defined($d->{hostport})) { + push @$devices, '-device', "usb-host$usbbus,hostbus=$d->{hostbus},hostport=$d->{hostport}"; + } elsif (defined($d->{spice}) && $d->{spice}) { + # usb redir support for spice, currently no usb3 + push @$devices, '-chardev', "spicevmc,id=usbredirchardev$i,name=usbredir"; + push @$devices, '-device', "usb-redir,chardev=usbredirchardev$i,id=usbredirdev$i,bus=ehci.0"; + } } }