How can I force a USB device driver to call a specific HCI controller driver? - linux-kernel

I have looked into couple USB device driver code looks like they have to associates with PCI device(s) and when usb_submit_urb() is called in USB device driver, the urb structure has already been associated with specific HCI driver, then when usb_submit_urb() calls usb_hcd_submit_urb (), usb_hcd_submit_urb() will fetch hcd from the parameter urb then calls urb->enqueue() which maps to the specific HCI driver.
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
......
......
if (likely(status == 0)) {
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
In my case I need to write a USB HCI driver that talks to a hardware which needs to be hidden from USB device driver, so I cannot change USB device driver to search for PCI ids for the hardware... In this case is there any way to force a specific device driver to associate with the USB HCI driver?
Update:
I have created two diagrams based on the discussion.
Diagram #1 shows the current USB model in kernel, I see from 'lspci' output that xHCI is the only host controller driver that is being used in my system.
Diagram #2 is a proposed design. While still allows NCM CDC device driver to work as a driver for current devices listed in its PCI tables, I would like to register my customized HCI with USB core for NCM CDC device driver. The customized HCI talks to customized hardware driver which hides the customized hardware info from user space (meaning there is no PCI probe).
My customized HCI needs to parse URB messages passed down from USB core and map them to corresponding APIs provided by customized hardware driver.
The problems I am having is that it looks like xHCI is by default used by all USB device drivers, I am not sure how can I tell USB core to use my customized HCI at all... even if I maybe able to hardcode USB core to force all traffics from NCM CDC USB device driver to customized HCI, because I won't be able to provide PCI productID/vendorID to NCM CDC device driver, how can I trigger NCM CDC device driver's probe() function to start at all?
Diagram #1 (Current kernel USB model):
----------------- ------------------ ------------------- -------------------
| NCM CDC | <----> | USB Core | <----> | xHCI | <----> | USB devices |
----------------- ------------------ ------------------- -------------------
Diagram #2 (proposed design):
----------------- ------------------ ----------------------------- -------------------------------- --------------------
| NCM CDC | <----> | USB Core | <-----> | Customized HCI | <----> | Customized Hardware driver | <----> | Customized HW |
----------------- ------------------ | ----------------------------- -------------------------------- --------------------
|
|
|
| ------------------- -------------------
|--->| xHCI | <----> | USB devices |
------------------- -------------------

If I understood properly your needs: you need to write a HCI driver which will be working outside of standard USB stack in Linux? So you don't want to register your HCI in Linux usb-core? If yes - just write HCI driver and don't register his API into usb-core. AFAIK which USB HCI driver (and HCI HW) is used only depends on the physical USB port you connected. So if you have system with more than one USB HCI then you can select HCI just by plugging USB device to given physical port. As I remember in USB 2.0 (ehci + companion controller) there was possibility to assign some USB port to either ehci or uhci/ohci (with some kind of mux) but now with xhci - I don't think it is possible. Mainly because xhci doesn't need any companion controller.

Related

How Operation System obtain Hardware ID

I am recently read documentation about Windows-Driver-Model, one of a chapter of it says :
Before a driver is installed for a new device, the bus or hub driver to which the device is connected assigns a hardware identifier (ID) to the device.
But how ??
For example the OS want to communicate with a USB device.
How can it ( the os ) obtain the hardware-id of the device ?
Is there some kind of protocol to communicate with the hardware that works like :
The OS send a signal ( or USB formatted message ) with a body of such as "I want to know hardware-id"
The hardware must response to this message to OS with a body of such as "My hardware-id is xxx"
If there is a protocol like this, could you please told me the "standard" of such a protocol.
On most modern computers every USB hub is connected to one xHCI controller (https://wiki.osdev.org/EXtensible_Host_Controller_Interface). At boot the BIOS will build ACPI tables in RAM that the OS will look for in conventional positions. Once the OS finds these tables, it will look at every entry to determine what devices are plugged to the computer including xHCI controllers. As stated on osdev.org
All xHCI controllers will have a Class ID of 0x0C, a Sublcass ID of 0x03, and an Interface value of 0x30. The configuration space for this device will contain two Base Address Registers: BAR0 and BAR1. These two 32-bit address fields combine to create a single 64-bit address that points to the base address of the memory mapped registers for the controller.
The memory mapped register of the xHCI s are then used to send commands to the USB device including commands to get the device descriptor of the USB device. The document on https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf is the spec for the xHCI. So if you want to really understand how it works under the hood then this is a great place to look at.

Multiple devices on mdio bus

I have multiple devices on MDIO bus (one AR8035 PHY, and 6 DP83849IFVS dual PHYs). The bus is connected to AM335x SoC with linux 4.14.40. Davinchi_mdio scans bus and finds all devices and attaches driver I think for AR8035. How can I access this bus via mdio? I want to write stand-lone (not PHY driver) kernel module, that can simply access mdio bus? How can I do that? I wanted to do that with phy_write/phy_read but I can't get struct phy_device* from my kernel module. How can I get struct phy_device* from the name of the interface ("eth0"). Will it be safe in terms of locks/mutaxes?
If you already have an subsystem for MDIO controller, then I can think of implementing an UIO driver for MDIO interface, which deals with read and write.
UIO driver is safe when compared to the messy kernel driver and complete control will be with the user application which uses that UIO.
**
*Each UIO device is accessed through a device file and several sysfs attribute files. The device file will be called /dev/uio0 for the first device, and /dev/uio1, /dev/uio2 and so on for subsequent devices.
/dev/uioX is used to access the address space of the card. Just use mmap() to access registers or RAM locations of your card.
Interrupts are handled by reading from /dev/uioX. A blocking read() from /dev/uioX will return as soon as an interrupt occurs.*
**

How does USB core decides which HCI driver to use for a USB device driver?

I am looking into USB device driver code. looks like all it does is to fill a URB message then calls usb_submit_urb() to pass the message to USB core functions once probe() is called upon matching PCI vendor/product ID.
However I am not able to figure out how USB core relates the device driver to correct HCI driver (xHCI, eHCI etc.)... what I found is most of HCI drivers register themselves as a platform driver which has a unique name, is that the identifier for usb core to correlate the device driver and host driver?
When you have usb 3.0 - then kernel uses xhci driver and doesn't need uhci, ohci or ehci drivers. In such configuration you have got only one hci driver and one hci host. Earlier in the USB 2.0 era there were 2 possible configurations:
ehci with companion controller (ohci or uhci)
ehci with transaction translator (TT)
In the first situation you need to have both drivers installed - for example ehci and uhci. In the second one only dedicated ehci driver was needed.
So currently when you have only xhci - it registers itself as the only usb host driver in linux system. Second thing - it is host driver function to request anything from usb devices - so usb host generates any requests to devices and it is responsible for maintenance of the answers from device. The xhci host driver registers his interrupt and memory area for request maintenance.
I think you need to take a look at this problem from the host (xhci) point of view, not from device point of view, because the host is the master in usb communication and the host initiates any requests. Device is only answering those requests.

How spi client driver is registered

I am new to Linux Device driver and trying to understand Linux device driver model which says a device must registered with its respected bus, be it the platform bus or real spi/i2c bus.
I could see the following macro which registered the i2c client device to its i2c bus.
module_i2c_driver(lm73_driver);
But I am not sure how it happen for a spi client device for example a CPLD/FPGA device sits on the spi bus.
Is such registrations based on the type of device?(block device or char device)

Identifying what /dev/ is a USB device connected to

I'd like to write a Ruby program for OSX that communicates via USB with my Arduino.
I am going to use the serialport gem for that purpose.
I found a sample code that says:
port_str = "/dev/ttyUSB0" #may be different for you
How can I scan and find the Arduino, and know to what port I should connect to automatically?
(I have OSX)
Thanks!
This can be tricky to do in a general way, because Arduino devices appear as USB serial ports, making it hard to distinguish between Arduino and non-Arduino ports.
The brute-force approach is: enumerate the USB serial devices, open() each in turn, and see if your firmware boot header is sent on the other end. On OSX, the USB serial devices are at /dev/tty.*, but that may change with future OS updates. This method works, but can be slow and timing sensitive. I've found that a startup delay on the Arduino before sending a header helps, as well as a simple "hello, are you there?" command the host can use to bang for signs of life.
Also, you can save the last port found so that subsequent app launches try that port first.
A variant: if your app asks the user to plug in the Arduino at startup, you can list the USB ports in /dev, wait for user to confirm it's plugged in, and list the ports again. Any newly appearing device is likely your Arduino.
At the next level, you could look at the USB Vendor and Product IDs (VID & PID). However, these IDs are all over the map in Arduino-land. They differ by model, version, revision, Chinese clones, and the various Arduino-compatible devices. See this writeup at Adafruit.
If you're just trying to make things work with a very narrow hardware set (e.g. the one Arduino on your bench), you can use this OSX command to see the USB device details:
system_profiler SPUSBDataType
With my system, I get:
...
USB Bus:
Host Controller Location: Built-in USB
Host Controller Driver: AppleUSBUHCI
PCI Device ID: 0x7fff000027c9
PCI Revision ID: 0x7fff00000002
PCI Vendor ID: 0x7fff00008086
Bus Number: 0x3d
Communication Device:
Product ID: 0x0043
Vendor ID: 0x2341
Version: 0.01
Serial Number: 75331313133351800000
Speed: Up to 12 Mb/sec
Manufacturer: Arduino (www.arduino.cc)
Location ID: 0x3d100000 / 2
Current Available (mA): 500
Current Required (mA): 100
The location ID (0x3d100000 / 2) seems to match up with the device name: /dev/cu.usbmodem3d11
See this question for running command line commands from within a Ruby script.

Resources