diff --git a/README.md b/README.md index ce60cd5..8da6992 100644 --- a/README.md +++ b/README.md @@ -534,6 +534,28 @@ Vagrant.configure("2") do |config| end ``` +## USB device passthrough + +You can specify multiple USB devices to passthrough to the VM via `libvirt.usb`. The device can be specified by the following options: + +* `bus` - The USB bus ID, e.g. "1" +* `device` - The USB device ID, e.g. "2" +* `vendor` - The USB devices vendor ID (VID), e.g. "0x1234" +* `product` - The USB devices product ID (PID), e.g. "0xabcd" + +At least one of these has to be specified, and `bus` and `device` may only be used together. + +The example values above match the device from the following output of `lsusb`: + +``` +Bus 001 Device 002: ID 1234:abcd Example device +``` + +Additionally, the following options can be used: + +* `startupPolicy` - Is passed through to libvirt and controls if the device has to exist. + libvirt currently allows the following values: "mandatory", "requisite", "optional". + ## No box and PXE boot There is support for PXE booting VMs with no disks as well as PXE booting VMs with blank disks. There are some limitations: diff --git a/lib/vagrant-libvirt/action/create_domain.rb b/lib/vagrant-libvirt/action/create_domain.rb index a470cc7..f704bb9 100644 --- a/lib/vagrant-libvirt/action/create_domain.rb +++ b/lib/vagrant-libvirt/action/create_domain.rb @@ -72,6 +72,9 @@ module VagrantPlugins # PCI device passthrough @pcis = config.pcis + # USB device passthrough + @usbs = config.usbs + config = env[:machine].provider_config @domain_type = config.driver @@ -192,6 +195,15 @@ module VagrantPlugins env[:ui].info(" -- PCI passthrough: #{pci[:bus]}:#{pci[:slot]}.#{pci[:function]}") end + @usbs.each do |usb| + usb_dev = [] + usb_dev.push("bus=#{usb[:bus]}") if usb[:bus] + usb_dev.push("device=#{usb[:device]}") if usb[:device] + usb_dev.push("vendor=#{usb[:vendor]}") if usb[:vendor] + usb_dev.push("product=#{usb[:product]}") if usb[:product] + env[:ui].info(" -- USB passthrough: #{usb_dev.join(', ')}") + end + env[:ui].info(" -- Command line : #{@cmd_line}") # Create libvirt domain. diff --git a/lib/vagrant-libvirt/config.rb b/lib/vagrant-libvirt/config.rb index 3f777b0..95ccc58 100644 --- a/lib/vagrant-libvirt/config.rb +++ b/lib/vagrant-libvirt/config.rb @@ -94,6 +94,9 @@ module VagrantPlugins # PCI device passthrough attr_accessor :pcis + # USB device passthrough + attr_accessor :usbs + # Suspend mode attr_accessor :suspend_mode @@ -152,6 +155,9 @@ module VagrantPlugins # PCI device passthrough @pcis = UNSET_VALUE + # USB device passthrough + @usbs = UNSET_VALUE + # Suspend mode @suspend_mode = UNSET_VALUE end @@ -222,6 +228,24 @@ module VagrantPlugins }) end + def usb(options={}) + if (options[:bus].nil? || options[:device].nil?) && options[:vendor].nil? && options[:product].nil? + raise 'Bus and device and/or vendor and/or product must be specified. Check `lsusb` for these.' + end + + if @usbs == UNSET_VALUE + @usbs = [] + end + + @usbs.push({ + bus: options[:bus], + device: options[:device], + vendor: options[:vendor], + product: options[:product], + startupPolicy: options[:startupPolicy], + }) + end + # NOTE: this will run twice for each time it's needed- keep it idempotent def storage(storage_type, options={}) if storage_type == :file @@ -389,6 +413,12 @@ module VagrantPlugins # Inputs @inputs = [{:type => "mouse", :bus => "ps2"}] if @inputs == UNSET_VALUE + # PCI device passthrough + @pcis = [] if @pcis == UNSET_VALUE + + # USB device passthrough + @usbs = [] if @usbs == UNSET_VALUE + # Suspend mode @suspend_mode = "pause" if @suspend_mode == UNSET_VALUE diff --git a/lib/vagrant-libvirt/templates/domain.xml.erb b/lib/vagrant-libvirt/templates/domain.xml.erb index f3ac41d..e2d8a5f 100644 --- a/lib/vagrant-libvirt/templates/domain.xml.erb +++ b/lib/vagrant-libvirt/templates/domain.xml.erb @@ -102,5 +102,20 @@ <% end %> + <% @usbs.each do |usb| %> + + + <% if usb[:vendor] %> + + <% end %> + <% if usb[:product] %> + + <% end %> + <% if usb[:bus] && usb[:device] %> +
+ <% end %> + + + <% end %>