As up to date and as diligent as any OS company tries to be with its software driver support, the rate of change of hardware, especially variants of existing devices, out paces anything that we can reasonably keep up with. So, what’s a developer to do when they buy a shiny new motherboard and QNX Neutrino doesn’t detect that new GigE port ?
I get asked this type of question at least once a week. Quite often, we’ve added support for the new device in our source tree, but haven’t released the new version of the driver yet. We do regular releases for sure, but not daily…
Well, there are already a bunch of drivers delivered as part of Neutrino, so it is quite possible that we *do* have a driver that would work, if it only ‘knew’ that the new device is just like one it already recognizes. There are a couple of easy ways to tell a driver about a new device, so here’s what to try if you hit this issue… No guarantees of course, but it can save a lot of heartburn.
Find the PCI IDs
Assuming that the new device is a PCI (or PCI-X or PCI-Express) device, which is a fair bet these days, it has 2 16-bit associated values called its device and vendor IDs, that together identify the device. It is these numbers that Neutrino uses to decide which driver to use to manage the device. Each driver has a (possibly extensive) list of devices that it knows are for it to manage, but it is also possible to pass a specific device/vendor ID pair to a driver and ask it to try to manage the device.
There are several databases that keep lists of these IDs
and QNX keeps a list of supported devices here:
http://www.qnx.com/developers/hardware_support/index.html
So, if a device isn’t running and you think a specific driver should work with it, the first thing to do is to find its PCI IDs. To do that, on a booted Neutrino system, in a shell run ‘pci -v | more’ to get output like this:
PCI version = 2.10Class = Bridge (Host/PCI)
Vendor ID = 8086h, Intel Corporation Device ID = 7190h, 440BX/ZX/DX - 82443BX/ZX/DX Host bridge PCI index = 0h Class Codes = 060000h Revision ID = 1h Bus number = 0 Device number = 0 Function num = 0 Status Reg = 210h Command Reg = 6h Header type = 0h Single-function BIST = 0h Build-in-self-test not supported Latency Timer = 0h Cache Line Size= 0h Subsystem Vendor ID = 15adh Subsystem ID = 1976h Max Lat = 0ns Min Gnt = 0ns PCI Int Pin = NC Interrupt line = 0
Class = Bridge (PCI/PCI) Vendor ID = 8086h, Intel Corporation Device ID = 7191h, 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge PCI index = 0h Class Codes = 060400h Revision ID = 1h Bus number = 0 Device number = 1 Function num = 0 Status Reg = 220h Command Reg = 11fh Header type = 1h Single-function BIST = 0h Build-in-self-test not supported Latency Timer = 0h Cache Line Size= 0h Primary Bus Number = 0h Secondary Bus Number = 1h Subordinate Bus Number = 1h Secondary Latency Timer = 40h I/O Base = f0h I/O Limit = 0h Secondary Status = 2a0h Memory Base = fff0h Memory Limit = 0h Prefetchable Memory Base = fff0h Prefetchable Memory Limit= 0h Prefetchable Base Upper 32 Bits = 0h Prefetchable Limit Upper 32 Bits = 0h I/O Base Upper 16 Bits = 0h I/O Limit Upper 16 Bits = 0h Bridge Control = 80h PCI Int Pin = NC Interrupt line = 0 CPU Interrupt = 0h
[Snip - this list can be *long* for a complex system] Class = Network (Ethernet) Vendor ID = 1022h, Advanced Micro Devices [AMD] Device ID = 2000h, 79c970 [PCnet32 LANCE] PCI index = 0h Class Codes = 020000h Revision ID = 10h Bus number = 0 Device number = 17 Function num = 0 Status Reg = 280h Command Reg = 7h Header type = 0h Single-function BIST = 0h Build-in-self-test not supported Latency Timer = 40h Cache Line Size= 0h PCI IO Address = 1080h length 128 enabled Subsystem Vendor ID = 1022h Subsystem ID = 2000h PCI Expansion ROM = 0h length 65536 disabled Max Lat = 255ns Min Gnt = 6ns PCI Int Pin = INT A Interrupt line = 9 CPU Interrupt = 9h
Find the device that you’re interested in and record the vendor and device PCI IDs that are listed for it.
Then choose one of the 2 methods below to get the driver going…
Quick command line test
Drivers in QNX Neutrino can be stopped/killed/restarted independently, so one thing to do is to kill and restart the driver that you think is the right one to use, passing the PCI IDs to it as command line parameters:
For instance, there are *many* variants of the Intel Gigabit Ethernet device that we support via our devn-i82544.so device driver. Happily, our driver generally supports the new variants very nicely.
So, a simple test is to run:
slay io-net
[slay is a 'kill by process name' executable that will end the io-net network manager process, which runs network device drivers.]
Then, restart io-net, specifying the i82544 driver and the specific ID that needs to be provided:
io-net -ptcpip -di82544 vid=<VendorID>,did=<DeviceID>
For this driver, the Vendor ID is typically 0×8086, since this is Intel’s main vendor ID – very droll.
The ‘-ptcpip’ part means ‘run the TCP/IP protocol stack’. You might add ‘-pqnet’ too if you want to run QNET.
If this works, your new device will be created in /dev/io-net, and running ‘ifconfig -a’ will show your new device or devices.
Make The Change Permanent
So, if you tried the command line option, and things worked well, you probably want to make the change permanent, so the driver starts up properly every time you reboot.
If you make your own custom boot image, you can just embed the io-net command from above into your build file, rebuild and you’re done.
More often, on X86 boxes, customers tend to use our diskboot process to manage driver startup. This uses a set of tables in /etc/system/enum/devices – one for audio devices, one for net(work) devices etc.
These tables look a bit confusing at first, but adding a new device is pretty simple – you just copy an existing line or lines for the driver you want to work with, modify it for your IDs, then reboot to see if it works…
e.g. to add a line for the Intel Gigabit Ethernet driver, you edit (e.g. with ‘vi’ ) /etc/system/enum/devices/net
and search for 82544
You’ll see a bunch of lines like this:
device(pci, ven=$(PCI_VEND_INTEL), dev=1008) # Intel 82544EI Gigabit device(pci, ven=$(PCI_VEND_INTEL), dev=1009) # Intel 82544EI Gigabit device(pci, ven=$(PCI_VEND_INTEL), dev=100c) # Intel 82544GC Gigabit
… lots more similar lines
Ending with:
tag(devn) append(legacy, ",nonet") requires($(IONET_CMD),) uniq(netnum, devn-en, 0) mount(-Tio-net "-opci=$(index),vid=0x$(ven),did=0x$(dev)" /lib/dll/devn-i82544.so, "/dev/io-net/en$(netnum)") use(symbolic=netmgr)
This last set of lines are the magic that launch the i82544 driver with the correct vendor and device IDs.
All you need to do to add a new device to this list is copy one of the device lines and modify the dev=<xxxx> lines
e.g.
device(pci, ven=$(PCI_VEND_INTEL), dev=1099)
where 0×1099 is the new device’s PCI device ID.
Save the file, and then reboot (because diskboot only runs at startup) and hopefully your device will show up…
If it does, great – you’re done, and can get back to your real job of getting your product built and tested.
If it doesn’t, let QNX know – it really helps us to know what you need !