2016-08-06 54 views
1

Nach der Registrierung eines PCI-Treibers unter pci_register_driver() innerhalb der init_module-Funktion soll der Treiber die Kontrolle über alle PCI-Geräte übernehmen, die noch keine Treiber haben, vorausgesetzt, die Geräte entsprechen der Hersteller-ID. Geräte-ID usw., wie in der struct pci_device_id angegeben.Benutzerdefinierter PCI-Treiber kann Gerät nicht testen

Ich möchte den Ethernet-Controller zwingen, meinen Treiber nur für Experimente zu verwenden (z. B. das Lesen von Konfigurationsbytes). Auf einem Virtualbox-Gast (Mint, Kernel 3.13.0) habe ich den Treiber des Ethernet-Controllers auf die schwarze Liste gesetzt, update-initramfs -u ausgeführt und neu gestartet. Dadurch wurde der Standardtreiber vom Controller getrennt, da der Treiber nicht mehr in der Ausgabe lspci -k angezeigt wurde.

Allerdings, als ich das Modul geladen habe, zeigten ein paar Geräte, die vorher fehlten, in der Ausgabe von lspci -k (mit meinem Treiber, der sie steuert), aber der Ethernet-Controller fehlte noch eine "Kernel driver in use: " Zeile. Wie kann ich erreichen, dass mein Modul den Controller erkennt und besitzt?

Beachten Sie, dass ich PCI_ANY_ID für die Hersteller- und Gerätefelder verwendete und die anderen Felder der struct pci_device_id nicht initialisiert. Also würde ich erwarten, dass der Treiber jedes Gerät sondiert, dem ein Treiber fehlt.

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/fs.h> 
#include <linux/pci.h> 

MODULE_LICENSE("GPL"); 

int init_module(void); 
void cleanup_module(void); 
static int pci_probe(struct pci_dev *, const struct pci_device_id *); 
static void pci_remove(struct pci_dev *dev); 

#define SUCCESS 0 
#define FAILURE -1 


static struct pci_device_id my_pci_id = { 
     .vendor = PCI_ANY_ID, 
     .device = PCI_ANY_ID 
}; 

static struct pci_driver my_pci_driver = { 
     .name = "kmod_driver", 
     .id_table = &my_pci_id, 
     .probe = pci_probe, 
     .remove = pci_remove 
}; 


int init_module(void) 
{ 
     return pci_register_driver(&my_pci_driver); 
} 

void cleanup_module(void) 
{ 
     pci_unregister_driver(&my_pci_driver); 
} 

static int pci_probe(struct pci_dev *dev, const pci_device_id *id) 
{ 
     int enableStatus = pci_enable_device(dev); 
     ..... 
     return SUCCESS; 
} 

static void pci_remove(struct pci_dev *dev) 
{ 
     return; 
} 
+0

Sie können nicht nur ANY sagen, ANY für Anbieter und Geräte-ID. Sie müssen den tatsächlichen Hersteller/das Gerät (und möglicherweise die Unterlieferanten-/Untergerät-IDs) für das Gerät angeben, das Sie über diesen Treiber steuern möchten. –

+0

@ChaitanyaLala, ist es nicht immer der Fall. Viele Treiber entsprechen der Klasse, z. AHCI, 8250, ... – 0andriy

+0

'.vendor = PCI_ANY_ID, .device = PCI_ANY_ID 'bedeutet, dass Ihr Treiber mit dem ersten _matching_-Gerät verglichen wird. Das erste passende Gerät kann den Treiber wahrscheinlich bereits geladen haben. – 0andriy

Antwort

0

Sie müssen auch die subvendor und subdevice Felder enthalten (sie PCI_ANY_ID und Einstellung). Die Matching-Funktion ist dies:

static inline const struct pci_device_id * 
pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) 
{ 
     if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) && 
      (id->device == PCI_ANY_ID || id->device == dev->device) && 
      (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) && 
      (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) && 
      !((id->class^dev->class) & id->class_mask)) 
       return id; 
     return NULL; 
} 

Sie die PCI_DEVICE Makro verwenden, können Sie die entsprechenden sub Mitglieder zu liefern:

static struct pci_device_id my_pci_id = { 
    PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID), 
};