<p dir="ltr">If I pass through 0:14, won't I loose USB on my host? I have a USB keyboard and mouse and need USB for other things like thumb drives.</p>
<p dir="ltr">Jon</p>
<div class="gmail_quote">On 23 Feb 2016 15:57, "Samuel Holland" <<a href="mailto:samuel@sholland.org">samuel@sholland.org</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello,<br>
<br>
On 02/23/2016 06:46 AM, Jonathan Scruggs wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
How can I pass through the USB ports to the guest so that the items<br>
plugged into the ports appear to the guest?<br>
</blockquote>
<br>
In short, "sudo setpci -s0:14.0 0xd0.W=0x0000" will pass through all of<br>
your ports.<br>
<br>
I was planning to write a blog post about it this month, but I haven't<br>
gotten to it yet, so I guess I'll write it here. I have been using this<br>
setup since December, and everything works without any issues. I had<br>
done like you (playing with the firmware options) and gotten nowhere; I<br>
finally found a Google+ post[0] (the user appears to have been deleted)<br>
with a link to the 9 series PCH datasheet[1], which has been immensely<br>
useful.<br>
<br>
I have only tried this with an AsRock Z97E-ITX/ac. It might not work on<br>
your board if your firmware disables switching ports (see section<br>
16.1.37). Your chipset datasheet is here[2]. The xHCI registers are in<br>
chapter 17 in your datasheet, so you will have to adapt the section<br>
references.<br>
<br>
Step 1: Map your USB ports<br>
==========================<br>
This is easiest to do if you turn USB3 (xHCI) off completely. First, you<br>
need to map your EHCI controllers to USB buses as seen by the kernel.<br>
These numbers can change when you reboot your machine, so do this after<br>
you have disabled USB3. Run `lspci` and look at the numbers after the<br>
EHCI controllers (#1/#2). Then run the command below. You should get<br>
similar output.<br>
<br>
$ readlink -f /sys/bus/usb/devices/usb?<br>
/sys/devices/pci0000:00/0000:00:14.0/usb1<br>
/sys/devices/pci0000:00/0000:00:1a.0/usb2<br>
/sys/devices/pci0000:00/0000:00:1d.0/usb3<br>
<br>
Run `watch lsusb -t` in a terminal. Take a flash drive/mouse/etc. and<br>
plug it into each port on your machine. There are 14 of them. If you<br>
cannot find some, they might be in a mini-PCIe or M.2 slot, or just not<br>
connected.<br>
<br>
Use the bus numbers you found earlier, and the output of lsusb, to map<br>
physical ports to logical ports on controllers. Eight of them will be on<br>
the EHCI controller marked #1, and the other six will be on #2. Now sort<br>
them, starting with EHCI #1 port 1, and ending with EHCI #2 port 6.<br>
<br>
Next you should turn USB3 back on in your firmware settings.<br>
<br>
Step 2: Pass through your controller<br>
====================================<br>
This is the easy part. Just add whichever controller you want to use in<br>
the VM to your libvirt XML or qemu command line. Personally, I only ever<br>
need to use USB2 devices in Windows, so I pass through both EHCI<br>
controllers. However, I believe the EHCI controllers on the PCH do not<br>
support MSI, so that may affect performance with devices like flash<br>
drives. With a keyboard or mouse, it shouldn't make any difference.<br>
<br>
Step 3: Route your USB ports<br>
============================<br>
Looking at section 16.1.36, we can connect individual ports to either<br>
the EHCI or xHCI controller. On your sorted list of ports, mark which<br>
ones you want to have available in the VM, and which ones you want to<br>
use on the host. This is switchable at runtime, so you can create<br>
several lists--I have some ports that are routed to EHCI all of the<br>
time, and others I toggle back and forth.<br>
<br>
Turn each list of port routes into a binary mask: 0 for each EHCI port,<br>
and 1 for each xHCI port. The least significant bit is EHCI #1 port 1.<br>
Extend it to 16 bits by setting the two most significant bits to 0. Then<br>
convert it to hexadecimal. It should be something between 0x0000 and<br>
0x3fff. Finally, run setpci (as root) to change the routing. Moved USB<br>
devices will reset immediately. The command is<br>
<br>
# setpci -s<xHCI PCI address> 0xd0.W=0x<the mask in hex><br>
<br>
For example, to move everything to the xHCI controller:<br>
<br>
# setpci -s0:14.0 0xd0.W=0x3fff<br>
<br>
Again, even though you are running this command to configure the xHCI<br>
controller, the bits are in the order the ports appear to the EHCI<br>
controllers. If, for some reason, you cannot turn off xHCI to find that<br>
order, use table 2-2 in section 2.2 to map xHCI ports (what you see in<br>
lsusb minus 1) to EHCI ports.<br>
<br>
If you are connecting a USB3 (blue) port to a EHCI controller, there's<br>
one additional step you (probably) need to take. You will need to either<br>
1) remember to never plug a USB3 device into the port, or 2) turn off<br>
USB3 on that port. See section 16.1.38 for the register to change. I<br>
have not needed to do this, so I am not certain, but I believe the port<br>
numbers here are as they appear to the xHCI controller.<br>
<br>
Step 4: Toggle your port mask<br>
=============================<br>
If you have more than one keyboard/mouse or a KVM switch or synergy, you<br>
are done. Personally, I use this method to avoid all of that, so I have<br>
to have a way to switch my keyboard back and forth while running the VM.<br>
The first step is to have a service running as root, that will run<br>
setpci for you when you tell it to switch ports. I use the following<br>
python script. You should only need to change the masks and port number<br>
(at the bottom). Hopefully it doesn't get mangled in the email.<br>
<br>
----------------SNIP----------------<br>
#!/usr/bin/env python3<br>
<br>
import socketserver<br>
import subprocess<br>
import syslog<br>
<br>
def change_usb_state(action):<br>
    global state<br>
    if action == state: return<br>
    if action == "toggle": action = "guest" if state == "host" else "host"<br>
    syslog.syslog("Setting xHCI port routing mask to {:#x}".format(masks[action]))<br>
    if subprocess.call(["setpci", "-s0:14.0", "0xd0.L=0x{:08x}".format(masks[action])]) == 0: state = action<br>
    else: syslog.syslog("Calling setpci failed. Assuming routing is unchanged.")<br>
<br>
class PCIHandler(socketserver.StreamRequestHandler):<br>
    def handle(self):<br>
        for line in self.rfile:<br>
            action = line.strip().decode("utf-8")<br>
            syslog.syslog("Got action request: {}".format(action))<br>
            if action in ["guest", "host", "toggle"]: change_usb_state(action)<br>
<br>
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): pass<br>
<br>
masks = { "guest": 0x0fc, "host": 0x0ff }<br>
state = "host"<br>
server = ThreadedTCPServer(("127.0.0.1", 10), PCIHandler)<br>
server.serve_forever()<br>
----------------SNIP----------------<br>
<br>
On Linux, you can then use netcat as any user to toggle your ports. I<br>
use i3, and have a key mapped like so, which toggles my USB ports and<br>
then locks my screen:<br>
<br>
----------------SNIP----------------<br>
bindsym Control+Mod1+Menu exec --no-startup-id busybox nc 127.0.0.1 10 <<< toggle; exec --no-startup-id slock<br>
----------------SNIP----------------<br>
<br>
The second part is to connect qemu to your service. (You could also have<br>
the service accept remote connections, but then anyone on your network<br>
could control your USB ports. I only recommend this if you have an<br>
isolated network to use with qemu, and you only have the service listen<br>
on that network.) The simple and secure way to do this is to connect a<br>
serial port in the VM to your service. I use Q35 and qemu directly; you<br>
will have to adapt this to libvirt yourself.<br>
<br>
----------------SNIP----------------<br>
    -device isa-serial,chardev=com1,index=0 \<br>
      -chardev socket,host=127.0.0.1,id=com1,port=10<br>
----------------SNIP----------------<br>
<br>
Third, you need some way to connect to the serial port from within the<br>
guest. On a Linux guest, you can use picocom, socat, etc. On Windows,<br>
the simple way is to use a PowerShell script:<br>
<br>
----------------SNIP----------------<br>
$port = New-Object System.IO.Ports.SerialPort COM1,115200,None,8,One<br>
$port.Open()<br>
$port.WriteLine("toggle")<br>
$port.Close()<br>
----------------SNIP----------------<br>
<br>
Personally, I use AutoHotKey to map the same key in Windows to switching<br>
my ports and locking my screen. I'd be happy to share it, but it is too<br>
long to paste here.<br>
<br>
Hopefully that should get you going. I apologize if this is too long,<br>
but I wanted to be thorough. It definitely took a weekend to get set up,<br>
but once it works, it is really rather seamless.<br>
<br>
[0] <a href="https://plus.google.com/wm/quevuelvamatt/app/basic/stream/z13ki3ixwvubfpk4e04chfi45r3lyv4zeiw" rel="noreferrer" target="_blank">https://plus.google.com/wm/quevuelvamatt/app/basic/stream/z13ki3ixwvubfpk4e04chfi45r3lyv4zeiw</a><br>
[1] <a href="http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/9-series-chipset-pch-datasheet.pdf" rel="noreferrer" target="_blank">http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/9-series-chipset-pch-datasheet.pdf</a><br>
[2] <a href="http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/x99-chipset-pch-datasheet.pdf" rel="noreferrer" target="_blank">http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/x99-chipset-pch-datasheet.pdf</a><br>
<br>
(See also sections 5.19-5.21 of the datasheet for more information.)<br>
<br>
--<br>
Regards,<br>
Samuel Holland <<a href="mailto:samuel@sholland.org" target="_blank">samuel@sholland.org</a>><br>
<br>
</blockquote></div>