From de3d4ac4d4700cda969c8cfd150ab9e3b182abf9 Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Tue, 14 Jun 2016 10:50:36 +0200 Subject: [PATCH] refactor usb functions out of QemuServer.pm this moves most of the usb functionality into its own module, making the QemuServer.pm smaller Signed-off-by: Dominik Csapak --- PVE/QemuServer/Makefile | 1 + PVE/QemuServer/USB.pm | 124 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 PVE/QemuServer/USB.pm diff --git a/PVE/QemuServer/Makefile b/PVE/QemuServer/Makefile index f105d0a..06617c5 100644 --- a/PVE/QemuServer/Makefile +++ b/PVE/QemuServer/Makefile @@ -1,4 +1,5 @@ .PHONY: install install: install -D -m 0644 PCI.pm ${DESTDIR}${PERLDIR}/PVE/QemuServer/PCI.pm + install -D -m 0644 USB.pm ${DESTDIR}${PERLDIR}/PVE/QemuServer/USB.pm install -D -m 0644 Memory.pm ${DESTDIR}${PERLDIR}/PVE/QemuServer/Memory.pm diff --git a/PVE/QemuServer/USB.pm b/PVE/QemuServer/USB.pm new file mode 100644 index 0000000..599641e --- /dev/null +++ b/PVE/QemuServer/USB.pm @@ -0,0 +1,124 @@ +package PVE::QemuServer::USB; + +use strict; +use warnings; +use PVE::QemuServer::PCI qw(print_pci_addr); +use PVE::JSONSchema; +use base 'Exporter'; + +our @EXPORT_OK = qw( +parse_usb_device +get_usb_controllers +get_usb_devices +); + +sub parse_usb_device { + my ($value) = @_; + + return undef if !$value; + + my $res = {}; + 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 $res; +} + +sub get_usb_controllers { + my ($conf, $bridges, $isq35, $format, $max_usb_devices) = @_; + + my $devices = []; + my $pciaddr = ""; + + if ($isq35) { + # the q35 chipset support native usb2, so we enable usb controller + # by default for this machine type + push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg'; + } else { + $pciaddr = print_pci_addr("piix3", $bridges); + push @$devices, '-device', "piix3-usb-uhci,id=uhci$pciaddr.0x2"; + + my $use_usb2 = 0; + for (my $i = 0; $i < $max_usb_devices; $i++) { + next if !$conf->{"usb$i"}; + my $d = eval { PVE::JSONSchema::parse_property_string($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 + push @$devices, '-readconfig', '/usr/share/qemu-server/pve-usb.cfg' if $use_usb2; + } + + # add usb3 controller if needed + + my $use_usb3 = 0; + for (my $i = 0; $i < $max_usb_devices; $i++) { + next if !$conf->{"usb$i"}; + my $d = eval { PVE::JSONSchema::parse_property_string($format,$conf->{"usb$i"}) }; + next if !$d || !$d->{usb3}; + $use_usb3 = 1; + } + + $pciaddr = print_pci_addr("xhci", $bridges); + push @$devices, '-device', "nec-usb-xhci,id=xhci$pciaddr" if $use_usb3; + + return @$devices; +} + +sub get_usb_devices { + my ($conf, $format, $max_usb_devices) = @_; + + my $devices = []; + + for (my $i = 0; $i < $max_usb_devices; $i++) { + next if !$conf->{"usb$i"}; + my $d = eval { PVE::JSONSchema::parse_property_string($format,$conf->{"usb$i"}) }; + next if !$d; + + if (defined($d->{host})) { + my $hostdevice = parse_usb_device($d->{host}); + $hostdevice->{usb3} = $d->{usb3}; + if (defined($hostdevice->{spice}) && $hostdevice->{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"; + } else { + push @$devices, '-device', print_usbdevice_full($conf, "usb$i", $hostdevice); + } + } + } + + return @$devices; +} + +sub print_usbdevice_full { + my ($conf, $deviceid, $device) = @_; + + return if !$device; + my $usbdevice = "usb-host"; + + # if it is a usb3 device, attach it to the xhci controller, else omit the bus option + if($device->{usb3}) { + $usbdevice .= ",bus=xhci.0"; + } + + if (defined($device->{vendorid}) && defined($device->{productid})) { + $usbdevice .= ",vendorid=0x$device->{vendorid},productid=0x$device->{productid}"; + } elsif (defined($device->{hostbus}) && defined($device->{hostport})) { + $usbdevice .= ",hostbus=$device->{hostbus},hostport=$device->{hostport}"; + } + + $usbdevice .= ",id=$deviceid"; + return $usbdevice; +} + +1; -- 2.39.2