]>
Commit | Line | Data |
---|---|---|
de3d4ac4 DC |
1 | package PVE::QemuServer::USB; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | use PVE::QemuServer::PCI qw(print_pci_addr); | |
6 | use PVE::JSONSchema; | |
7 | use base 'Exporter'; | |
8 | ||
9 | our @EXPORT_OK = qw( | |
10 | parse_usb_device | |
11 | get_usb_controllers | |
12 | get_usb_devices | |
13 | ); | |
14 | ||
15 | sub parse_usb_device { | |
16 | my ($value) = @_; | |
17 | ||
18 | return undef if !$value; | |
19 | ||
20 | my $res = {}; | |
21 | if ($value =~ m/^(0x)?([0-9A-Fa-f]{4}):(0x)?([0-9A-Fa-f]{4})$/) { | |
22 | $res->{vendorid} = $2; | |
23 | $res->{productid} = $4; | |
24 | } elsif ($value =~ m/^(\d+)\-(\d+(\.\d+)*)$/) { | |
25 | $res->{hostbus} = $1; | |
26 | $res->{hostport} = $2; | |
27 | } elsif ($value =~ m/^spice$/i) { | |
28 | $res->{spice} = 1; | |
29 | } else { | |
30 | return undef; | |
31 | } | |
32 | ||
33 | return $res; | |
34 | } | |
35 | ||
36 | sub get_usb_controllers { | |
d559309f | 37 | my ($conf, $bridges, $arch, $machine, $format, $max_usb_devices) = @_; |
de3d4ac4 DC |
38 | |
39 | my $devices = []; | |
40 | my $pciaddr = ""; | |
41 | ||
d559309f WB |
42 | if ($arch eq 'aarch64') { |
43 | $pciaddr = print_pci_addr('ehci', $bridges, $arch, $machine); | |
44 | push @$devices, '-device', "usb-ehci,id=ehci$pciaddr"; | |
7583d156 | 45 | } elsif ($machine !~ /q35/) { # FIXME: combine this and machine_type_is_q35 |
d559309f | 46 | $pciaddr = print_pci_addr("piix3", $bridges, $arch, $machine); |
de3d4ac4 DC |
47 | push @$devices, '-device', "piix3-usb-uhci,id=uhci$pciaddr.0x2"; |
48 | ||
49 | my $use_usb2 = 0; | |
50 | for (my $i = 0; $i < $max_usb_devices; $i++) { | |
51 | next if !$conf->{"usb$i"}; | |
52 | my $d = eval { PVE::JSONSchema::parse_property_string($format,$conf->{"usb$i"}) }; | |
53 | next if !$d || $d->{usb3}; # do not add usb2 controller if we have only usb3 devices | |
54 | $use_usb2 = 1; | |
55 | } | |
56 | # include usb device config | |
57 | push @$devices, '-readconfig', '/usr/share/qemu-server/pve-usb.cfg' if $use_usb2; | |
58 | } | |
59 | ||
60 | # add usb3 controller if needed | |
61 | ||
62 | my $use_usb3 = 0; | |
63 | for (my $i = 0; $i < $max_usb_devices; $i++) { | |
64 | next if !$conf->{"usb$i"}; | |
65 | my $d = eval { PVE::JSONSchema::parse_property_string($format,$conf->{"usb$i"}) }; | |
66 | next if !$d || !$d->{usb3}; | |
67 | $use_usb3 = 1; | |
68 | } | |
69 | ||
d559309f | 70 | $pciaddr = print_pci_addr("xhci", $bridges, $arch, $machine); |
de3d4ac4 DC |
71 | push @$devices, '-device', "nec-usb-xhci,id=xhci$pciaddr" if $use_usb3; |
72 | ||
73 | return @$devices; | |
74 | } | |
75 | ||
76 | sub get_usb_devices { | |
77 | my ($conf, $format, $max_usb_devices) = @_; | |
78 | ||
79 | my $devices = []; | |
80 | ||
81 | for (my $i = 0; $i < $max_usb_devices; $i++) { | |
82 | next if !$conf->{"usb$i"}; | |
83 | my $d = eval { PVE::JSONSchema::parse_property_string($format,$conf->{"usb$i"}) }; | |
84 | next if !$d; | |
85 | ||
86 | if (defined($d->{host})) { | |
87 | my $hostdevice = parse_usb_device($d->{host}); | |
88 | $hostdevice->{usb3} = $d->{usb3}; | |
89 | if (defined($hostdevice->{spice}) && $hostdevice->{spice}) { | |
90 | # usb redir support for spice, currently no usb3 | |
91 | push @$devices, '-chardev', "spicevmc,id=usbredirchardev$i,name=usbredir"; | |
92 | push @$devices, '-device', "usb-redir,chardev=usbredirchardev$i,id=usbredirdev$i,bus=ehci.0"; | |
93 | } else { | |
94 | push @$devices, '-device', print_usbdevice_full($conf, "usb$i", $hostdevice); | |
95 | } | |
96 | } | |
97 | } | |
98 | ||
99 | return @$devices; | |
100 | } | |
101 | ||
102 | sub print_usbdevice_full { | |
103 | my ($conf, $deviceid, $device) = @_; | |
104 | ||
105 | return if !$device; | |
106 | my $usbdevice = "usb-host"; | |
107 | ||
108 | # if it is a usb3 device, attach it to the xhci controller, else omit the bus option | |
109 | if($device->{usb3}) { | |
110 | $usbdevice .= ",bus=xhci.0"; | |
111 | } | |
112 | ||
113 | if (defined($device->{vendorid}) && defined($device->{productid})) { | |
114 | $usbdevice .= ",vendorid=0x$device->{vendorid},productid=0x$device->{productid}"; | |
115 | } elsif (defined($device->{hostbus}) && defined($device->{hostport})) { | |
116 | $usbdevice .= ",hostbus=$device->{hostbus},hostport=$device->{hostport}"; | |
117 | } | |
118 | ||
119 | $usbdevice .= ",id=$deviceid"; | |
120 | return $usbdevice; | |
121 | } | |
122 | ||
123 | 1; |