Périphérique de plate-forme de modèle de pilote de périphérique Linux

Périphérique de plate-forme de modèle de pilote de périphérique Linux

Le chapitre précédent a présenté le pilote de périphérique de caractères Linux, qui est relativement basique et permet à chacun de comprendre comment enregistrer et utiliser le pilote de périphérique du noyau Linux. Mais au travail, je pense personnellement qu'il existe relativement peu de possibilités d'écrire un pilote de périphérique de caractères entièrement à la main. La plupart d'entre elles sont basées sur des modifications de code antérieures effectuées depuis trois ans. Dans le pilote du noyau, vous verrez davantage de mots liés à la plate-forme. De quoi s’agit-il spécifiquement ? Jetons un coup d’œil.

autobus à plate-forme

Sous Linux embarqué, vous entendrez peut-être parler de bus I2C, de bus SPI, de bus USB, etc., mais qu'est-ce que le bus de plateforme et quelles sont ses spécifications ? Le bus de plateforme est un bus virtuel. Il n'a pas de spécifications de protocole de communication comme le bus présenté ci-dessus. Il est uniquement virtualisé pour mieux gérer les pilotes de périphériques du noyau Linux.

Au cours du processus de développement du projet, de nombreux pilotes de périphériques devront être enregistrés, mais ces périphériques auront tous de nombreux points communs, tels que les opérations auxquelles il faut prêter attention au réveil. différents, mais ils auront tous des besoins, et il en va de même lors de l'allumage et de l'extinction. Afin de faciliter la gestion de ces pilotes de périphériques, Linux a ajouté des périphériques et des pilotes à la plate-forme pour faciliter la gestion unifiée des pilotes pendant le processus de développement. Les périphériques et les pilotes sont montés sur le bus. Lorsque de nouveaux périphériques ou pilotes sont ajoutés, ils seront Lorsque les informations sur le périphérique et le pilote sont cohérentes, les opérations correspondantes sont effectuées pour terminer l'application de ressources et l'enregistrement du périphérique.

Le noyau Linux fournit une interface pour enregistrer les bus. Voyons quelles informations fournissent les bus de la plateforme :

/* 从platform_bus的定义来看,虽然我们说platform总线,实际上它还是一个设备 */
struct device platform_bus = {
    
    
        .init_name      = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);

/* 定义platform设备的默认属性 */
static struct attribute *platform_dev_attrs[] = {
    
    
        &dev_attr_modalias.attr,
        &dev_attr_driver_override.attr,
        NULL,
};
ATTRIBUTE_GROUPS(platform_dev);

/* 提供设备的休眠唤醒接口函数,platform设备的休眠唤醒都通过这个接口完成调用 */
static const struct dev_pm_ops platform_dev_pm_ops = {
    
    
        .runtime_suspend = pm_generic_runtime_suspend,
        .runtime_resume = pm_generic_runtime_resume,
        USE_PLATFORM_PM_SLEEP_OPS
};

/* 定义platform总线的一些总要接口 */
struct bus_type platform_bus_type = {
    
    
        .name           = "platform",
        .dev_groups     = platform_dev_groups,	/* 总线上设备的默认属性 */
        .match          = platform_match,		/* 前面我们说到注册分别注册设备和驱动之后,将会进行设备驱动匹配,platform设备就是通过该函数实现的 */
        .uevent         = platform_uevent,		/* 当添加、删除设备的时候,生成uevent添加到环境变量,实际上可以理解为有设备添加、删除时发送广播  */
        .pm             = &platform_dev_pm_ops,	/* 这个就是上面的休眠唤醒时的调用接口了 */
};
EXPORT_SYMBOL_GPL(platform_bus_type);

int __init platform_bus_init(void)
{
    
    
        int error;

        early_platform_cleanup();

    	/* 注册platform设备 */
        error = device_register(&platform_bus);
        if (error)
                return error;
    	/* 向系统注册platform总线 */
        error =  bus_register(&platform_bus_type);
        if (error)
                device_unregister(&platform_bus);
        of_platform_register_reconfig_notifier();
        return error;
}

La fonction bus_register effectue principalement les opérations suivantes :

  1. Définissez l'indicateur d'auto-détection du pilote drivers_autoprobe sur 1, de sorte que tant qu'un périphérique ou un pilote rejoint le bus, la détection du pilote de périphérique sera déclenchée ;
  2. Créez le nœud d'attribut par défaut du bus ;
  3. Créer une sonde de bus et d'autres nœuds de fichiers ;

Après avoir enregistré le bus plate-forme auprès du système, comment l'utiliser ? Jetons un coup d'œil au fonctionnement des périphériques et des pilotes de la plate-forme.

dispositif de plate-forme

Les périphériques de plate-forme sont généralement ajoutés à diverses interfaces ou périphériques SOC dans le pilote du noyau. En tant qu'interface pour se connecter au périphérique du noyau, le pilote de périphérique correspondant peut être plus flexible. Voyons d'abord comment le noyau définit ce périphérique de plateforme.

struct platform_device {
    
    
        const char      *name;			/* 设备属于什么名字的 */
        int             id;				/* 设备的索引,比如有多个类似的设备 */
        struct device   dev;			/* 内核设备的基础 */
        ...
        u32             num_resources;
        struct resource *resource;		/* 用于这个设备的资源保存了,比如中断和寄存器地址等 */
        ...
};

Après avoir essentiellement compris le type de périphérique de plate-forme ci-dessus, comment s'enregistre-t-il auprès du noyau Linux ? Principalement via les deux fonctions d'interface suivantes.

/* 登记注册platform device */
int platform_device_register(struct platform_device *pdev);
/* 登记注册num个platform device */
int platform_add_devices(struct platform_device **devs, int num);

Alors, quelles sont les principales opérations de la fonction platform_device_register() ?

  1. Initialisez pdev->dev via device_initialize, qui consiste à initialiser le périphérique de structure ci-dessus ;
  2. Définissez le masque DMA du périphérique de la plate-forme ;
  3. Initialisez le parent de pdev->dev sur platform_bus et du bus sur platform_bus_type ;
  4. Mettre à jour les ressources des appareils de la plateforme ;
  5. Ajoutez le périphérique pdev->dev au noyau via device_add();

Il semble que l'enregistrement soit terminé. Il n'y a plus que l'appareil et aucun pilote. Voyons quel est le pilote.

pilote de plateforme

Le noyau sépare les périphériques et les pilotes. Les périphériques peuvent être des entités visibles et tangibles, ou des périphériques virtuels distants, tandis que les pilotes sont le code qui permet au périphérique de fonctionner normalement. Le pilote de plateforme est défini comme suit :

struct platform_device_id {
    
    
        char name[PLATFORM_NAME_SIZE];
        kernel_ulong_t driver_data;
};

struct platform_driver {
    
    
    	/* probe函数用于探测是否存在和该驱动一致的platform device,由各自driver实现,驱动加载时调用 */
        int (*probe)(struct platform_device *);
    	/* remove函数则是在卸载模块时调用,释放相关资源 */
        int (*remove)(struct platform_device *);
    	/* 系统关机时将会调用shutdown */
        void (*shutdown)(struct platform_device *);
    	/* suspend和resume则是系统进入休眠和唤醒时调用 */
        int (*suspend)(struct platform_device *, pm_message_t state);
        int (*resume)(struct platform_device *);
    	/* 内核驱动的基础 */
        struct device_driver driver;
    	/* platform device和driver匹配信息 */
        const struct platform_device_id *id_table;
};

Les membres de base du pilote de plate-forme sont répertoriés ci-dessus. Chaque pilote sera implémenté. Les besoins de base sont de compléter le remplissage des informations de sonde, de suppression et d'id_table. Pour enregistrer un pilote auprès du noyau, l'enregistrement du pilote se fait via platform_driver_register, qui effectue principalement plusieurs opérations :

  1. Définissez le bus du conducteur sur platform_bus_type ;
  2. Le pilote est un pilote de plate-forme, donc les fonctions de détection, de suppression et d'arrêt de device_driver sont définies sur les fonctions du pilote de plate-forme ;
  3. Enregistrez le pilote auprès du noyau via la fonction driver_register ;

Le sens de la sonde

Une machine dotée uniquement de matériel sans logiciel n'est peut-être qu'un tas de ferraille ; et avec uniquement des pilotes logiciels, elle est inutile et ne peut pas jouer son rôle sans support. Bien que nous ayons enregistré le périphérique et le pilote, s'il n'y a pas de correspondance, cela ne fonctionnera pas, tout comme l'utilisation d'un micrologiciel ARM64 sur une puce d'architecture mips et un échec d'exécution, le but de la sonde est donc de confirmer si le périphérique actuel est cohérent avec lui-même via le pilote. S'ils sont cohérents, l'enregistrement des nœuds du système peut être effectué.

Lors de l'introduction du périphérique de plate-forme ci-dessus, il y a un membre name et un id_table dans le pilote de plate-forme. Quand le périphérique et le pilote seront-ils déclenchés pour correspondre ?

Avec le recul, lors de l'enregistrement du pilote via la fonction platform_driver_register(), driver_register() appellera bus_add_driver() pour enregistrer le pilote auprès du bus. Dans bus_add_driver(), parce que le bus a déjà défini drivers_autoprobe, driver_attach() sera utilisé pour faire correspondre le périphérique et le pilote. , le processus est le suivant :

platform_driver_register
	driver_register
		bus_add_driver
			driver_attach
				__driver_attach
					driver_match_device
						bus->match

Dans driver_attach, les klist_devices du bus (toutes les informations sur les périphériques du bus sont sur cette liste chaînée) seront mis en correspondance avec le pilote un par un. La correspondance est effectuée via la fonction __driver_attach(). Dans __driver_attach, le bus est appelé via driver_match_device() La fonction de correspondance du bus plateforme est platform_match(). platform_match effectuera les comparaisons suivantes dans l'ordre :

  1. Si le driver_override du périphérique de plate-forme est défini, comparez le driver_override de pdev et le nom de drv pour voir s'ils sont cohérents ;
  2. Pour faire correspondre l'arborescence des périphériques, comparez les informations of_match_table de drv et of_node de dev pour voir si elles sont cohérentes ;
  3. En comparant les informations acpi, ce point n'est pas très clair et n'est pas utilisé normalement ;
  4. Comparez pdrv->id_table et pdev->name. Ceci est généralement utilisé plus souvent ;
  5. Enfin, comparez directement pdev->name et drv->name ;

Si aucune des comparaisons ci-dessus n’est cohérente, il n’y a pas de correspondance, sinon la correspondance est réussie. Si la correspondance du pilote de périphérique est réussie, elle le sera via la fonction device_driver_attach().

device_driver_attach effectuera les opérations suivantes :

  1. Obtenez les informations de configuration des broches de l'appareil ;
  2. Établissez un lien entre le pilote et le périphérique dans le répertoire /sys ;
  3. La fonction sonde du bus où se trouve le dispositif est appelée en premier, sinon la fonction sonde du driver est appelée ;
  4. Configurez toutes les broches de l'appareil à l'état par défaut ;

Par exemple, le bus de la plate-forme n'implémente pas la fonction de sonde, donc la fonction platform_drv_probe() attribuée lors de l'enregistrement du pilote sera appelée. Ici, la fonction de sonde du pilote de plate-forme est en fait appelée, qui est la fonction de sonde implémentée par le pilote. lui-même.

Lorsque la fonction de sonde est appelée, cela prouve que le modèle de pilote de périphérique de l'ensemble du noyau Linux a été exécuté. Cependant, pour savoir si le périphérique existe réellement, la fonction de sonde doit être implémentée. Une fois que la fonction de sonde a confirmé que le périphérique existe, elle Il sera possible de demander des ressources et des nœuds de périphériques associés.

modèle de pilote de périphérique

modèle de pilote de périphérique de plate-forme

Je suppose que tu aimes

Origine blog.csdn.net/weixin_41944449/article/details/132963909
conseillé
Classement