Loaded driver modalias
RFC PATCH 1/1 Loaded driver modalias
Please CC me to responses as I'm not subscribed to LKML. Also, this is my first kernel patch, advise is certainly welcome.
For something I'm working on I have the need to answer the question, "given a hardware ID, does Linux distro X have a driver to support this hardware?" and more specifically, "which drivers support this hardware?" I can, generally speaking, get this data from files like /lib/modules/*/modules.alias. However, this does not work for drivers built into the kernel. With that in mind, I've cooked up a little proof of concept. Basically, its a sysfs file /sys/modules/$module/drivers/$driver/modalias that, when read, contains modalias-style filters for this driver.
The attached patch only does this for PCI drivers, each subsystem would need a patch like this. Is this idea crazy? Is there a better implementation?
Thanks!
Nathaniel McCallum
drivers/pci/pci-driver.c +69 -2
@@ -118,6 +118,70 @@static inline void pci_remove_newid_file (struct pci_driver *drv) {}#endif +#define ADD (buf, size, cond, wdata, data, wodata) \ +{ \ + if (cond) { \ + if (snprintf(buf, size, "%s" wdata, buf, data) >= size) \ + return -ENOMEM; \ + } \ + else { \ + if (snprintf(buf, size, "%s" wodata, buf) >= size) \ + return -ENOMEM; \ + } \ +} + +#define PCI_MODALIAS (buf, size, v, d, sv, sd, c, cm) \ +{ \ +ADD(buf, size, 1, "%s", "pci:", "") \ +ADD(buf, size, v != PCI_ANY_ID, "v%08X", v, "v*") \ +ADD(buf, size, d != PCI_ANY_ID, "d%08X", d, "d*") \ +ADD(buf, size, sv != PCI_ANY_ID, "sv%08X", sv, "sv*") \ +ADD(buf, size, sd != PCI_ANY_ID, "sd%08X", sd, "sd*") \ +ADD(buf, size, ((cm >> 16) & 0xFF) == 0xFF, "bc%02X", ((c >> 16) & 0xFF), "bc*") \ +ADD(buf, size, ((cm >> 8) & 0xFF) == 0xFF, "sc%02X", ((c >> 8) & 0xFF), "sc*") \ +ADD(buf, size, ((cm >> 0) & 0xFF) == 0xFF, "i%02X*", ((c >> 0) & 0xFF), "i*") \ +ADD(buf, size, 1, "%s", "\n", "") \ +} + +static ssize_t +show_modaliases (struct device_driver *driver,char *buf) +{ +struct pci_driver *pdrv =to_pci_driver (driver); +struct list_head *pos; +struct pci_dynid *dynid; +int i; + +/* Reset the buffer to be blank */ + buf[0 ] ='\0' ; + +/* List the static ids */ +for (i=0 ; pdrv->id_table[i].vendor !=0 && + pdrv->id_table[i].device !=0 ; i++) { +PCI_MODALIAS (buf,PAGE_SIZE , + pdrv->id_table[i].vendor, + pdrv->id_table[i].device, + pdrv->id_table[i].subvendor, + pdrv->id_table[i].subdevice, + pdrv->id_table[i].class, + pdrv->id_table[i].class_mask) + } + +/* List the dynamic ids */ +list_for_each (pos, &pdrv->dynids.list) { + dynid = list_entry(pos, struct pci_dynid, node); +PCI_MODALIAS (buf,PAGE_SIZE , + dynid->id.vendor, + dynid->id.device, + dynid->id.subvendor, + dynid->id.subdevice, + dynid->id.class, + dynid->id.class_mask) + } + +return strlen (buf); +} +static DRIVER_ATTR(modaliases, S_IRUGO, show_modaliases, NULL); +/** * pci_match_id - See if a pci device matches a given pci_id table * @ids: array of PCI device id structures to search in
@@ -702,9 +766,11 @@return error; error =pci_create_newid_file (drv); -if (error) -driver_unregister (&drv->driver); +if (!error) + error =driver_create_file (&drv->driver, &driver_attr_modaliases); +if (error) +pci_unregister_driver (drv);return error; }
@@ -722,6 +788,7 @@ pci_unregister_driver(struct pci_driver *drv) {pci_remove_newid_file (drv); +driver_remove_file (&drv->driver, &driver_attr_modaliases);driver_unregister (&drv->driver);pci_free_dynids (drv); }
Quoted 13 lines · Nathaniel McCallum
Please CC me to responses as I'm not subscribed to LKML. Also, this is my first kernel patch, advise is certainly welcome.
For something I'm working on I have the need to answer the question, "given a hardware ID, does Linux distro X have a driver to support this hardware?" and more specifically, "which drivers support this hardware?" I can, generally speaking, get this data from files like
/lib/modules/*/modules.alias. However, this does not work for drivers built into the kernel. With that in mind, I've cooked up a little proof of concept. Basically, its a sysfs file/sys/modules/$module/drivers/$driver/modaliasthat, when read, contains modalias-style filters for this driver.
Quoted 2 lines
The attached patch only does this for PCI drivers, each subsystem would need a patch like this. Is this idea crazy? Is there a better implementation?
Hmm, what if that gets larger than 4k? It seems not really like something for sysfs. There are also drivers which export a modalias which matches more devices, than the device it actually would accept to bind to. Some driver have logic in the match() function to exclude stuff.
What's the exact information you need? Would it be sufficient to ask a bus with a modalias string, which driver of that bus matched that device?
Kay
Quoted 20 lines · Kay Sievers
Quoted 13 lines · Nathaniel McCallum
Please CC me to responses as I'm not subscribed to LKML. Also, this is my first kernel patch, advise is certainly welcome.
For something I'm working on I have the need to answer the question, "given a hardware ID, does Linux distro X have a driver to support this hardware?" and more specifically, "which drivers support this hardware?" I can, generally speaking, get this data from files like
/lib/modules/*/modules.alias. However, this does not work for drivers built into the kernel. With that in mind, I've cooked up a little proof of concept. Basically, its a sysfs file/sys/modules/$module/drivers/$driver/modaliasthat, when read, contains modalias-style filters for this driver.Quoted 3 lines
The attached patch only does this for PCI drivers, each subsystem would need a patch like this. Is this idea crazy? Is there a better implementation?
Quoted 6 lines
Hmm, what if that gets larger than 4k? It seems not really like something for sysfs. There are also drivers which export a modalias which matches more devices, than the device it actually would accept to bind to. Some driver have logic in the
match()function to exclude stuff.
In this current patch, an error is returned. Like I said, this is more proof of concept than anything. I'm trying to ask a running kernel "What hardware do you at least pretend to support?" While I would love to get only the drivers that would actually bind to the device, I don't suspect this is possible since you'd need real or emulated hardware to test this. One of my explicit design requirements is that the hardware ids don't represent "real" hardware. The hardware might exist in real life, but I don't have it (and I can't emulate it). I just want to know what Linux would try to do with the hardware *if* I had it. Thus, I don't really care about the logic in the match() function since it would require real hardware.
What method would be appropriate for this other than sysfs?
Quoted 4 lines
What's the exact information you need? Would it be sufficient to ask a bus with a modalias string, which driver of that bus matched that device?
I want to create a database of this information that exists outside the Linux kernel. This database should contain a map of filters to drivers such that, given any hardware id (real or otherwise), I should be able to determine which kernel drivers would attempt to "do something" with this hardware.
So, first I would snapshot one or more distributions (and perhaps different kernels in the same distro). Then I would compare hardware IDs against this snapshot. Once this driver database is built, you can do lots of things with it, including stuff like regression testing. The important thing is that the hardware id is not available at the time the snapshot is taken.
One of the possible usages for this, outside of my project, would be to create a list of the most common hardware ids out there. Then, for each kernel release, a snapshot could be taken of its hardware support. Then, you could test to make sure that all common hardware is supported and that no regressions have appeared. Sure, this doesn't test whether the *real* hardware works or not. However, testing physical hardware cannot be easily automated, and this can.
Nathaniel
Quoted 20 lines · Kay Sievers
Quoted 13 lines · Nathaniel McCallum
Please CC me to responses as I'm not subscribed to LKML. Also, this is my first kernel patch, advise is certainly welcome.
For something I'm working on I have the need to answer the question, "given a hardware ID, does Linux distro X have a driver to support this hardware?" and more specifically, "which drivers support this hardware?" I can, generally speaking, get this data from files like
/lib/modules/*/modules.alias. However, this does not work for drivers built into the kernel. With that in mind, I've cooked up a little proof of concept. Basically, its a sysfs file/sys/modules/$module/drivers/$driver/modaliasthat, when read, contains modalias-style filters for this driver.Quoted 3 lines
The attached patch only does this for PCI drivers, each subsystem would need a patch like this. Is this idea crazy? Is there a better implementation?
Quoted 6 lines
Hmm, what if that gets larger than 4k? It seems not really like something for sysfs. There are also drivers which export a modalias which matches more devices, than the device it actually would accept to bind to. Some driver have logic in the
match()function to exclude stuff.
Also, would it not be possible to break the 4k barrier with a binary attribute?
Nathaniel