2015-10-25 1 views
0

Je développe ce module pour périphérique personnalisé qui, en fait, un 4 * 8 bits io ports attachés au bus ISA avec des adresses 0x0120 - 0x0123. Ce pilote est basé sur "scull" par Alessandro Rubini et Jonathan Corbet. Mon OS est Ubuntu 10.04, le noyau est générique 2.6.32-74, j'utilise le compilateur gcc orienté console. Lors de l'insertion du module compilé à l'aide de "insmod", j'obtiens une erreur "mauvaise adresse" et le module n'a pas été chargé. J'ai essayé de le déboguer en utilisant "printk" et ai découvert que mon module obtient avec succès une gamme de ports io, des nombres majeurs et mineurs et ensuite, en essayant de faire la fonction "Reset_Port" il génère une erreur .Lors de l'insertion de mon module noyau INSMOD quitte avec erreur "mauvaise adresse", met en garde sur "Kernel discordance"

Quelqu'un peut-il me dire, qu'est-ce que je fais mal?

Voici __exit et les fonctions __init de mon module

void __exit ET3201_exit(void) 
{ 
     int i; 
     dev_t devno = MKDEV(ET3201_major, ET3201_minor); 

     /* Get rid of our char dev entries */ 
     if (ET3201_devices) { 
       for (i = 0; i < ET3201_nr_devs; i++) { 
         ET3201_trim(ET3201_devices + i); 
         cdev_del(&ET3201_devices[i].cdev); 
       } 
       kfree(ET3201_devices); 
     } 

#ifdef ET3201_DEBUG /* use proc only if debugging */ 
     ET3201_remove_proc(); 
#endif 

     /* cleanup_module is never called if registering failed */ 
     unregister_chrdev_region(devno, ET3201_nr_devs); 
    if (! port) release_region(BaseIO, 8); 
    printk(KERN_INFO "Goodbye, cruel world - ET3201 is unloaded\n"); 

     /* and call the cleanup functions for friend devices */ 
     /*ET3201_access_cleanup();*/ 
} 
/*----------------------------------------------------------------------------*/ 
/* Set up the char_dev structure for this device. */ 
static void ET3201_setup_cdev(struct ET3201_dev *dev, int index) 
{ 
     int err, devno = MKDEV(ET3201_major, ET3201_minor + index); 

     cdev_init(&dev->cdev, &ET3201_fops); 
     dev->cdev.owner = THIS_MODULE; 
     dev->cdev.ops = &ET3201_fops; 
    dev->CAMAC_Module_Number = CAMAC_Nmod; 
    dev->CAMAC_Command_Adress = CAMAC_Adcom; 
    dev->Driver_Number = ET3201_minor + index; 
     err = cdev_add (&dev->cdev, devno, 1); 
     /* Fail gracefully if need be */ 
     if (err) 
       printk(KERN_NOTICE "Error %d adding ET3201%d", err, index); 
} 
/*----------------------------------------------------------------------------*/ 
int __init ET3201_init(void) 
{ 
    int result = 0; 
    int i; 
    dev_t dev = 0; 
    BaseIO = Base; 
    /* Get a range of minor numbers to work with, asking for a dynamic 
    major unless directed otherwise at load time. */ 
    if (ET3201_major) { 
      dev = MKDEV(ET3201_major, ET3201_minor); 
     result = register_chrdev_region(dev, ET3201_nr_devs, "ET3201"); 
    } else { 
      result = alloc_chrdev_region(&dev, ET3201_minor, ET3201_nr_devs, "ET3201"); 
     ET3201_major = MAJOR(dev); 
    } 
    if (result < 0) { 
     printk(KERN_WARNING "ET3201: can't get major %d\n", ET3201_major); 
     return result; 
    }  
    port = request_region(BaseIO, 8, "ET3201"); 
    if (port == NULL) { 
         printk(KERN_WARNING "ET3201 cannot reserve i-o ports %lu \n", BaseIO); 
         return -ENODEV; 
      goto fail; 
       } 
     /* 
     * allocate the devices -- we can't have them static, as the number 
     * can be specified at load time 
     */ 
     ET3201_devices = kmalloc(ET3201_nr_devs * sizeof(struct ET3201_dev), GFP_KERNEL); 
     if (! ET3201_devices) { 
       result = -ENOMEM; 
     printk(KERN_ALERT "ET3201: can't get memory \n"); 
       goto fail; /* Fail gracefully if need be */ 
     } 
     memset(ET3201_devices, 0, ET3201_nr_devs * sizeof(struct ET3201_dev)); 

     /* Initialize each device. */ 
     for (i = 0; i < ET3201_nr_devs; i++) { 
       ET3201_devices[i].quantum = ET3201_quantum; 
       ET3201_devices[i].qset = ET3201_qset; 
       init_MUTEX(&ET3201_devices[i].sem); 
       ET3201_setup_cdev(&ET3201_devices[i], i); 
     } 

     /* At this point call the init function for any friend device */ 
     dev = MKDEV(ET3201_major, ET3201_minor + ET3201_nr_devs); 
     /*dev += ET3201_access_init(dev);*/ 

    printk(KERN_INFO "ET3201 is initialized with major %d\n", ET3201_major); 
    if (port != NULL){ 
     printk(KERN_INFO "ET3201 is trying to reset %d devices\n", ET3201_nr_devs); 
     result = Reset_Port(); 
    } 
     if (result != 0) { 
     printk(KERN_ALERT "ET3201: device cannot reset with result %d\n", result); 
       result = -EFAULT; 
       goto fail; 
     } 
#ifdef ET3201_DEBUG /* only when debugging */ 
     ET3201_create_proc(); 
#endif 

     return 0; /* succeed */ 

    fail: 
     ET3201_exit(); 
    return result; 
} 
/*----------------------------------------------------------------------------*/ 
module_init(ET3201_init); 
module_exit(ET3201_exit); 
MODULE_LICENSE("GPL"); 
MODULE_ALIAS_MISCDEV(ET3201_minor); 

et suivant sera Reset_Port()

static int Reset_Port(void) 
{ 
int result = -EIO; 
int count; 
if (port == NULL) goto fail; 
for (count = 0; count < ET3201_nr_devs; count++) 
{ 
outb(0x00, ports[count]); 
} 
wmb();   /*write memory barrier*/ 
LastOp = E_Reset; 
result = 0;  /* success */ 
fail: 
return result; 
} 
EXPORT_SYMBOL(Reset_Port); 

Maintenant, après la fixation 'int Reset_Port (vide) J'ai une autre problème -
'ATTENTION: modpost: Trouvé 1 incompatibilité (s) de section.' Après le débogage, je vois que ceci est le résultat de l'appel 'ET3201_exit()' de 'module_init()' - quand j'ai remarqué cet appel, l'avertissement a disparu. Surprenant que exactement le même appel a été fait dans le pilote "scull" des auteurs respectés - et cela fonctionne. Question: Qu'est-ce qui peut entraîner une non-concordance du noyau dans ce code?

+0

En ce qui concerne le nouveau problème, votre fonction 'ET3201_exit' est déclarée avec l'attribut de section' __exit'. Cet attribut signifie que cette section peut ne pas être créée si la fonctionnalité de déchargement du module n'est pas activée dans le noyau. Mais vous utilisez cette fonction dans 'module_init', qui est utilisé chaque fois que le support de déchargement de module existe ou non. C'est la raison pour laquelle modpost signale l'incompatibilité entre les sections: il est possible que 'ET3201_exit' soit appelée quand elle n'existe pas. – Tsyvarev

+0

@Tsyvarev, merci beaucoup! J'ai enlevé l'attribut __exit et la discordance de section a disparu. Les attributs __init et __exit n'ont pas été utilisés dans le pilote de périphérique 'scull'. –

Répondre

0

Oui! Le bug est corrigé - après avoir déclaré 'int Reset_Port (void)' le module a été inséré et supprimé avec succès. J'ai pensé (mais c'était faux) que toutes les fonctions qui peuvent être appelées depuis 'module_init()' ne doivent pas être déclarées comme statiques.

+0

'module_init' ** peut utiliser ** des fonctions statiques. Mais l'utilisation de EXPORT_SYMBOL pour la fonction statique semble brisée. – Tsyvarev

+0

@Tsyvarev, merci pour un commentaire utile! Mon 'module_init' utilise la fonction statique 'ET3201_remove_proc()' et cela fonctionne bien. –