I've had a discussion with some colleagues whether USB is polling-based or interrupt-driven. Some claim USB keyboards involve larger overhead than i.e. PS/2 keyboards due to the requirement of former being polled by the main CPU. Now, with today's typical CPU speeds it would probably be a small amount of CPU-time spent in either case, but it is still interesting to know.
I've tried to find out myself. I suspect the answer could be dependent on the USB host controller interface. I looked specifically at UHCI which is one of the original standards and is rather simple to understand (ftp://ftp.netbsd.org/pub/NetBSD/misc/blymn/uhci11d.pdf). Based on my reading of this, it seems it could be argued both ways whether USB devices are polling based or not.
So here some facts I've gathered from reading the UHCI spec:
1) It's true a USB device (at least prior to USB 3.0 which is what applies to most/all keyboards) can't actively send an interrupt. They can only answer a query whether there is a pending interrupt. Hence, this query has to be sent periodically.
So far, point 1 suggests it is indeed polling-based. But then we have:
2) It is not the CPU itself which sends the queries, but rather the host controller.
3) The main CPU does, however, have to program the host controller, by laying out a detailed schedule of what happens in each ms.
4) The UHCI host controller can send interrupts to the main CPU to alert it of completed transfers. Hence, the main CPU doesn't need to poll for completion of transfers.
So now it would seem (and this is what some colleagues argued) that from the point-of-view of the main CPU, USB isn't polling based anyway. It is the host controller that periodically polls, and then delivers the interrupts to the main CPU. This wouldn't be so bad, because the host controller doesn't have other jobs, so it's not a problem it is doing this polling.
But unfortunately, I don't think this is really the case after all, because:
5) According to my reading of UHCI, there is no way the main CPU can configure a UHCI controller and USB keyboard such that once it is configured, the main CPU will not have to do further work until something happens, e.g. the user presses a key and the keyboard sets a pending interrupt which is delivered to the host controller and ultimately host as specified above. According to my reading, the main CPU has to continuously "work" to keep it up and running. There are as I see it two reasons for this:
- Transfer descriptors have an Interrupt-on-completion bit that can be set so that the main CPU is interrupted upon completion of the transfer. So far so good, but unfortunately there's no way to differentiate between positive and negative answers to interrupt queries, so this means the main CPU will be interrupted every time a device is queried about interrupt status, no matter whether it has a pending interrupt or not.
- The schedule cannot be reused. Each transfer descriptor has an ACTIVE bit that must be set to 1 for the host controller to execute it. The host controller sets it 0 after it has been executed. As a result, the main CPU will have to periodically go through the transfer descriptors and set them back to active, so that they will be executed again.
So even though it seems UHCI has the potential to deliver interrupts "for free" to the main CPU, it seems the above two points ruin it and means that even if the main CPU doesn't have to be engaged in out-right polling of the keyboard, it still has to periodically reschedule the polling, even in the case of no events. Which means it is sort of engaging in polling.
I'm really interested if someone could validate these observations, especially the two bullet points above. Bonus points if someone can point out how OHCI, EHCI, and XHCI differ in these aspects!