{"id":4994,"date":"2025-11-07T18:59:44","date_gmt":"2025-11-07T17:59:44","guid":{"rendered":"https:\/\/workboot.fr\/ciela\/?page_id=4994"},"modified":"2025-11-08T10:35:45","modified_gmt":"2025-11-08T09:35:45","slug":"module-allons-dans-le-noyau","status":"publish","type":"page","link":"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/","title":{"rendered":"module , allons dans le noyau"},"content":{"rendered":"\n<nav aria-label=\"Table des mati\u00e8res\" class=\"wp-block-table-of-contents\"><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#partie-1-fondamentaux\">PARTIE 1 : FONDAMENTAUX<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#1-1-architecture-linux-espace-noyau-vs-espace-utilisateur\">1.1 Architecture Linux : Espace noyau vs espace utilisateur<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#1-2-qu-est-ce-qu-un-module-noyau\">1.2 Qu&rsquo;est-ce qu&rsquo;un module noyau ?<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#1-3-differences-avec-la-programmation-applicative\">1.3 Diff\u00e9rences avec la programmation applicative <\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#partie-2-environnement-de-developpement\">PARTIE 2 : ENVIRONNEMENT DE D\u00c9VELOPPEMENT <\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#2-1-installation-des-outils-sur-debian-12\">2.1 Installation des outils sur Debian 12<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#2-2-structure-d-un-projet-de-module\">2.2 Structure d&rsquo;un projet de module<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#premier-module-hello-world\">Premier module : Hello World <\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#partie-3-anatomie-d-un-module\">PARTIE 3 : ANATOMIE D&rsquo;UN MODULE<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#3-1-structure-de-base-complete\">3.1 Structure de base compl\u00e8te<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#3-2-explications-detaillees\">3.2 Explications d\u00e9taill\u00e9es<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#les-macros-essentielles\">Les macros essentielles :<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#gestion-d-erreurs-avec-pattern-goto\">Gestion d&rsquo;erreurs avec pattern goto :<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#3-3-module-avec-meilleures-pratiques\">3.3 Module avec meilleures pratiques<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#3-4-makefile-avance\">3.4 Makefile avanc\u00e9 <\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#3-5-commandes-de-test-avancees\">3.5 Commandes de test avanc\u00e9es<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#points-cles-a-retenir\">Points cl\u00e9s \u00e0 retenir :<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#partie-4-bibliotheques-et-api-du-noyau\">PARTIE 4 : BIBLIOTH\u00c8QUES ET API DU NOYAU<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#4-1-headers-principaux-revision-etendue\">4.1 Headers principaux &#8211; R\u00e9vision \u00e9tendue<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#4-2-api-memoire-approfondissement\">4.2 API M\u00e9moire &#8211; Approfondissement<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#4-4-api-gpio-partie-critique\">4.4 API GPIO &#8211; PARTIE CRITIQUE<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#4-4-1-concepts-gpio-de-base\">4.4.1 Concepts GPIO de base<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#4-4-2-module-gpio-complet-avec-led\">4.4.2 Module GPIO complet avec LED<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#4-5-api-timers-pour-execution-periodique\">4.5 API Timers &#8211; Pour ex\u00e9cution p\u00e9riodique<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#4-6-makefile-pour-modules-gpio\">4.6 Makefile pour modules GPIO<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#4-7-commandes-de-test-gpio\">4.7 Commandes de test GPIO<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#partie-5-exemples-progressifs\">PARTIE 5 : EXEMPLES PROGRESSIFS<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#5-1-module-hello-world-ameliore\">5.1 Module \u00ab\u00a0Hello World\u00a0\u00bb am\u00e9lior\u00e9<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#5-2-module-de-journalisation-dans-un-fichier\">5.2 Module de journalisation dans un fichier<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#5-3-module-gpio-complet-pour-controle-led\">5.3 Module GPIO complet pour contr\u00f4le LED<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#5-4-module-avec-timer-pour-execution-periodique\">5.4 Module avec timer pour ex\u00e9cution p\u00e9riodique<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#5-5-makefile-pour-tous-les-exemples\">5.5 Makefile pour tous les exemples<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#5-6-script-de-demonstration-complet\">5.6 Script de d\u00e9monstration complet<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#partie-6-bonnes-pratiques\">PARTIE 6 : BONNES PRATIQUES<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#6-1-gestion-des-erreurs-et-nettoyage-des-ressources\">6.1 Gestion des erreurs et nettoyage des ressources<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#6-1-1-pattern-de-gestion-d-erreurs-robuste\">6.1.1 Pattern de gestion d&rsquo;erreurs robuste<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#6-2-securite-et-stabilite\">6.2 S\u00e9curit\u00e9 et stabilit\u00e9<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#6-2-1-verifications-de-securite-critiques\">6.2.1 V\u00e9rifications de s\u00e9curit\u00e9 critiques<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#6-3-debogage-avec-dmesg-et-printk\">6.3 D\u00e9bogage avec dmesg et printk<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#6-3-1-module-de-debogage-avance\">6.3.1 Module de d\u00e9bogage avanc\u00e9<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#6-4-compilation-avec-makefile-avance\">6.4 Compilation avec Makefile avanc\u00e9<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#6-5-script-de-monitoring-et-debogage\">6.5 Script de monitoring et d\u00e9bogage<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#6-6-commandes-de-debogage-essentielles\">6.6 Commandes de d\u00e9bogage essentielles<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#points-cles-des-bonnes-pratiques\">Points cl\u00e9s des bonnes pratiques :<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#partie-7-concepts-avances\">PARTIE 7 : CONCEPTS AVANC\u00c9S<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#7-1-interruptions-et-gestionnaires-d-irq\">7.1 Interruptions et gestionnaires d&rsquo;IRQ<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#7-1-1-module-avec-gestion-d-interruption-gpio\">7.1.1 Module avec gestion d&rsquo;interruption GPIO<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#7-2-systemes-de-fichiers-virtuels\">7.2 Syst\u00e8mes de fichiers virtuels<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#7-2-1-interface-procfs-pour-le-module\">7.2.1 Interface procfs pour le module<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#7-3-peripheriques-caracteres\">7.3 P\u00e9riph\u00e9riques caract\u00e8res<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#7-3-1-driver-de-peripherique-caractere-complet\">7.3.1 Driver de p\u00e9riph\u00e9rique caract\u00e8re complet<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#7-4-synchronisation-mutex-spinlocks\">7.4 Synchronisation : mutex, spinlocks<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#7-4-1-module-de-demonstration-de-synchronisation\">7.4.1 Module de d\u00e9monstration de synchronisation<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/#7-5-makefile-pour-les-concepts-avances\">7.5 Makefile pour les concepts avanc\u00e9s<\/a><\/li><\/ol><\/li><\/ol><\/nav>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"partie-1-fondamentaux\">PARTIE 1 : FONDAMENTAUX<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"1-1-architecture-linux-espace-noyau-vs-espace-utilisateur\">1.1 Architecture Linux : Espace noyau vs espace utilisateur<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>Syst\u00e8me Linux\n\u251c\u2500\u2500 Espace utilisateur (User Space)\n\u2502   \u251c\u2500\u2500 Applications (bash, gcc, etc.)\n\u2502   \u251c\u2500\u2500 Biblioth\u00e8ques (libc, etc.)\n\u2502   \u2514\u2500\u2500 Appels syst\u00e8me (syscalls)\n\u2502\n\u2514\u2500\u2500 Espace noyau (Kernel Space)\n    \u251c\u2500\u2500 Modules noyau\n    \u251c\u2500\u2500 Gestionnaire de m\u00e9moire\n    \u251c\u2500\u2500 Planificateur (scheduler)\n    \u251c\u2500\u2500 Pilotes de p\u00e9riph\u00e9riques\n    \u2514\u2500\u2500 Syst\u00e8me de fichiers<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Diff\u00e9rences cl\u00e9s :<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Aspect<\/th><th class=\"has-text-align-left\" data-align=\"left\">Espace utilisateur<\/th><th class=\"has-text-align-left\" data-align=\"left\">Espace noyau<\/th><\/tr><\/thead><tbody><tr><td><strong>Acc\u00e8s m\u00e9moire<\/strong><\/td><td>M\u00e9moire virtuelle limit\u00e9e<\/td><td>Acc\u00e8s complet \u00e0 toute la m\u00e9moire<\/td><\/tr><tr><td><strong>Privil\u00e8ges<\/strong><\/td><td>Restrictions s\u00e9v\u00e8res<\/td><td>Privil\u00e8ges maximum<\/td><\/tr><tr><td><strong>Stabilit\u00e9<\/strong><\/td><td>Processus isol\u00e9<\/td><td>Panne = crash syst\u00e8me<\/td><\/tr><tr><td><strong>D\u00e9bogage<\/strong><\/td><td>Outils classiques (gdb)<\/td><td>D\u00e9bogage complexe<\/td><\/tr><tr><td><strong>API<\/strong><\/td><td>Biblioth\u00e8ques standards (libc)<\/td><td>API noyau sp\u00e9cifiques<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"1-2-qu-est-ce-qu-un-module-noyau\">1.2 Qu&rsquo;est-ce qu&rsquo;un module noyau ?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>D\u00e9finition :<\/strong><br>Un module noyau est un morceau de code compil\u00e9 qui peut \u00eatre charg\u00e9 et d\u00e9charg\u00e9 dynamiquement dans le noyau Linux, sans n\u00e9cessiter de red\u00e9marrage.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Avantages :<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Modularit\u00e9<\/strong>&nbsp;: Extension des fonctionnalit\u00e9s sans recompiler le noyau<\/li>\n\n\n\n<li><strong>D\u00e9veloppement<\/strong>&nbsp;: Test plus facile qu&rsquo;un patch noyau complet<\/li>\n\n\n\n<li><strong>Maintenance<\/strong>&nbsp;: Mise \u00e0 jour sans red\u00e9marrage du syst\u00e8me<\/li>\n\n\n\n<li><strong>Sp\u00e9cialisation<\/strong>&nbsp;: Chargement uniquement des fonctionnalit\u00e9s n\u00e9cessaires<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Limitations importantes :<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u274c&nbsp;<strong>Pas de biblioth\u00e8que C standard<\/strong>&nbsp;(pas de printf, malloc, etc.)<\/li>\n\n\n\n<li>\u274c&nbsp;<strong>Pas de protection m\u00e9moire<\/strong>&nbsp;(erreur = panne syst\u00e8me)<\/li>\n\n\n\n<li>\u274c&nbsp;<strong>Pas de floating point<\/strong>&nbsp;(sauf avec pr\u00e9cautions)<\/li>\n\n\n\n<li>\u274c&nbsp;<strong>Stack limit\u00e9e<\/strong>&nbsp;(4Ko-8Ko typiquement)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"1-3-differences-avec-la-programmation-applicative\">1.3 Diff\u00e9rences avec la programmation applicative<br><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Exemple comparatif :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ PROGRAMMATION APPLICATIVE (espace utilisateur)\n#include &lt;stdio.h>\n#include &lt;stdlib.h>\n\nint main() {\n    char *buffer = malloc(100);  \/\/ malloc standard\n    printf(\"Hello World!\\n\");    \/\/ printf standard\n    free(buffer);\n    return 0;\n}\n\n<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ PROGRAMMATION NOYAU (espace noyau)\n#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/slab.h>\n\nstatic int __init mon_module_init(void) {\n    char *buffer = kmalloc(100, GFP_KERNEL);  \/\/ kmalloc du noyau\n    printk(KERN_INFO \"Hello Kernel!\\n\");      \/\/ printk du noyau\n    kfree(buffer);\n    return 0;\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Points critiques :<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Gestion m\u00e9moire<\/strong>&nbsp;:&nbsp;<code>kmalloc\/kfree<\/code>&nbsp;au lieu de&nbsp;<code>malloc\/free<\/code><\/li>\n\n\n\n<li><strong>Affichage<\/strong>&nbsp;:&nbsp;<code>printk<\/code>&nbsp;au lieu de&nbsp;<code>printf<\/code><\/li>\n\n\n\n<li><strong>Entr\u00e9e\/sortie<\/strong>&nbsp;: Pas de fonctions standards (fopen, fread, etc.)<\/li>\n\n\n\n<li><strong>Concurrence<\/strong>&nbsp;: Gestion explicite n\u00e9cessaire (mutex, spinlocks)<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"partie-2-environnement-de-developpement\">PARTIE 2 : ENVIRONNEMENT DE D\u00c9VELOPPEMENT<br><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"2-1-installation-des-outils-sur-debian-12\">2.1 Installation des outils sur Debian 12<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Commandes d&rsquo;installation :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Mettre \u00e0 jour le syst\u00e8me\nsudo apt update &amp;&amp; sudo apt upgrade -y\n\n# Installer les outils de d\u00e9veloppement\nsudo apt install -y build-essential linux-headers-$(uname -r) \nsudo apt install -y libelf-dev libssl-dev flex bison\nsudo apt install -y git gdb dmesg\n\n# V\u00e9rifier l'installation\nuname -r  # Doit afficher la version du noyau (ex: 6.1.0-10-amd64)\nls \/usr\/src\/linux-headers-$(uname -r)  # Doit exister<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"2-2-structure-d-un-projet-de-module\">2.2 Structure d&rsquo;un projet de module<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Arborescence recommand\u00e9e :<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mon_module\/\n\u251c\u2500\u2500 Makefile\n\u251c\u2500\u2500 src\/\n\u2502   \u251c\u2500\u2500 module_principal.c\n\u2502   \u2514\u2500\u2500 module_secondaire.c\n\u251c\u2500\u2500 include\/\n\u2502   \u2514\u2500\u2500 definitions.h\n\u2514\u2500\u2500 scripts\/\n    \u2514\u2500\u2500 test_module.sh<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>AVERTISSEMENT IMPORTANT :<\/strong><br>\u26a0\ufe0f&nbsp;<strong>TOUJOURS tester les modules dans une machine virtuelle<\/strong><br>\u26a0\ufe0f&nbsp;<strong>NE JAMAIS d\u00e9velopper sur votre machine principale<\/strong><br>\u26a0\ufe0f&nbsp;<strong>Une erreur dans un module peut crasher tout le syst\u00e8me<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"premier-module-hello-world\">Premier module : Hello World<br><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Cr\u00e9ons notre premier module pour valider l&rsquo;environnement :<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>hello_world.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n\n\/\/ Macro de licence (OBLIGATOIRE)\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Votre Nom\");\nMODULE_DESCRIPTION(\"Mon premier module noyau\");\nMODULE_VERSION(\"1.0\");\n\n\/\/ Fonction d'initialisation\nstatic int __init hello_init(void)\n{\n    \/\/ printk pour l'affichage dans les logs noyau\n    \/\/ KERN_INFO est le niveau de log\n    printk(KERN_INFO \"Hello World! Module charge avec succes.\\n\");\n    return 0; \/\/ 0 = succ\u00e8s\n}\n\n\/\/ Fonction de nettoyage\nstatic void __exit hello_exit(void)\n{\n    printk(KERN_INFO \"Au revoir! Module decharge.\\n\");\n}\n\n\/\/ D\u00e9claration des points d'entr\u00e9e\nmodule_init(hello_init);\nmodule_exit(hello_exit);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Makefile correspondant :<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">makefile<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Sp\u00e9cifier la version du noyau\nKVERSION = $(shell uname -r)\n\n# Nom du module\nMODULE_NAME = hello_world\nobj-m += $(MODULE_NAME).o\n\n# R\u00e8gle de compilation\nall:\n\tmake -C \/lib\/modules\/$(KVERSION)\/build M=$(PWD) modules\n\n# R\u00e8gle de nettoyage\nclean:\n\tmake -C \/lib\/modules\/$(KVERSION)\/build M=$(PWD) clean\n\n# R\u00e8gle d'installation\ninstall:\n\tsudo insmod $(MODULE_NAME).ko\n\n# R\u00e8gle de d\u00e9sinstallation\nuninstall:\n\tsudo rmmod $(MODULE_NAME)\n\n# R\u00e8gle de test\ntest: all install\n\tdmesg | tail -5\n\tsleep 2\n\tmake uninstall\n\tdmesg | tail -5<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Commandes de test :<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Compiler le module\nmake\n\n# Charger le module\nsudo insmod hello_world.ko\n\n# V\u00e9rifier qu'il est charg\u00e9\nlsmod | grep hello_world\n\n# Voir les logs\ndmesg | tail -5\n\n# D\u00e9charger le module\nsudo rmmod hello_world\n\n# V\u00e9rifier les messages de sortie\ndmesg | tail -5<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Explications ligne par ligne :<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>#include &lt;linux\/module.h&gt;<\/code>&nbsp;: D\u00e9finitions de base pour les modules<\/li>\n\n\n\n<li><code>#include &lt;linux\/kernel.h&gt;<\/code>&nbsp;: Fonctions noyau comme printk<\/li>\n\n\n\n<li><code>#include &lt;linux\/init.h&gt;<\/code>&nbsp;: Macros __init et __exit<\/li>\n\n\n\n<li><code>MODULE_LICENSE(\"GPL\")<\/code>&nbsp;:&nbsp;<strong>OBLIGATOIRE<\/strong>&nbsp;&#8211; sp\u00e9cifie la licence<\/li>\n\n\n\n<li><code>static int __init<\/code>&nbsp;: Fonction ex\u00e9cut\u00e9e au chargement<\/li>\n\n\n\n<li><code>__init<\/code>&nbsp;: Le code peut \u00eatre lib\u00e9r\u00e9 apr\u00e8s initialisation<\/li>\n\n\n\n<li><code>printk(KERN_INFO \"...\")<\/code>&nbsp;: \u00c9quivalent noyau de printf<\/li>\n\n\n\n<li><code>module_init\/exit<\/code>&nbsp;: Points d&rsquo;entr\u00e9e\/sortie du module<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"partie-3-anatomie-d-un-module\">PARTIE 3 : ANATOMIE D&rsquo;UN MODULE<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3-1-structure-de-base-complete\">3.1 Structure de base compl\u00e8te<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Voici un module plus complet qui montre tous les \u00e9l\u00e9ments essentiels :<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/slab.h>       \/\/ Pour kmalloc\/kfree\n#include &lt;linux\/errno.h>      \/\/ Codes d'erreur\n\n\/\/ ============================================================================\n\/\/ SECTION : METADONNEES DU MODULE\n\/\/ ============================================================================\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Votre Nom &lt;email@example.com>\");\nMODULE_DESCRIPTION(\"Module demonstrant l'anatomie complete d'un module noyau\");\nMODULE_VERSION(\"1.0\");\n\n\/\/ Parametres du module (peuvent etre passes a l'insertion)\nstatic char *parametre_texte = \"valeur_par_defaut\";\nstatic int parametre_numerique = 42;\n\nmodule_param(parametre_texte, charp, 0644);\nMODULE_PARM_DESC(parametre_texte, \"Un parametre texte modifiable\");\n\nmodule_param(parametre_numerique, int, 0644);\nMODULE_PARM_DESC(parametre_numerique, \"Un parametre numerique\");\n\n\/\/ ============================================================================\n\/\/ SECTION : VARIABLES GLOBALES ET ETAT\n\/\/ ============================================================================\n\nstatic struct kmem_cache *mon_cache = NULL;\nstatic void *allocation_persistante = NULL;\nstatic int compteur_operations = 0;\n\n\/\/ ============================================================================\n\/\/ SECTION : FONCTION D'INITIALISATION\n\/\/ ============================================================================\n\nstatic int __init mon_module_init(void)\n{\n    int resultat = 0;\n    \n    printk(KERN_INFO \"=== DEBUT INITIALISATION MODULE ===\\n\");\n    printk(KERN_INFO \"Parametres: texte='%s', numerique=%d\\n\", \n           parametre_texte, parametre_numerique);\n    \n    \/\/ 1. Allocation de memoire\n    allocation_persistante = kmalloc(1024, GFP_KERNEL);\n    if (!allocation_persistante) {\n        printk(KERN_ERR \"ECHEC: Impossible d'allouer 1024 octets\\n\");\n        resultat = -ENOMEM;\n        goto erreur_allocation;\n    }\n    printk(KERN_INFO \"SUCCES: Memoire allouee (1024 octets)\\n\");\n    \n    \/\/ 2. Creation d'un cache memoire\n    mon_cache = kmem_cache_create(\"mon_cache_noyau\", \n                                  256, 0, SLAB_HWCACHE_ALIGN, NULL);\n    if (!mon_cache) {\n        printk(KERN_ERR \"ECHEC: Creation du cache memoire\\n\");\n        resultat = -ENOMEM;\n        goto erreur_cache;\n    }\n    printk(KERN_INFO \"SUCCES: Cache memoire cree\\n\");\n    \n    \/\/ 3. Initialisation des compteurs\n    compteur_operations = 0;\n    \n    printk(KERN_INFO \"=== INITIALISATION TERMINEE AVEC SUCCES ===\\n\");\n    return 0;\n\n\/\/ ============================================================================\n\/\/ SECTION : GESTION DES ERREURS (PATTERN goto)\n\/\/ ============================================================================\n\nerreur_cache:\n    kfree(allocation_persistante);\n    \nerreur_allocation:\n    printk(KERN_ERR \"=== INITIALISATION ECHOUEE (code: %d) ===\\n\", resultat);\n    return resultat;\n}\n\n\/\/ ============================================================================\n\/\/ SECTION : FONCTION DE NETTOYAGE\n\/\/ ============================================================================\n\nstatic void __exit mon_module_exit(void)\n{\n    printk(KERN_INFO \"=== DEBUT NETTOYAGE MODULE ===\\n\");\n    \n    \/\/ 1. Destruction du cache memoire\n    if (mon_cache) {\n        kmem_cache_destroy(mon_cache);\n        printk(KERN_INFO \"Cache memoire detruit\\n\");\n    }\n    \n    \/\/ 2. Liberation de la memoire\n    if (allocation_persistante) {\n        kfree(allocation_persistante);\n        printk(KERN_INFO \"Memoire liberee\\n\");\n    }\n    \n    \/\/ 3. Affichage des statistiques\n    printk(KERN_INFO \"Operations effectuees: %d\\n\", compteur_operations);\n    \n    printk(KERN_INFO \"=== NETTOYAGE TERMINEE ===\\n\");\n}\n\n\/\/ ============================================================================\n\/\/ SECTION : POINTS D'ENTREE PRINCIPAUX\n\/\/ ============================================================================\n\nmodule_init(mon_module_init);\nmodule_exit(mon_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3-2-explications-detaillees\">3.2 Explications d\u00e9taill\u00e9es<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"les-macros-essentielles\">Les macros essentielles :<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>MODULE_LICENSE()<\/strong>&nbsp;&#8211;&nbsp;<strong>CRITIQUE<\/strong>&nbsp;:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">MODULE_LICENSE(\"GPL\");                    \/\/ Licence GPL\n\/\/ MODULE_LICENSE(\"GPL v2\");             \/\/ GPL version 2  \n\/\/ MODULE_LICENSE(\"Dual BSD\/GPL\");       \/\/ Double licence\n\/\/ MODULE_LICENSE(\"Proprietary\");        \/\/ Licence propri\u00e9taire (limitations)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Sans MODULE_LICENSE(), le module marquera le noyau comme \u00ab\u00a0tainted\u00a0\u00bb !<\/strong><br><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>module_param()<\/strong>&nbsp;: Permet de passer des param\u00e8tres au module :<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static int ma_variable = 10;\nmodule_param(ma_variable, int, 0644);\n\/\/ Types: bool, charp, int, long, short, uint, ulong, ushort\n\/\/ Permissions: 0644 (rw-r--r--), 0444 (r--r--r--), etc.<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"gestion-d-erreurs-avec-pattern-goto\">Gestion d&rsquo;erreurs avec pattern goto :<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Pourquoi utiliser goto en noyau ?<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static int __init init(void)\n{\n    res = alloc_A();\n    if (!res) goto err_A;\n    \n    res = alloc_B(); \n    if (!res) goto err_B;\n    \n    res = alloc_C();\n    if (!res) goto err_C;\n    \n    return 0;  \/\/ Succ\u00e8s\n\nerr_C:\n    free_B();\nerr_B:\n    free_A(); \nerr_A:\n    return -ENOMEM;\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ce pattern est PR\u00c9F\u00c9R\u00c9 car :<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Plus lisible que des if\/else imbriqu\u00e9s<\/li>\n\n\n\n<li>Garantit le bon ordre de nettoyage<\/li>\n\n\n\n<li>Standard dans le code noyau Linux<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3-3-module-avec-meilleures-pratiques\">3.3 Module avec meilleures pratiques<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>advanced_module.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/slab.h>\n#include &lt;linux\/errno.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Expert Kernel\");\nMODULE_DESCRIPTION(\"Module avec gestion d'erreur robuste\");\n\n#define DEVICE_NAME \"mon_device\"\n#define BUFFER_SIZE 4096\n\nstatic struct {\n    void *buffer_principal;\n    void *buffer_secondaire;\n    int devices_crees;\n    bool initialisation_terminee;\n} etat_global = {\n    .buffer_principal = NULL,\n    .buffer_secondaire = NULL, \n    .devices_crees = 0,\n    .initialisation_terminee = false\n};\n\n\/\/ Fonction de nettoyage interm\u00e9diaire\nstatic void nettoyage_partiel(void)\n{\n    printk(KERN_INFO \"Nettoyage des ressources partielles...\\n\");\n    \n    if (etat_global.buffer_secondaire) {\n        kfree(etat_global.buffer_secondaire);\n        etat_global.buffer_secondaire = NULL;\n        printk(KERN_INFO \"Buffer secondaire libere\\n\");\n    }\n    \n    if (etat_global.buffer_principal) {\n        kfree(etat_global.buffer_principal);\n        etat_global.buffer_principal = NULL;\n        printk(KERN_INFO \"Buffer principal libere\\n\");\n    }\n}\n\nstatic int __init mon_module_init(void)\n{\n    int ret = 0;\n    \n    printk(KERN_INFO \"Initialisation du module avance...\\n\");\n    \n    \/\/ \u00c9tape 1: Allocation buffer principal\n    etat_global.buffer_principal = kmalloc(BUFFER_SIZE, GFP_KERNEL);\n    if (!etat_global.buffer_principal) {\n        printk(KERN_ERR \"Echec allocation buffer principal\\n\");\n        ret = -ENOMEM;\n        goto echec_init;\n    }\n    printk(KERN_INFO \"Buffer principal alloue (%d octets)\\n\", BUFFER_SIZE);\n    \n    \/\/ \u00c9tape 2: Allocation buffer secondaire  \n    etat_global.buffer_secondaire = kzalloc(BUFFER_SIZE \/ 2, GFP_KERNEL);\n    if (!etat_global.buffer_secondaire) {\n        printk(KERN_ERR \"Echec allocation buffer secondaire\\n\");\n        ret = -ENOMEM;\n        goto echec_init;\n    }\n    printk(KERN_INFO \"Buffer secondaire alloue et initialise a zero\\n\");\n    \n    \/\/ \u00c9tape 3: Simulation creation device\n    \/\/ Normalement: register_chrdev, device_create, etc.\n    etat_global.devices_crees = 1;\n    printk(KERN_INFO \"Device '%s' cree\\n\", DEVICE_NAME);\n    \n    \/\/ Marquer l'initialisation comme reussie\n    etat_global.initialisation_terminee = true;\n    \n    printk(KERN_INFO \"=== MODULE CHARGE AVEC SUCCES ===\\n\");\n    return 0;\n\nechec_init:\n    nettoyage_partiel();\n    printk(KERN_ERR \"=== ECHEC CHARGEMENT MODULE (code: %d) ===\\n\", ret);\n    return ret;\n}\n\nstatic void __exit mon_module_exit(void)\n{\n    printk(KERN_INFO \"Dechargement du module...\\n\");\n    \n    if (!etat_global.initialisation_terminee) {\n        printk(KERN_WARNING \"Module jamais initialise completement\\n\");\n        nettoyage_partiel();\n        return;\n    }\n    \n    \/\/ Simulation suppression device\n    if (etat_global.devices_crees > 0) {\n        printk(KERN_INFO \"Device '%s' supprime\\n\", DEVICE_NAME);\n        etat_global.devices_crees = 0;\n    }\n    \n    \/\/ Liberation memoire\n    nettoyage_partiel();\n    \n    printk(KERN_INFO \"=== MODULE DECHARGE AVEC SUCCES ===\\n\");\n}\n\nmodule_init(mon_module_init);\nmodule_exit(mon_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3-4-makefile-avance\">3.4 Makefile avanc\u00e9<br><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Makefile :<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Configuration\nKVERSION := $(shell uname -r)\nKDIR := \/lib\/modules\/$(KVERSION)\/build\nPWD := $(shell pwd)\n\n# Modules a compiler\nobj-m += hello_world.o\nobj-m += module_anatomy.o  \nobj-m += advanced_module.o\n\n# Flags de compilation\nccflags-y := -DDEBUG -Wall -Wextra\n\n# Cible par defaut\nall:\n\t$(MAKE) -C $(KDIR) M=$(PWD) modules\n\n# Cible de debogage\ndebug: ccflags-y += -DDEBUG -g\ndebug: all\n\n# Nettoyage\nclean:\n\t$(MAKE) -C $(KDIR) M=$(PWD) clean\n\n# Installation et test\ntest-module: all\n\tsudo dmesg -C\n\tsudo insmod hello_world.ko\n\tdmesg | tail -3\n\tsudo rmmod hello_world\n\tdmesg | tail -3\n\ntest-advanced: all  \n\tsudo dmesg -C\n\tsudo insmod advanced_module.ko\n\tdmesg\n\tsudo rmmod advanced_module\n\tdmesg\n\n# Aide\nhelp:\n\t@echo \"Cibles disponibles:\"\n\t@echo \"  all          - Compiler tous les modules\"\n\t@echo \"  debug        - Compiler avec symboles de debogage\"\n\t@echo \"  clean        - Nettoyer les fichiers generes\"\n\t@echo \"  test-module  - Tester le module hello_world\"\n\t@echo \"  test-advanced - Tester le module avance\"\n\n.PHONY: all clean debug test-module test-advanced help<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3-5-commandes-de-test-avancees\">3.5 Commandes de test avanc\u00e9es<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Script de test complet :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#!\/bin\/bash\n# test_complet.sh\n\necho \"=== TEST COMPLET DES MODULES ===\"\n\n# Compilation\necho \"1. Compilation...\"\nmake clean\nmake\n\n# Test parametres\necho \"2. Test avec parametres...\"\nsudo insmod module_anatomy.ko parametre_texte=\"test_valeur\" parametre_numerique=123\ndmesg | tail -5\nsudo rmmod module_anatomy\n\necho \"3. Test valeurs par defaut...\"\nsudo insmod module_anatomy.ko\ndmesg | tail -5  \nsudo rmmod module_anatomy\n\necho \"4. Test module avance...\"\nsudo insmod advanced_module.ko\ndmesg | tail -10\nsudo rmmod advanced_module\ndmesg | tail -5\n\necho \"=== TESTS TERMINES ===\"<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Commandes utiles pour l&rsquo;inspection :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Voir les modules charges\nlsmod\n\n# Voir les parametres d'un module (si charges)\nsudo modinfo hello_world.ko\n\n# Surveiller les logs noyau en temps reel\nsudo dmesg -w\n\n# Voir l'utilisation memoire des modules\ncat \/proc\/modules\n\n# Checker le statut 'tainted'\ncat \/proc\/sys\/kernel\/tainted<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"points-cles-a-retenir\">Points cl\u00e9s \u00e0 retenir :<\/h3>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Toujours impl\u00e9menter module_init() et module_exit()<\/strong><\/li>\n\n\n\n<li><strong>MODULE_LICENSE() est OBLIGATOIRE<\/strong><\/li>\n\n\n\n<li><strong>Utiliser le pattern goto pour la gestion d&rsquo;erreurs<\/strong><\/li>\n\n\n\n<li><strong>Nettoyer TOUTES les ressources dans la fonction exit<\/strong><\/li>\n\n\n\n<li><strong>printk() pour le d\u00e9bogage, pas de printf()<\/strong><\/li>\n\n\n\n<li><strong>Tester syst\u00e9matiquement les \u00e9checs d&rsquo;allocation<\/strong><\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>AVERTISSEMENT :<\/strong>&nbsp;Ces modules sont \u00e9ducatifs. En production, ajoutez :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>V\u00e9rifications de s\u00e9curit\u00e9 suppl\u00e9mentaires<\/li>\n\n\n\n<li>Gestion de la concurrence (mutex)<\/li>\n\n\n\n<li>Support de la configuration via sysfs\/procfs<\/li>\n\n\n\n<li>Gestion d&rsquo;\u00e9nergie (suspend\/resume)<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"partie-4-bibliotheques-et-api-du-noyau\">PARTIE 4 : BIBLIOTH\u00c8QUES ET API DU NOYAU<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"4-1-headers-principaux-revision-etendue\">4.1 Headers principaux &#8211; R\u00e9vision \u00e9tendue<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>    \/\/ D\u00e9finitions de base des modules\n#include &lt;linux\/kernel.h>    \/\/ Fonctions noyau (printk, etc.)\n#include &lt;linux\/init.h>      \/\/ Macros __init, __exit\n#include &lt;linux\/slab.h>      \/\/ Allocation m\u00e9moire (kmalloc, kfree)\n#include &lt;linux\/fs.h>        \/\/ Syst\u00e8me de fichiers\n#include &lt;linux\/errno.h>     \/\/ Codes d'erreur\n#include &lt;linux\/device.h>    \/\/ Infrastructure device\n#include &lt;linux\/cdev.h>      \/\/ P\u00e9riph\u00e9riques caract\u00e8res\n#include &lt;linux\/uaccess.h>   \/\/ copy_to_user, copy_from_user\n#include &lt;linux\/io.h>        \/\/ Acc\u00e8s m\u00e9moire mapp\u00e9 (ioremap, iounmap)\n#include &lt;linux\/interrupt.h> \/\/ Gestion d'interruptions\n#include &lt;linux\/gpio.h>      \/\/ API GPIO - IMPORTANT POUR NOUS\n#include &lt;linux\/of.h>        \/\/ Device Tree\n#include &lt;linux\/of_gpio.h>   \/\/ GPIO via Device Tree\n#include &lt;linux\/delay.h>     \/\/ D\u00e9lais (msleep, udelay)<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"4-2-api-memoire-approfondissement\">4.2 API M\u00e9moire &#8211; Approfondissement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Exemple complet d&rsquo;allocations m\u00e9moire :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/slab.h>\n#include &lt;linux\/vmalloc.h>\n\nstatic void demo_memoire(void)\n{\n    void *kmalloc_ptr = NULL;\n    void *kzalloc_ptr = NULL; \n    void *vmalloc_ptr = NULL;\n    int *tableau = NULL;\n    \n    \/\/ 1. kmalloc - m\u00e9moire physique contigu\u00eb (rapide)\n    kmalloc_ptr = kmalloc(1024, GFP_KERNEL);\n    if (!kmalloc_ptr) {\n        printk(KERN_ERR \"kmalloc a \u00e9chou\u00e9\\n\");\n        return;\n    }\n    printk(KERN_INFO \"kmalloc r\u00e9ussi: %p\\n\", kmalloc_ptr);\n    \n    \/\/ 2. kzalloc - kmalloc + initialisation \u00e0 z\u00e9ro\n    kzalloc_ptr = kzalloc(512, GFP_KERNEL);\n    if (!kzalloc_ptr) {\n        printk(KERN_ERR \"kzalloc a \u00e9chou\u00e9\\n\");\n        goto erreur;\n    }\n    printk(KERN_INFO \"kzalloc r\u00e9ussi: %p (initialis\u00e9 \u00e0 0)\\n\", kzalloc_ptr);\n    \n    \/\/ 3. Tableau avec kmalloc_array\n    tableau = kmalloc_array(100, sizeof(int), GFP_KERNEL);\n    if (!tableau) {\n        printk(KERN_ERR \"kmalloc_array a \u00e9chou\u00e9\\n\");\n        goto erreur;\n    }\n    printk(KERN_INFO \"Tableau de 100 int allou\u00e9: %p\\n\", tableau);\n    \n    \/\/ 4. vmalloc - m\u00e9moire virtuelle (peut \u00eatre non contigu\u00eb en physique)\n    vmalloc_ptr = vmalloc(8192);  \/\/ 8KB\n    if (!vmalloc_ptr) {\n        printk(KERN_ERR \"vmalloc a \u00e9chou\u00e9\\n\");\n        goto erreur;\n    }\n    printk(KERN_INFO \"vmalloc r\u00e9ussi: %p\\n\", vmalloc_ptr);\n    \n    \/\/ Utilisation...\n    memset(kmalloc_ptr, 0xAA, 1024);\n    memset(tableau, 0, 100 * sizeof(int));\n    \nerreur:\n    \/\/ Nettoyage dans l'ordre INVERSE\n    if (vmalloc_ptr) vfree(vmalloc_ptr);\n    if (tableau) kfree(tableau);\n    if (kzalloc_ptr) kfree(kzalloc_ptr);\n    if (kmalloc_ptr) kfree(kmalloc_ptr);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"4-4-api-gpio-partie-critique\">4.4 API GPIO &#8211; PARTIE CRITIQUE<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"4-4-1-concepts-gpio-de-base\">4.4.1 Concepts GPIO de base<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>D\u00e9finitions :<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>GPIO<\/strong>&nbsp;: General Purpose Input\/Output<\/li>\n\n\n\n<li><strong>Direction<\/strong>&nbsp;: INPUT (lecture) ou OUTPUT (\u00e9criture)<\/li>\n\n\n\n<li><strong>Valeur<\/strong>&nbsp;: HIGH (1) ou LOW (0)<\/li>\n\n\n\n<li><strong>Actif<\/strong>&nbsp;: ACTIVE_HIGH ou ACTIVE_LOW<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"4-4-2-module-gpio-complet-avec-led\">4.4.2 Module GPIO complet avec LED<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>gpio_led.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/gpio.h>\n#include &lt;linux\/delay.h>\n#include &lt;linux\/errno.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Expert GPIO\");\nMODULE_DESCRIPTION(\"Controle LED via GPIO avec gestion d'erreurs robuste\");\n\n\/\/ ============================================================================\n\/\/ CONFIGURATION GPIO - \u00c0 ADAPTER \u00c0 VOTRE MAT\u00c9RIEL !\n\/\/ ============================================================================\n\n\/*\n * IMPORTANT: Choisir les GPIO selon votre carte:\n * - Raspberry Pi: GPIO4=broche7, GPIO17=broche11, GPIO18=broche12\n * - BeagleBone: GPIO_20=brocheP9.41, GPIO_60=brocheP9.12\n * - Carte DIY: V\u00e9rifier la documentation\n *\/\n\n\/\/ Par d\u00e9faut: GPIO 4 (broche 7 sur Raspberry Pi)\nstatic int gpio_led = 4;  \nmodule_param(gpio_led, int, 0644);\nMODULE_PARM_DESC(gpio_led, \"Numero GPIO pour la LED (defaut: 4)\");\n\nstatic int gpio_bouton = 17;  \/\/ GPIO pour bouton (optionnel)\nmodule_param(gpio_bouton, int, 0644);\nMODULE_PARM_DESC(gpio_bouton, \"Numero GPIO pour bouton (defaut: 17)\");\n\n\/\/ Etat global\nstatic struct {\n    bool gpio_led_reserve;\n    bool gpio_bouton_reserve;\n    bool module_actif;\n} etat_gpio = {\n    .gpio_led_reserve = false,\n    .gpio_bouton_reserve = false, \n    .module_actif = false\n};\n\n\/\/ ============================================================================\n\/\/ FONCTIONS GPIO\n\/\/ ============================================================================\n\nstatic int configurer_gpio_led(void)\n{\n    int ret = 0;\n    \n    printk(KERN_INFO \"Configuration GPIO %d pour LED...\\n\", gpio_led);\n    \n    \/\/ 1. R\u00e9server le GPIO\n    ret = gpio_request(gpio_led, \"led_module\");\n    if (ret) {\n        printk(KERN_ERR \"Echec reservation GPIO %d (code: %d)\\n\", gpio_led, ret);\n        return ret;\n    }\n    etat_gpio.gpio_led_reserve = true;\n    printk(KERN_INFO \"GPIO %d reserve avec succes\\n\", gpio_led);\n    \n    \/\/ 2. Configurer en sortie\n    ret = gpio_direction_output(gpio_led, 0);  \/\/ 0 = LED \u00e9teinte au d\u00e9but\n    if (ret) {\n        printk(KERN_ERR \"Echec configuration sortie GPIO %d\\n\", gpio_led);\n        return ret;\n    }\n    printk(KERN_INFO \"GPIO %d configure en sortie (valeur initiale: LOW)\\n\", gpio_led);\n    \n    return 0;\n}\n\nstatic int configurer_gpio_bouton(void)\n{\n    int ret = 0;\n    \n    printk(KERN_INFO \"Configuration GPIO %d pour bouton...\\n\", gpio_bouton);\n    \n    \/\/ 1. R\u00e9server le GPIO\n    ret = gpio_request(gpio_bouton, \"bouton_module\");\n    if (ret) {\n        printk(KERN_WARNING \"Echec reservation bouton GPIO %d (inutilisable)\\n\", gpio_bouton);\n        return ret;  \/\/ Non critique pour ce demo\n    }\n    etat_gpio.gpio_bouton_reserve = true;\n    \n    \/\/ 2. Configurer en entr\u00e9e\n    ret = gpio_direction_input(gpio_bouton);\n    if (ret) {\n        printk(KERN_WARNING \"Echec configuration entree GPIO %d\\n\", gpio_bouton);\n        return ret;\n    }\n    printk(KERN_INFO \"GPIO %d configure en entree\\n\", gpio_bouton);\n    \n    return 0;\n}\n\nstatic void liberer_gpios(void)\n{\n    if (etat_gpio.gpio_led_reserve) {\n        gpio_set_value(gpio_led, 0);  \/\/ Eteindre LED\n        gpio_free(gpio_led);\n        etat_gpio.gpio_led_reserve = false;\n        printk(KERN_INFO \"GPIO LED %d libere\\n\", gpio_led);\n    }\n    \n    if (etat_gpio.gpio_bouton_reserve) {\n        gpio_free(gpio_bouton);\n        etat_gpio.gpio_bouton_reserve = false;\n        printk(KERN_INFO \"GPIO bouton %d libere\\n\", gpio_bouton);\n    }\n}\n\n\/\/ ============================================================================\n\/\/ DEMONSTRATION LED\n\/\/ ============================================================================\n\nstatic void demonstration_led(void)\n{\n    int i;\n    \n    printk(KERN_INFO \"=== DEMONSTRATION LED GPIO %d ===\\n\", gpio_led);\n    \n    \/\/ Clignotement rapide\n    for (i = 0; i &lt; 6; i++) {\n        gpio_set_value(gpio_led, 1);  \/\/ Allumer\n        printk(KERN_INFO \"LED ON\\n\");\n        msleep(200);  \/\/ 200ms - NE PAS utiliser usleep en noyau!\n        \n        gpio_set_value(gpio_led, 0);  \/\/ Eteindre\n        printk(KERN_INFO \"LED OFF\\n\");\n        msleep(200);\n    }\n    \n    \/\/ Allumer en continu\n    gpio_set_value(gpio_led, 1);\n    printk(KERN_INFO \"LED allumee en continu\\n\");\n}\n\nstatic void lire_bouton(void)\n{\n    int valeur;\n    \n    if (!etat_gpio.gpio_bouton_reserve) {\n        return;  \/\/ Bouton non configur\u00e9\n    }\n    \n    valeur = gpio_get_value(gpio_bouton);\n    printk(KERN_INFO \"Bouton GPIO %d: %s\\n\", \n           gpio_bouton, valeur ? \"HIGH\" : \"LOW\");\n}\n\n\/\/ ============================================================================\n\/\/ INITIALISATION ET NETTOYAGE\n\/\/ ============================================================================\n\nstatic int __init gpio_module_init(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"=== INITIALISATION MODULE GPIO ===\\n\");\n    \n    \/\/ 1. Configuration LED (obligatoire)\n    ret = configurer_gpio_led();\n    if (ret) {\n        goto erreur_init;\n    }\n    \n    \/\/ 2. Configuration bouton (optionnelle)\n    configurer_gpio_bouton();  \/\/ On ignore les erreurs\n    \n    \/\/ 3. D\u00e9monstration\n    demonstration_led();\n    lire_bouton();\n    \n    etat_gpio.module_actif = true;\n    \n    printk(KERN_INFO \"=== MODULE GPIO ACTIF ===\\n\");\n    printk(KERN_INFO \"LED sur GPIO: %d\\n\", gpio_led);\n    if (etat_gpio.gpio_bouton_reserve) {\n        printk(KERN_INFO \"Bouton sur GPIO: %d\\n\", gpio_bouton);\n    }\n    \n    return 0;\n\nerreur_init:\n    liberer_gpios();\n    printk(KERN_ERR \"=== ECHEC INITIALISATION GPIO ===\\n\");\n    return ret;\n}\n\nstatic void __exit gpio_module_exit(void)\n{\n    printk(KERN_INFO \"=== NETTOYAGE MODULE GPIO ===\\n\");\n    \n    if (etat_gpio.module_actif) {\n        \/\/ Eteindre la LED avant de sortir\n        if (etat_gpio.gpio_led_reserve) {\n            gpio_set_value(gpio_led, 0);\n            printk(KERN_INFO \"LED eteinte\\n\");\n        }\n        \n        liberer_gpios();\n    }\n    \n    printk(KERN_INFO \"=== MODULE GPIO DESACTIVE ===\\n\");\n}\n\nmodule_init(gpio_module_init);\nmodule_exit(gpio_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"4-5-api-timers-pour-execution-periodique\">4.5 API Timers &#8211; Pour ex\u00e9cution p\u00e9riodique<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>gpio_timer.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/gpio.h>\n#include &lt;linux\/timer.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_DESCRIPTION(\"LED clignotante avec timer noyau\");\n\nstatic int gpio_led = 4;\nstatic int intervalle_ms = 500;  \/\/ 500ms par d\u00e9faut\nmodule_param(intervalle_ms, int, 0644);\n\nstatic struct timer_list mon_timer;\nstatic bool etat_led = false;  \/\/ false=OFF, true=ON\n\n\/\/ Fonction appel\u00e9e par le timer\nstatic void timer_callback(struct timer_list *t)\n{\n    \/\/ Changer l'\u00e9tat de la LED\n    etat_led = !etat_led;\n    gpio_set_value(gpio_led, etat_led ? 1 : 0);\n    \n    printk(KERN_INFO \"Timer: LED %s\\n\", etat_led ? \"ON\" : \"OFF\");\n    \n    \/\/ Reprogrammer le timer\n    mod_timer(&amp;mon_timer, jiffies + msecs_to_jiffies(intervalle_ms));\n}\n\nstatic int __init timer_module_init(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"Initialisation timer LED...\\n\");\n    \n    \/\/ Configuration GPIO\n    ret = gpio_request(gpio_led, \"timer_led\");\n    if (ret) {\n        printk(KERN_ERR \"Echec GPIO %d\\n\", gpio_led);\n        return ret;\n    }\n    \n    gpio_direction_output(gpio_led, 0);\n    \n    \/\/ Initialisation du timer\n    timer_setup(&amp;mon_timer, timer_callback, 0);\n    \n    \/\/ Premier d\u00e9clenchement\n    mod_timer(&amp;mon_timer, jiffies + msecs_to_jiffies(intervalle_ms));\n    \n    printk(KERN_INFO \"Timer LED actif (intervalle: %d ms)\\n\", intervalle_ms);\n    return 0;\n}\n\nstatic void __exit timer_module_exit(void)\n{\n    \/\/ Arr\u00eater le timer\n    del_timer_sync(&amp;mon_timer);\n    \n    \/\/ Eteindre LED et lib\u00e9rer GPIO\n    gpio_set_value(gpio_led, 0);\n    gpio_free(gpio_led);\n    \n    printk(KERN_INFO \"Timer LED desactive\\n\");\n}\n\nmodule_init(timer_module_init);\nmodule_exit(timer_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"4-6-makefile-pour-modules-gpio\">4.6 Makefile pour modules GPIO<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Makefile :<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>KVERSION := $(shell uname -r)\nKDIR := \/lib\/modules\/$(KVERSION)\/build\nPWD := $(shell pwd)\n\nobj-m += gpio_led.o\nobj-m += gpio_timer.o\n\nccflags-y := -Wall -Wextra\n\nall:\n\t$(MAKE) -C $(KDIR) M=$(PWD) modules\n\nclean:\n\t$(MAKE) -C $(KDIR) M=$(PWD) clean\n\n# Test GPIO LED\ntest-gpio: all\n\tsudo dmesg -C\n\tsudo insmod gpio_led.ko gpio_led=4 gpio_bouton=17\n\tdmesg\n\tsleep 3\n\tsudo rmmod gpio_led\n\tdmesg\n\n# Test timer LED  \ntest-timer: all\n\tsudo dmesg -C\n\tsudo insmod gpio_timer.ko intervalle_ms=300\n\tdmesg | head -10\n\tsleep 5\n\tsudo rmmod gpio_timer\n\tdmesg | tail -5\n\n.PHONY: all clean test-gpio test-timer<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"4-7-commandes-de-test-gpio\">4.7 Commandes de test GPIO<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Script de test pratique :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#!\/bin\/bash\n# test_gpio.sh\n\necho \"=== TEST MODULES GPIO ===\"\n\n# V\u00e9rifier les GPIO disponibles\necho \"1. GPIO disponibles:\"\nls \/sys\/class\/gpio\/ 2>\/dev\/null || echo \"Interface GPIO non disponible\"\n\n# Compilation\necho \"2. Compilation modules...\"\nmake\n\n# Test module LED basique\necho \"3. Test module LED...\"\nsudo insmod gpio_led.ko gpio_led=4\nsleep 2\nsudo rmmod gpio_led\n\n# Test avec param\u00e8tres diff\u00e9rents\necho \"4. Test avec GPIO personnalis\u00e9...\"\nsudo insmod gpio_led.ko gpio_led=17\nsleep 2  \nsudo rmmod gpio_led\n\n# Test timer\necho \"5. Test timer LED...\"\nsudo insmod gpio_timer.ko intervalle_ms=200\nsleep 3\nsudo rmmod gpio_timer\n\necho \"=== TESTS GPIO TERMINES ===\"<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"partie-5-exemples-progressifs\">PARTIE 5 : EXEMPLES PROGRESSIFS<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"5-1-module-hello-world-ameliore\">5.1 Module \u00ab\u00a0Hello World\u00a0\u00bb am\u00e9lior\u00e9<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>hello_advanced.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/version.h>\n#include &lt;linux\/slab.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Votre Nom\");\nMODULE_DESCRIPTION(\"Hello World avance avec informations systeme\");\nMODULE_VERSION(\"2.0\");\n\nstatic int nombre_affichages = 3;\nmodule_param(nombre_affichages, int, 0644);\nMODULE_PARM_DESC(nombre_affichages, \"Nombre de fois ou afficher le message\");\n\nstatic char *message_personnalise = \"Bonjour le noyau!\";\nmodule_param(message_personnalise, charp, 0644);\nMODULE_PARM_DESC(message_personnalise, \"Message personnalise a afficher\");\n\nstatic void afficher_infos_systeme(void)\n{\n    printk(KERN_INFO \"=== INFORMATIONS SYST\u00c8ME ===\\n\");\n    printk(KERN_INFO \"Version noyau: %s\\n\", UTS_RELEASE);\n    printk(KERN_INFO \"Architecture: %s\\n\", CONFIG_ARCH);\n    printk(KERN_INFO \"Nombre processeurs: %d\\n\", num_online_cpus());\n}\n\nstatic int __init hello_advanced_init(void)\n{\n    int i;\n    \n    printk(KERN_INFO \"=== INITIALISATION HELLO ADVANCED ===\\n\");\n    \n    \/\/ Afficher les informations syst\u00e8me\n    afficher_infos_systeme();\n    \n    \/\/ Afficher les param\u00e8tres\n    printk(KERN_INFO \"Parametres: affichages=%d, message='%s'\\n\",\n           nombre_affichages, message_personnalise);\n    \n    \/\/ Boucle d'affichage\n    for (i = 0; i &lt; nombre_affichages; i++) {\n        printk(KERN_INFO \"[%d\/%d] %s\\n\", \n               i + 1, nombre_affichages, message_personnalise);\n        \n        \/\/ Petite pause si ce n'est pas le dernier\n        if (i &lt; nombre_affichages - 1) {\n            msleep(1000); \/\/ 1 seconde\n        }\n    }\n    \n    \/\/ Allocation de test\n    void *test_buffer = kmalloc(256, GFP_KERNEL);\n    if (test_buffer) {\n        printk(KERN_INFO \"Test allocation memoire: OK (%p)\\n\", test_buffer);\n        kfree(test_buffer);\n    }\n    \n    printk(KERN_INFO \"=== MODULE HELLO ADVANCE CHARGE ===\\n\");\n    return 0;\n}\n\nstatic void __exit hello_advanced_exit(void)\n{\n    printk(KERN_INFO \"=== DECHARGEMENT HELLO ADVANCED ===\\n\");\n    \n    \/\/ Message d'au revoir\n    int i;\n    for (i = 0; i &lt; 2; i++) {\n        printk(KERN_INFO \"Au revoir! (%d)\\n\", i + 1);\n        if (i == 0) msleep(500);\n    }\n    \n    printk(KERN_INFO \"=== MODULE HELLO ADVANCE DECHARGE ===\\n\");\n}\n\nmodule_init(hello_advanced_init);\nmodule_exit(hello_advanced_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"5-2-module-de-journalisation-dans-un-fichier\">5.2 Module de journalisation dans un fichier<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>kernel_logger.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/fs.h>\n#include &lt;linux\/uaccess.h>\n#include &lt;linux\/slab.h>\n#include &lt;linux\/string.h>\n#include &lt;linux\/time.h>\n#include &lt;linux\/version.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Expert Logger\");\nMODULE_DESCRIPTION(\"Journalisation noyau vers fichier\");\n\n\/\/ Configuration\n#define LOG_FILENAME \"\/var\/log\/kernel_module.log\"\nstatic char *fichier_log = LOG_FILENAME;\nmodule_param(fichier_log, charp, 0644);\nMODULE_PARM_DESC(fichier_log, \"Chemin du fichier de log\");\n\nstatic int max_lignes = 10;\nmodule_param(max_lignes, int, 0644);\nMODULE_PARM_DESC(max_lignes, \"Nombre maximum de lignes a journaliser\");\n\n\/\/ Etat global\nstatic struct {\n    int compteur_lignes;\n    bool initialise;\n} etat_logger = {\n    .compteur_lignes = 0,\n    .initialise = false\n};\n\n\/\/ Fonction pour obtenir le timestamp\nstatic void obtenir_timestamp(char *buffer, size_t taille)\n{\n    struct timespec64 now;\n    ktime_get_real_ts64(&amp;now);\n    \n    snprintf(buffer, taille, \"[%lld.%09ld]\", \n             (long long)now.tv_sec, now.tv_nsec);\n}\n\n\/\/ Fonction pour ecrire dans le fichier\nstatic int ecrire_dans_fichier(const char *message)\n{\n    struct file *fichier;\n    loff_t pos = 0;\n    int ret;\n    char *buffer_complet;\n    char timestamp[50];\n    \n    \/\/ Allouer un buffer pour le message complet\n    buffer_complet = kmalloc(1024, GFP_KERNEL);\n    if (!buffer_complet) {\n        printk(KERN_ERR \"Erreur allocation memoire pour log\\n\");\n        return -ENOMEM;\n    }\n    \n    \/\/ Obtenir le timestamp\n    obtenir_timestamp(timestamp, sizeof(timestamp));\n    \n    \/\/ Formater le message complet\n    snprintf(buffer_complet, 1024, \"%s %s\\n\", timestamp, message);\n    \n    \/\/ Ouvrir le fichier en mode append\n    fichier = filp_open(fichier_log, O_WRONLY | O_CREAT | O_APPEND, 0644);\n    if (IS_ERR(fichier)) {\n        printk(KERN_ERR \"Erreur ouverture fichier %s: %ld\\n\", \n               fichier_log, PTR_ERR(fichier));\n        kfree(buffer_complet);\n        return PTR_ERR(fichier);\n    }\n    \n    \/\/ Ecrire dans le fichier\n    ret = kernel_write(fichier, buffer_complet, strlen(buffer_complet), &amp;pos);\n    if (ret &lt; 0) {\n        printk(KERN_ERR \"Erreur ecriture fichier: %d\\n\", ret);\n    } else {\n        etat_logger.compteur_lignes++;\n        printk(KERN_INFO \"Log ecrit: %s\", buffer_complet);\n    }\n    \n    \/\/ Fermer le fichier\n    filp_close(fichier, NULL);\n    kfree(buffer_complet);\n    \n    return ret;\n}\n\n\/\/ Fonction pour lire le fichier de log\nstatic void lire_fichier_log(void)\n{\n    struct file *fichier;\n    char *buffer;\n    loff_t pos = 0;\n    int ret;\n    \n    buffer = kmalloc(4096, GFP_KERNEL);\n    if (!buffer) {\n        printk(KERN_ERR \"Erreur allocation pour lecture\\n\");\n        return;\n    }\n    \n    \/\/ Ouvrir en lecture\n    fichier = filp_open(fichier_log, O_RDONLY, 0);\n    if (IS_ERR(fichier)) {\n        printk(KERN_WARNING \"Impossible de lire le fichier log\\n\");\n        kfree(buffer);\n        return;\n    }\n    \n    \/\/ Lire le contenu\n    ret = kernel_read(fichier, buffer, 4095, &amp;pos);\n    if (ret > 0) {\n        buffer[ret] = '\\0';\n        printk(KERN_INFO \"=== CONTENU DU FICHIER LOG ===\\n%s\\n\", buffer);\n    }\n    \n    filp_close(fichier, NULL);\n    kfree(buffer);\n}\n\nstatic int __init kernel_logger_init(void)\n{\n    int i;\n    \n    printk(KERN_INFO \"=== INITIALISATION JOURNALISEUR NOYAU ===\\n\");\n    \n    \/\/ Message de bienvenue dans le log fichier\n    ecrire_dans_fichier(\"=== DEBUT JOURNALISATION MODULE NOYAU ===\");\n    \n    \/\/ Journaliser quelques evenements de test\n    for (i = 0; i &lt; max_lignes &amp;&amp; i &lt; 5; i++) {\n        char message[100];\n        snprintf(message, sizeof(message), \n                \"Evenement test %d du module noyau\", i + 1);\n        ecrire_dans_fichier(message);\n        msleep(100);\n    }\n    \n    \/\/ Lire et afficher le contenu actuel\n    lire_fichier_log();\n    \n    etat_logger.initialise = true;\n    \n    printk(KERN_INFO \"Journaliseur actif: %s (%d lignes ecrites)\\n\",\n           fichier_log, etat_logger.compteur_lignes);\n    \n    return 0;\n}\n\nstatic void __exit kernel_logger_exit(void)\n{\n    printk(KERN_INFO \"=== ARRET JOURNALISEUR NOYAU ===\\n\");\n    \n    if (etat_logger.initialise) {\n        ecrire_dans_fichier(\"=== FIN JOURNALISATION MODULE NOYAU ===\");\n        \n        printk(KERN_INFO \"Total lignes journalisees: %d\\n\", \n               etat_logger.compteur_lignes);\n        printk(KERN_INFO \"Fichier log disponible: %s\\n\", fichier_log);\n    }\n}\n\nmodule_init(kernel_logger_init);\nmodule_exit(kernel_logger_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"5-3-module-gpio-complet-pour-controle-led\">5.3 Module GPIO complet pour contr\u00f4le LED<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>led_controller.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/gpio.h>\n#include &lt;linux\/delay.h>\n#include &lt;linux\/fs.h>\n#include &lt;linux\/uaccess.h>\n#include &lt;linux\/device.h>\n#include &lt;linux\/cdev.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Controleur LED\");\nMODULE_DESCRIPTION(\"Controle LED GPIO avec interface utilisateur\");\n\n\/\/ Configuration GPIO\nstatic int gpio_led = 4;\nmodule_param(gpio_led, int, 0644);\nMODULE_PARM_DESC(gpio_led, \"GPIO pour la LED\");\n\n\/\/ Variables globales\nstatic struct {\n    bool led_allumee;\n    bool gpio_reserve;\n    int compteur_operations;\n    struct class *classe;\n    struct device *device;\n    dev_t numero_device;\n} etat_led = {\n    .led_allumee = false,\n    .gpio_reserve = false,\n    .compteur_operations = 0\n};\n\n\/\/ Fonctions de controle LED\nstatic void allumer_led(void)\n{\n    if (!etat_led.gpio_reserve) return;\n    \n    gpio_set_value(gpio_led, 1);\n    etat_led.led_allumee = true;\n    etat_led.compteur_operations++;\n    printk(KERN_INFO \"LED allumee (GPIO %d)\\n\", gpio_led);\n}\n\nstatic void eteindre_led(void)\n{\n    if (!etat_led.gpio_reserve) return;\n    \n    gpio_set_value(gpio_led, 0);\n    etat_led.led_allumee = false;\n    etat_led.compteur_operations++;\n    printk(KERN_INFO \"LED eteinte (GPIO %d)\\n\", gpio_led);\n}\n\nstatic void basculer_led(void)\n{\n    if (etat_led.led_allumee) {\n        eteindre_led();\n    } else {\n        allumer_led();\n    }\n}\n\nstatic void clignoter_led(int repetitions, int delais_ms)\n{\n    int i;\n    \n    printk(KERN_INFO \"Debut clignotement: %d repetitions, %d ms\\n\", \n           repetitions, delais_ms);\n    \n    for (i = 0; i &lt; repetitions; i++) {\n        allumer_led();\n        msleep(delais_ms);\n        eteindre_led();\n        \n        if (i &lt; repetitions - 1) {\n            msleep(delais_ms);\n        }\n    }\n    \n    printk(KERN_INFO \"Fin clignotement\\n\");\n}\n\n\/\/ Demonstration automatique\nstatic void demonstration_led(void)\n{\n    printk(KERN_INFO \"=== DEMONSTRATION LED CONTROLEUR ===\\n\");\n    \n    \/\/ Sequence 1: Clignotement rapide\n    printk(KERN_INFO \"Sequence 1: Clignotement rapide\\n\");\n    clignoter_led(5, 200);\n    msleep(500);\n    \n    \/\/ Sequence 2: Clignotement lent\n    printk(KERN_INFO \"Sequence 2: Clignotement lent\\n\");\n    clignoter_led(3, 500);\n    msleep(500);\n    \n    \/\/ Sequence 3: Allumage progressif\n    printk(KERN_INFO \"Sequence 3: Pulse\\n\");\n    int i;\n    for (i = 0; i &lt; 3; i++) {\n        allumer_led();\n        msleep(100);\n        eteindre_led();\n        msleep(50);\n        allumer_led();\n        msleep(300);\n        eteindre_led();\n        msleep(200);\n    }\n    \n    \/\/ Final: Allumer\n    allumer_led();\n    printk(KERN_INFO \"=== FIN DEMONSTRATION ===\\n\");\n}\n\n\/\/ Initialisation GPIO\nstatic int initialiser_gpio(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"Initialisation GPIO %d pour LED...\\n\", gpio_led);\n    \n    \/\/ Verifier si le GPIO est valide\n    if (!gpio_is_valid(gpio_led)) {\n        printk(KERN_ERR \"GPIO %d invalide\\n\", gpio_led);\n        return -EINVAL;\n    }\n    \n    \/\/ Reserver le GPIO\n    ret = gpio_request(gpio_led, \"led_controller\");\n    if (ret) {\n        printk(KERN_ERR \"Erreur reservation GPIO %d: %d\\n\", gpio_led, ret);\n        return ret;\n    }\n    etat_led.gpio_reserve = true;\n    \n    \/\/ Configurer en sortie\n    ret = gpio_direction_output(gpio_led, 0);\n    if (ret) {\n        printk(KERN_ERR \"Erreur configuration sortie GPIO %d: %d\\n\", gpio_led, ret);\n        gpio_free(gpio_led);\n        etat_led.gpio_reserve = false;\n        return ret;\n    }\n    \n    \/\/ Initialiser eteinte\n    gpio_set_value(gpio_led, 0);\n    etat_led.led_allumee = false;\n    \n    printk(KERN_INFO \"GPIO %d initialise avec succes\\n\", gpio_led);\n    return 0;\n}\n\nstatic void __init led_controller_init(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"=== INITIALISATION LED CONTROLEUR ===\\n\");\n    \n    \/\/ Initialiser GPIO\n    ret = initialiser_gpio();\n    if (ret) {\n        printk(KERN_ERR \"Echec initialisation GPIO\\n\");\n        return;\n    }\n    \n    \/\/ Lancer la demonstration\n    demonstration_led();\n    \n    printk(KERN_INFO \"=== LED CONTROLEUR ACTIF ===\\n\");\n    printk(KERN_INFO \"GPIO: %d, Etat: %s, Operations: %d\\n\",\n           gpio_led, \n           etat_led.led_allumee ? \"ALLUMEE\" : \"ETEINTE\",\n           etat_led.compteur_operations);\n}\n\nstatic void __exit led_controller_exit(void)\n{\n    printk(KERN_INFO \"=== ARRET LED CONTROLEUR ===\\n\");\n    \n    \/\/ Eteindre la LED\n    if (etat_led.led_allumee) {\n        eteindre_led();\n    }\n    \n    \/\/ Liberer GPIO\n    if (etat_led.gpio_reserve) {\n        gpio_free(gpio_led);\n        printk(KERN_INFO \"GPIO %d libere\\n\", gpio_led);\n    }\n    \n    \/\/ Afficher les statistiques\n    printk(KERN_INFO \"Statistiques finales:\\n\");\n    printk(KERN_INFO \"- Total operations: %d\\n\", etat_led.compteur_operations);\n    printk(KERN_INFO \"- Dernier etat: %s\\n\", \n           etat_led.led_allumee ? \"ALLUMEE\" : \"ETEINTE\");\n    \n    printk(KERN_INFO \"=== LED CONTROLEUR DESACTIVE ===\\n\");\n}\n\nmodule_init(led_controller_init);\nmodule_exit(led_controller_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"5-4-module-avec-timer-pour-execution-periodique\">5.4 Module avec timer pour ex\u00e9cution p\u00e9riodique<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>periodic_timer.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/timer.h>\n#include &lt;linux\/jiffies.h>\n#include &lt;linux\/gpio.h>\n#include &lt;linux\/slab.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Timer Expert\");\nMODULE_DESCRIPTION(\"Module avec timer periodique et multiple fonctionnalites\");\n\n\/\/ Configuration\nstatic int intervalle_timer_ms = 1000;\nmodule_param(intervalle_timer_ms, int, 0644);\nMODULE_PARM_DESC(intervalle_timer_ms, \"Intervalle timer en millisecondes\");\n\nstatic int gpio_led = 4;\nmodule_param(gpio_led, int, 0644);\n\nstatic int duree_execution_sec = 30;\nmodule_param(duree_execution_sec, int, 0644);\nMODULE_PARM_DESC(duree_execution_sec, \"Duree d'execution en secondes\");\n\n\/\/ Etat global\nstatic struct {\n    struct timer_list mon_timer;\n    unsigned long compteur_ticks;\n    bool timer_actif;\n    bool gpio_configure;\n    bool led_etat;\n    struct timespec64 debut;\n} etat_timer = {\n    .compteur_ticks = 0,\n    .timer_actif = false,\n    .gpio_configure = false,\n    .led_etat = false\n};\n\n\/\/ Fonction pour obtenir le temps ecoule\nstatic long obtenir_temps_ecoule_ms(void)\n{\n    struct timespec64 maintenant, ecoule;\n    ktime_get_real_ts64(&amp;maintenant);\n    \n    ecoule = timespec64_sub(maintenant, etat_timer.debut);\n    return timespec64_to_ms(&amp;ecoule);\n}\n\n\/\/ Callback du timer\nstatic void callback_timer(struct timer_list *t)\n{\n    long temps_ecoule = obtenir_temps_ecoule_ms();\n    \n    etat_timer.compteur_ticks++;\n    \n    \/\/ Basculer LED si GPIO configure\n    if (etat_timer.gpio_configure) {\n        etat_timer.led_etat = !etat_timer.led_etat;\n        gpio_set_value(gpio_led, etat_timer.led_etat ? 1 : 0);\n    }\n    \n    \/\/ Journaliser periodiquement\n    if (etat_timer.compteur_ticks % 10 == 0) {\n        printk(KERN_INFO \"Timer tick %lu - Temps ecoule: %ld ms\\n\",\n               etat_timer.compteur_ticks, temps_ecoule);\n    } else {\n        printk(KERN_DEBUG \"Tick %lu - LED: %s\\n\", \n               etat_timer.compteur_ticks,\n               etat_timer.led_etat ? \"ON\" : \"OFF\");\n    }\n    \n    \/\/ Verifier la duree d'execution\n    if (duree_execution_sec > 0 &amp;&amp; \n        temps_ecoule >= duree_execution_sec * 1000) {\n        printk(KERN_INFO \"Duree d'execution atteinte (%d sec)\\n\", \n               duree_execution_sec);\n        return; \/\/ Ne pas reprogrammer\n    }\n    \n    \/\/ Reprogrammer le timer\n    if (etat_timer.timer_actif) {\n        mod_timer(&amp;etat_timer.mon_timer, \n                  jiffies + msecs_to_jiffies(intervalle_timer_ms));\n    }\n}\n\n\/\/ Configuration GPIO optionnelle\nstatic int configurer_gpio_led(void)\n{\n    int ret;\n    \n    if (!gpio_is_valid(gpio_led)) {\n        printk(KERN_WARNING \"GPIO %d invalide - LED desactivee\\n\", gpio_led);\n        return -EINVAL;\n    }\n    \n    ret = gpio_request(gpio_led, \"periodic_timer\");\n    if (ret) {\n        printk(KERN_WARNING \"Erreur GPIO %d - LED desactivee: %d\\n\", gpio_led, ret);\n        return ret;\n    }\n    \n    ret = gpio_direction_output(gpio_led, 0);\n    if (ret) {\n        printk(KERN_WARNING \"Erreur configuration GPIO %d: %d\\n\", gpio_led, ret);\n        gpio_free(gpio_led);\n        return ret;\n    }\n    \n    etat_timer.gpio_configure = true;\n    etat_timer.led_etat = false;\n    printk(KERN_INFO \"GPIO %d configure pour LED\\n\", gpio_led);\n    \n    return 0;\n}\n\nstatic int __init periodic_timer_init(void)\n{\n    printk(KERN_INFO \"=== INITIALISATION TIMER PERIODIQUE ===\\n\");\n    \n    \/\/ Enregistrer le temps de debut\n    ktime_get_real_ts64(&amp;etat_timer.debut);\n    \n    \/\/ Configuration GPIO (optionnelle)\n    configurer_gpio_led();\n    \n    \/\/ Initialiser le timer\n    timer_setup(&amp;etat_timer.mon_timer, callback_timer, 0);\n    \n    \/\/ Demarrer le timer\n    etat_timer.timer_actif = true;\n    mod_timer(&amp;etat_timer.mon_timer, \n              jiffies + msecs_to_jiffies(intervalle_timer_ms));\n    \n    printk(KERN_INFO \"Timer periodique active:\\n\");\n    printk(KERN_INFO \"- Intervalle: %d ms\\n\", intervalle_timer_ms);\n    printk(KERN_INFO \"- Duree max: %d sec\\n\", duree_execution_sec);\n    printk(KERN_INFO \"- LED GPIO: %d (%s)\\n\", gpio_led,\n           etat_timer.gpio_configure ? \"actif\" : \"inactif\");\n    \n    return 0;\n}\n\nstatic void __exit periodic_timer_exit(void)\n{\n    printk(KERN_INFO \"=== ARRET TIMER PERIODIQUE ===\\n\");\n    \n    \/\/ Arreter le timer\n    etat_timer.timer_actif = false;\n    del_timer_sync(&amp;etat_timer.mon_timer);\n    \n    \/\/ Eteindre et liberer GPIO\n    if (etat_timer.gpio_configure) {\n        gpio_set_value(gpio_led, 0);\n        gpio_free(gpio_led);\n        printk(KERN_INFO \"GPIO %d libere\\n\", gpio_led);\n    }\n    \n    \/\/ Afficher les statistiques finales\n    printk(KERN_INFO \"Statistiques finales:\\n\");\n    printk(KERN_INFO \"- Total ticks: %lu\\n\", etat_timer.compteur_ticks);\n    printk(KERN_INFO \"- Temps total: %ld ms\\n\", obtenir_temps_ecoule_ms());\n    printk(KERN_INFO \"- Ticks par seconde: %lu\\n\", \n           etat_timer.compteur_ticks * 1000 \/ (obtenir_temps_ecoule_ms() ?: 1));\n    \n    printk(KERN_INFO \"=== TIMER PERIODIQUE DESACTIVE ===\\n\");\n}\n\nmodule_init(periodic_timer_init);\nmodule_exit(periodic_timer_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"5-5-makefile-pour-tous-les-exemples\">5.5 Makefile pour tous les exemples<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Makefile :<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>KVERSION := $(shell uname -r)\nKDIR := \/lib\/modules\/$(KVERSION)\/build\nPWD := $(shell pwd)\n\n# Tous les modules de la partie 5\nobj-m += hello_advanced.o\nobj-m += kernel_logger.o\nobj-m += led_controller.o\nobj-m += periodic_timer.o\n\nccflags-y := -Wall -Wextra\n\nall:\n\t$(MAKE) -C $(KDIR) M=$(PWD) modules\n\nclean:\n\t$(MAKE) -C $(KDIR) M=$(PWD) clean\n\n# Tests individuels\ntest-hello:\n\tsudo dmesg -C\n\tsudo insmod hello_advanced.ko nombre_affichages=2 message_personnalise=\"Test reussi!\"\n\tdmesg\n\tsudo rmmod hello_advanced\n\tdmesg\n\ntest-logger:\n\tsudo dmesg -C\n\tsudo insmod kernel_logger.ko max_lignes=5 fichier_log=\"\/tmp\/kernel_test.log\"\n\tdmesg\n\tsudo rmmod kernel_logger\n\tdmesg\n\tcat \/tmp\/kernel_test.log 2&gt;\/dev\/null || echo \"Fichier log non trouve\"\n\ntest-led:\n\tsudo dmesg -C\n\tsudo insmod led_controller.ko gpio_led=4\n\tdmesg\n\tsudo rmmod led_controller\n\tdmesg\n\ntest-timer:\n\tsudo dmesg -C\n\tsudo insmod periodic_timer.ko intervalle_timer_ms=500 duree_execution_sec=10\n\tdmesg | head -15\n\tsleep 12\n\tsudo rmmod periodic_timer\n\tdmesg | tail -10\n\n# Test complet\ntest-all: test-hello test-logger test-led test-timer\n\n.PHONY: all clean test-hello test-logger test-led test-timer test-all<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"5-6-script-de-demonstration-complet\">5.6 Script de d\u00e9monstration complet<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>demo_complete.sh :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#!\/bin\/bash\necho \"=== DEMONSTRATION COMPLETE PARTIE 5 ===\"\n\n# Compilation\necho \"1. Compilation des modules...\"\nmake\n\n# Test Hello World avanc\u00e9\necho \"2. Test Hello World avanc\u00e9...\"\nsudo insmod hello_advanced.ko nombre_affichages=3 message_personnalise=\"Salut Kernel!\"\nsleep 2\nsudo rmmod hello_advanced\ndmesg | tail -10\n\n# Test Logger\necho \"3. Test Journalisation...\"\nsudo insmod kernel_logger.ko max_lignes=8 fichier_log=\"\/tmp\/demo_kernel.log\"\nsleep 1\nsudo rmmod kernel_logger\necho \"--- Contenu du log ---\"\ncat \/tmp\/demo_kernel.log 2>\/dev\/null || echo \"Fichier non trouv\u00e9\"\n\n# Test LED Controller\necho \"4. Test Contr\u00f4leur LED...\"\nsudo insmod led_controller.ko gpio_led=17\nsleep 3\nsudo rmmod led_controller\ndmesg | tail -5\n\n# Test Timer p\u00e9riodique\necho \"5. Test Timer P\u00e9riodique...\"\nsudo insmod periodic_timer.ko intervalle_timer_ms=300 duree_execution_sec=8\nsleep 10\nsudo rmmod periodic_timer\ndmesg | grep \"Timer\\|Tick\" | tail -10\n\necho \"=== DEMONSTRATION TERMINEE ===\"<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"partie-6-bonnes-pratiques\">PARTIE 6 : BONNES PRATIQUES<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6-1-gestion-des-erreurs-et-nettoyage-des-ressources\">6.1 Gestion des erreurs et nettoyage des ressources<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"6-1-1-pattern-de-gestion-d-erreurs-robuste\">6.1.1 Pattern de gestion d&rsquo;erreurs robuste<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>error_handling.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/slab.h>\n#include &lt;linux\/fs.h>\n#include &lt;linux\/device.h>\n#include &lt;linux\/gpio.h>\n#include &lt;linux\/cdev.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Expert Bonnes Pratiques\");\nMODULE_DESCRIPTION(\"Demonstration gestion d'erreurs robuste\");\n\n#define DEVICE_NAME \"safe_device\"\n#define MAX_DEVICES 2\n#define BUFFER_SIZE 1024\n\n\/\/ Structure pour l'etat complet du module\nstruct module_state {\n    struct cdev cdev;\n    dev_t dev_num;\n    struct class *device_class;\n    struct device *device;\n    void *buffer_principal;\n    void *buffer_secondaire;\n    int gpio_led;\n    bool ressources_allouees[6]; \/\/ Bitmap des ressources\n    enum {\n        RESSOURCE_CDEV = 0,\n        RESSOURCE_CLASS,\n        RESSOURCE_DEVICE,\n        RESSOURCE_BUFFER1,\n        RESSOURCE_BUFFER2,\n        RESSOURCE_GPIO\n    };\n};\n\nstatic struct module_state module_etat;\n\n\/\/ Fonctions de gestion des ressources\nstatic int allouer_buffer_principal(void)\n{\n    module_etat.buffer_principal = kzalloc(BUFFER_SIZE, GFP_KERNEL);\n    if (!module_etat.buffer_principal) {\n        printk(KERN_ERR \"Echec allocation buffer principal\\n\");\n        return -ENOMEM;\n    }\n    module_etat.ressources_allouees[RESSOURCE_BUFFER1] = true;\n    printk(KERN_INFO \"Buffer principal alloue: %p\\n\", module_etat.buffer_principal);\n    return 0;\n}\n\nstatic int allouer_buffer_secondaire(void)\n{\n    module_etat.buffer_secondaire = kmalloc(BUFFER_SIZE \/ 2, GFP_KERNEL);\n    if (!module_etat.buffer_secondaire) {\n        printk(KERN_ERR \"Echec allocation buffer secondaire\\n\");\n        return -ENOMEM;\n    }\n    module_etat.ressources_allouees[RESSOURCE_BUFFER2] = true;\n    printk(KERN_INFO \"Buffer secondaire alloue: %p\\n\", module_etat.buffer_secondaire);\n    return 0;\n}\n\nstatic int configurer_gpio(void)\n{\n    int ret;\n    module_etat.gpio_led = 4; \/\/ GPIO par defaut\n    \n    if (!gpio_is_valid(module_etat.gpio_led)) {\n        printk(KERN_ERR \"GPIO %d invalide\\n\", module_etat.gpio_led);\n        return -EINVAL;\n    }\n    \n    ret = gpio_request(module_etat.gpio_led, \"safe_module\");\n    if (ret) {\n        printk(KERN_ERR \"Echec reservation GPIO %d: %d\\n\", module_etat.gpio_led, ret);\n        return ret;\n    }\n    \n    ret = gpio_direction_output(module_etat.gpio_led, 0);\n    if (ret) {\n        printk(KERN_ERR \"Echec configuration GPIO %d: %d\\n\", module_etat.gpio_led, ret);\n        gpio_free(module_etat.gpio_led);\n        return ret;\n    }\n    \n    module_etat.ressources_allouees[RESSOURCE_GPIO] = true;\n    printk(KERN_INFO \"GPIO %d configure avec succes\\n\", module_etat.gpio_led);\n    return 0;\n}\n\nstatic int creer_device(void)\n{\n    int ret;\n    \n    \/\/ Allocation numero device\n    ret = alloc_chrdev_region(&amp;module_etat.dev_num, 0, MAX_DEVICES, DEVICE_NAME);\n    if (ret &lt; 0) {\n        printk(KERN_ERR \"Echec allocation numero device: %d\\n\", ret);\n        return ret;\n    }\n    module_etat.ressources_allouees[RESSOURCE_CDEV] = true;\n    printk(KERN_INFO \"Numero device alloue: %d\\n\", MAJOR(module_etat.dev_num));\n    \n    \/\/ Creation classe\n    module_etat.device_class = class_create(DEVICE_NAME);\n    if (IS_ERR(module_etat.device_class)) {\n        printk(KERN_ERR \"Echec creation classe device\\n\");\n        return PTR_ERR(module_etat.device_class);\n    }\n    module_etat.ressources_allouees[RESSOURCE_CLASS] = true;\n    \n    \/\/ Creation device\n    module_etat.device = device_create(module_etat.device_class, NULL, \n                                      module_etat.dev_num, NULL, DEVICE_NAME);\n    if (IS_ERR(module_etat.device)) {\n        printk(KERN_ERR \"Echec creation device\\n\");\n        return PTR_ERR(module_etat.device);\n    }\n    module_etat.ressources_allouees[RESSOURCE_DEVICE] = true;\n    \n    printk(KERN_INFO \"Device %s cree avec succes\\n\", DEVICE_NAME);\n    return 0;\n}\n\n\/\/ Fonction de nettoyage complet\nstatic void nettoyer_ressources(void)\n{\n    printk(KERN_INFO \"Nettoyage des ressources...\\n\");\n    \n    \/\/ ORDRE INVERSE de l'allocation\n    if (module_etat.ressources_allouees[RESSOURCE_DEVICE]) {\n        device_destroy(module_etat.device_class, module_etat.dev_num);\n        module_etat.ressources_allouees[RESSOURCE_DEVICE] = false;\n        printk(KERN_INFO \"Device detruit\\n\");\n    }\n    \n    if (module_etat.ressources_allouees[RESSOURCE_CLASS]) {\n        class_destroy(module_etat.device_class);\n        module_etat.ressources_allouees[RESSOURCE_CLASS] = false;\n        printk(KERN_INFO \"Classe detruite\\n\");\n    }\n    \n    if (module_etat.ressources_allouees[RESSOURCE_CDEV]) {\n        unregister_chrdev_region(module_etat.dev_num, MAX_DEVICES);\n        module_etat.ressources_allouees[RESSOURCE_CDEV] = false;\n        printk(KERN_INFO Region device liberee\\n\");\n    }\n    \n    if (module_etat.ressources_allouees[RESSOURCE_GPIO]) {\n        gpio_set_value(module_etat.gpio_led, 0);\n        gpio_free(module_etat.gpio_led);\n        module_etat.ressources_allouees[RESSOURCE_GPIO] = false;\n        printk(KERN_INFO \"GPIO libere\\n\");\n    }\n    \n    if (module_etat.ressources_allouees[RESSOURCE_BUFFER2]) {\n        kfree(module_etat.buffer_secondaire);\n        module_etat.buffer_secondaire = NULL;\n        module_etat.ressources_allouees[RESSOURCE_BUFFER2] = false;\n        printk(KERN_INFO \"Buffer secondaire libere\\n\");\n    }\n    \n    if (module_etat.ressources_allouees[RESSOURCE_BUFFER1]) {\n        kfree(module_etat.buffer_principal);\n        module_etat.buffer_principal = NULL;\n        module_etat.ressources_allouees[RESSOURCE_BUFFER1] = false;\n        printk(KERN_INFO \"Buffer principal libere\\n\");\n    }\n}\n\nstatic int __init safe_module_init(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"=== INITIALISATION MODULE SECURISE ===\\n\");\n    \n    \/\/ Initialiser le bitmap de ressources\n    memset(&amp;module_etat.ressources_allouees, 0, sizeof(module_etat.ressources_allouees));\n    \n    \/\/ Sequence d'initialisation avec gestion d'erreur\n    ret = allouer_buffer_principal();\n    if (ret) goto erreur;\n    \n    ret = allouer_buffer_secondaire();\n    if (ret) goto erreur;\n    \n    ret = configurer_gpio();\n    if (ret) goto erreur;\n    \n    ret = creer_device();\n    if (ret) goto erreur;\n    \n    \/\/ Simulation d'utilisation\n    memset(module_etat.buffer_principal, 0xAA, BUFFER_SIZE);\n    gpio_set_value(module_etat.gpio_led, 1);\n    \n    printk(KERN_INFO \"=== MODULE SECURISE CHARGE AVEC SUCCES ===\\n\");\n    return 0;\n\nerreur:\n    printk(KERN_ERR \"Erreur lors de l'initialisation: %d\\n\", ret);\n    nettoyer_ressources();\n    return ret;\n}\n\nstatic void __exit safe_module_exit(void)\n{\n    printk(KERN_INFO \"=== DECHARGEMENT MODULE SECURISE ===\\n\");\n    nettoyer_ressources();\n    printk(KERN_INFO \"=== MODULE SECURISE DECHARGE ===\\n\");\n}\n\nmodule_init(safe_module_init);\nmodule_exit(safe_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6-2-securite-et-stabilite\">6.2 S\u00e9curit\u00e9 et stabilit\u00e9<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"6-2-1-verifications-de-securite-critiques\">6.2.1 V\u00e9rifications de s\u00e9curit\u00e9 critiques<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>security_checks.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/slab.h>\n#include &lt;linux\/uaccess.h>\n#include &lt;linux\/string.h>\n#include &lt;linux\/bug.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_DESCRIPTION(\"Demonstration des verifications de securite\");\n\n#define MAX_USER_INPUT 256\n\nstatic void demonstrations_securite(void)\n{\n    char *buffer = NULL;\n    int *tableau = NULL;\n    size_t taille;\n    \n    printk(KERN_INFO \"=== DEMONSTRATIONS SECURITE ===\\n\");\n    \n    \/\/ 1. Verification des allocations\n    buffer = kmalloc(MAX_USER_INPUT, GFP_KERNEL);\n    if (!buffer) {\n        printk(KERN_ERR \"Echec allocation memoire - arret securise\\n\");\n        return;\n    }\n    \n    \/\/ 2. Initialisation de la memoire\n    memset(buffer, 0, MAX_USER_INPUT);\n    \n    \/\/ 3. Verification des bornes\n    taille = MAX_USER_INPUT - 1;\n    if (taille > MAX_USER_INPUT) {\n        printk(KERN_WARNING \"Taille invalide, ajustement automatique\\n\");\n        taille = MAX_USER_INPUT - 1;\n    }\n    \n    \/\/ 4. Verification des pointeurs\n    if (!buffer) {\n        printk(KERN_ERR \"Pointeur nul detecte\\n\");\n        return;\n    }\n    \n    \/\/ 5. Utilisation de BUG_ON pour les conditions critiques\n    BUG_ON(!buffer);\n    \n    \/\/ 6. Verification de saturation arithmetique\n    int grande_taille = 1000;\n    int petite_taille = 10;\n    if (grande_taille + petite_taille &lt; grande_taille) {\n        printk(KERN_ERR \"Saturation arithmetique detectee!\\n\");\n        kfree(buffer);\n        return;\n    }\n    \n    \/\/ 7. Allocation avec verification de taille\n    tableau = kmalloc_array(1000, sizeof(int), GFP_KERNEL);\n    if (!tableau) {\n        printk(KERN_ERR \"Echec allocation tableau\\n\");\n        kfree(buffer);\n        return;\n    }\n    \n    printk(KERN_INFO \"Toutes les verifications de securite passees\\n\");\n    \n    \/\/ Nettoyage\n    kfree(tableau);\n    kfree(buffer);\n}\n\n\/\/ Fonction pour simuler le traitement de donnees utilisateur\nstatic int traiter_donnees_utilisateur(const char __user *data, size_t taille)\n{\n    char *buffer_kernel;\n    int ret = 0;\n    \n    \/\/ Verification de base\n    if (!data) {\n        printk(KERN_ERR \"Donnees utilisateur nulles\\n\");\n        return -EINVAL;\n    }\n    \n    if (taille > MAX_USER_INPUT) {\n        printk(KERN_ERR \"Taille des donnees trop importante: %zu\\n\", taille);\n        return -EFBIG;\n    }\n    \n    if (taille == 0) {\n        printk(KERN_WARNING \"Taille des donnees nulle\\n\");\n        return -EINVAL;\n    }\n    \n    \/\/ Allocation\n    buffer_kernel = kmalloc(taille + 1, GFP_KERNEL);\n    if (!buffer_kernel) {\n        printk(KERN_ERR \"Echec allocation pour donnees utilisateur\\n\");\n        return -ENOMEM;\n    }\n    \n    \/\/ Copie securisee depuis l'espace utilisateur\n    if (copy_from_user(buffer_kernel, data, taille)) {\n        printk(KERN_ERR \"Echec copie depuis espace utilisateur\\n\");\n        kfree(buffer_kernel);\n        return -EFAULT;\n    }\n    \n    \/\/ Null-terminator pour securite\n    buffer_kernel[taille] = '\\0';\n    \n    printk(KERN_INFO \"Donnees utilisateur traitees: %s\\n\", buffer_kernel);\n    \n    kfree(buffer_kernel);\n    return ret;\n}\n\nstatic int __init security_module_init(void)\n{\n    printk(KERN_INFO \"=== INITIALISATION MODULE SECURITE ===\\n\");\n    \n    demonstrations_securite();\n    \n    \/\/ Test de traitement de donnees (simulation)\n    char test_data[] = \"Donnees test securisees\";\n    traiter_donnees_utilisateur((const char __user *)test_data, strlen(test_data));\n    \n    printk(KERN_INFO \"=== MODULE SECURITE ACTIF ===\\n\");\n    return 0;\n}\n\nstatic void __exit security_module_exit(void)\n{\n    printk(KERN_INFO \"=== DECHARGEMENT MODULE SECURITE ===\\n\");\n}\n\nmodule_init(security_module_init);\nmodule_exit(security_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6-3-debogage-avec-dmesg-et-printk\">6.3 D\u00e9bogage avec dmesg et printk<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"6-3-1-module-de-debogage-avance\">6.3.1 Module de d\u00e9bogage avanc\u00e9<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>debug_module.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/version.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_DESCRIPTION(\"Module de debogage avance\");\n\n\/\/ Niveaux de debug configurables\nstatic int niveau_debug = 3; \/\/ 0=aucun, 1=erreurs, 2=avertissements, 3=info, 4=debug\nmodule_param(niveau_debug, int, 0644);\nMODULE_PARM_DESC(niveau_debug, \"Niveau de debug (0-4)\");\n\n\/\/ Macros de debogage\n#define DEBUG_ERR(fmt, ...)   \\\n    if (niveau_debug >= 1)    \\\n        printk(KERN_ERR \"[ERR] %s:%d \" fmt, __FILE__, __LINE__, ##__VA_ARGS__)\n\n#define DEBUG_WARN(fmt, ...)  \\\n    if (niveau_debug >= 2)    \\\n        printk(KERN_WARNING \"[WARN] %s:%d \" fmt, __FILE__, __LINE__, ##__VA_ARGS__)\n\n#define DEBUG_INFO(fmt, ...)  \\\n    if (niveau_debug >= 3)    \\\n        printk(KERN_INFO \"[INFO] %s:%d \" fmt, __FILE__, __LINE__, ##__VA_ARGS__)\n\n#define DEBUG_DBG(fmt, ...)   \\\n    if (niveau_debug >= 4)    \\\n        printk(KERN_DEBUG \"[DBG] %s:%d \" fmt, __FILE__, __LINE__, ##__VA_ARGS__)\n\n\/\/ Fonction pour dumper les informations systeme\nstatic void dump_infos_systeme(void)\n{\n    DEBUG_INFO(\"=== INFORMATIONS SYSTEME ===\\n\");\n    DEBUG_INFO(\"Version noyau: %s\\n\", UTS_RELEASE);\n    DEBUG_INFO \"Compilation: %s\\n\", LINUX_COMPILE_BY \"@\" LINUX_COMPILE_HOST);\n    DEBUG_INFO(\"Date compilation: %s %s\\n\", LINUX_COMPILE_DATE, UTS_VERSION);\n    \n    \/\/ Informations sur la memoire\n    struct sysinfo si;\n    si_meminfo(&amp;si);\n    DEBUG_INFO(\"Memoire totale: %lu MB\\n\", si.totalram \/ 1024 \/ 1024);\n    DEBUG_INFO(\"Memoire libre: %lu MB\\n\", si.freeram \/ 1024 \/ 1024);\n}\n\n\/\/ Simulation d'operations avec differents niveaux de log\nstatic void simulation_operations(void)\n{\n    int i;\n    \n    DEBUG_INFO(\"Debut simulation d'operations\\n\");\n    \n    for (i = 0; i &lt; 5; i++) {\n        DEBUG_DBG(\"Iteration %d\/5\\n\", i + 1);\n        \n        switch (i) {\n            case 0:\n                DEBUG_INFO(\"Operation 1: Initialisation\\n\");\n                break;\n            case 1:\n                DEBUG_WARN(\"Operation 2: Avertissement test\\n\");\n                break;\n            case 2:\n                DEBUG_ERR(\"Operation 3: Erreur simulation\\n\");\n                break;\n            case 3:\n                DEBUG_INFO(\"Operation 4: Retour a la normale\\n\");\n                break;\n            case 4:\n                DEBUG_DBG(\"Operation 5: Debug detaille\\n\");\n                break;\n        }\n        \n        \/\/ Simulation delai\n        if (niveau_debug >= 4) {\n            DEBUG_DBG(\"Pause 100ms\\n\");\n        }\n        msleep(100);\n    }\n    \n    DEBUG_INFO(\"Fin simulation d'operations\\n\");\n}\n\n\/\/ Fonction pour tester les differents niveaux de printk\nstatic void test_niveaux_printk(void)\n{\n    DEBUG_INFO(\"=== TEST NIVEAUX PRINTK ===\\n\");\n    \n    printk(KERN_EMERG \"Niveau 0: EMERGENCE - Systeme inutilisable\\n\");\n    printk(KERN_ALERT \"Niveau 1: ALERTE - Action immediate requise\\n\");\n    printk(KERN_CRIT \"Niveau 2: CRITIQUE - Conditions critiques\\n\");\n    printk(KERN_ERR \"Niveau 3: ERREUR - Conditions d'erreur\\n\");\n    printk(KERN_WARNING \"Niveau 4: AVERTISSEMENT - Conditions d'avertissement\\n\");\n    printk(KERN_NOTICE \"Niveau 5: NOTICE - Conditions normales mais significatives\\n\");\n    printk(KERN_INFO \"Niveau 6: INFORMATION - Messages informatifs\\n\");\n    printk(KERN_DEBUG \"Niveau 7: DEBUG - Messages de debug\\n\");\n    \n    DEBUG_INFO(\"=== FIN TEST PRINTK ===\\n\");\n}\n\nstatic int __init debug_module_init(void)\n{\n    printk(KERN_INFO \"=== INITIALISATION MODULE DEBUG ===\\n\");\n    \n    DEBUG_INFO(\"Niveau de debug configure: %d\\n\", niveau_debug);\n    \n    dump_infos_systeme();\n    test_niveaux_printk();\n    simulation_operations();\n    \n    DEBUG_INFO(\"=== MODULE DEBUG ACTIF ===\\n\");\n    return 0;\n}\n\nstatic void __exit debug_module_exit(void)\n{\n    DEBUG_INFO(\"=== DECHARGEMENT MODULE DEBUG ===\\n\");\n    \n    DEBUG_INFO(\"Nettoyage des ressources de debug\\n\");\n    DEBUG_DBG(\"Dernier message de debug\\n\");\n    \n    printk(KERN_INFO \"=== MODULE DEBUG DECHARGE ===\\n\");\n}\n\nmodule_init(debug_module_init);\nmodule_exit(debug_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6-4-compilation-avec-makefile-avance\">6.4 Compilation avec Makefile avanc\u00e9<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Makefile professionnel :<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Configuration de compilation\nKVERSION := $(shell uname -r)\nKDIR := \/lib\/modules\/$(KVERSION)\/build\nPWD := $(shell pwd)\n\n# Modules a compiler\nobj-m += error_handling.o\nobj-m += security_checks.o\nobj-m += debug_module.o\n\n# Flags de compilation\nccflags-y := -Wall -Wextra -Wno-unused-parameter\nccflags-y += -DDEBUG\n\n# Cibles de compilation\nall:\n\t@echo \"Compilation des modules noyau...\"\n\t$(MAKE) -C $(KDIR) M=$(PWD) modules\n\n# Compilation avec debug etat\ndebug: ccflags-y += -g -DDEBUG_VERBOSE\ndebug: all\n\n# Compilation release (optimisations)\nrelease: ccflags-y := -O2\nrelease: all\n\n# Nettoyage\nclean:\n\t@echo \"Nettoyage des fichiers generes...\"\n\t$(MAKE) -C $(KDIR) M=$(PWD) clean\n\trm -f *.o *.mod.c Module.symvers modules.order\n\trm -f .*.cmd *.mod *.ko\n\n# Installation des modules\ninstall: all\n\t@echo \"Installation des modules...\"\n\tsudo insmod error_handling.ko || true\n\tsudo insmod security_checks.ko || true\n\tsudo insmod debug_module.ko niveau_debug=4 || true\n\n# Desinstallation\nuninstall:\n\t@echo \"Desinstallation des modules...\"\n\tsudo rmmod debug_module 2&gt;\/dev\/null || true\n\tsudo rmmod security_checks 2&gt;\/dev\/null || true\n\tsudo rmmod error_handling 2&gt;\/dev\/null || true\n\n# Test automatique\ntest: all uninstall\n\t@echo \"=== LANCEMENT DES TESTS ===\"\n\t\n\t@echo \"1. Test gestion d'erreurs...\"\n\tsudo dmesg -C\n\tsudo insmod error_handling.ko\n\tsudo rmmod error_handling\n\tdmesg | tail -10\n\t\n\t@echo \"2. Test securite...\"\n\tsudo dmesg -C\n\tsudo insmod security_checks.ko\n\tsudo rmmod security_checks\n\tdmesg | tail -10\n\t\n\t@echo \"3. Test debug...\"\n\tsudo dmesg -C\n\tsudo insmod debug_module.ko niveau_debug=4\n\tsudo rmmod debug_module\n\tdmesg | tail -15\n\n# Verification de la qualite du code\ncheck:\n\t@echo \"Verification de la qualite du code...\"\n\t@echo \"Checking coding style...\"\n\t@-checkpatch.pl --no-tree --file *.c 2&gt;\/dev\/null || echo \"Install checkpatch.pl for style checking\"\n\n# Aide\nhelp:\n\t@echo \"Cibles disponibles:\"\n\t@echo \"  all       - Compilation standard\"\n\t@echo \"  debug     - Compilation avec symboles debug\"\n\t@echo \"  release   - Compilation optimisee\"\n\t@echo \"  clean     - Nettoyage complet\"\n\t@echo \"  install   - Installation des modules\"\n\t@echo \"  uninstall - Desinstallation des modules\"\n\t@echo \"  test      - Tests automatiques\"\n\t@echo \"  check     - Verification qualite code\"\n\n.PHONY: all debug release clean install uninstall test check help<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6-5-script-de-monitoring-et-debogage\">6.5 Script de monitoring et d\u00e9bogage<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>monitor_system.sh :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#!\/bin\/bash\n# Script de monitoring pour le developpement de modules noyau\n\necho \"=== MONITORING SYSTEME NOYAU ===\"\n\n# Fonction pour afficher les informations des modules\nshow_module_info() {\n    echo \"--- Modules charges ---\"\n    lsmod | head -10\n    echo\n}\n\n# Fonction pour surveiller les messages du noyau\nmonitor_dmesg() {\n    echo \"--- Derniers messages noyau ---\"\n    dmesg | tail -20\n    echo\n}\n\n# Fonction pour verifier l'etat systeme\ncheck_system_health() {\n    echo \"--- Sante du systeme ---\"\n    echo \"Uptime: $(cat \/proc\/uptime | cut -d' ' -f1) seconds\"\n    echo \"Load average: $(cat \/proc\/loadavg)\"\n    echo \"Memoire libre: $(grep MemFree \/proc\/meminfo | awk '{print $2}') kB\"\n    echo\n}\n\n# Fonction pour surveiller un module specifique\nmonitor_module() {\n    local module=$1\n    echo \"--- Surveillance module: $module ---\"\n    \n    if lsmod | grep -q \"$module\"; then\n        echo \"\u2713 Module $module est charge\"\n        # Afficher les messages relatifs au module\n        dmesg | grep \"$module\" | tail -5\n    else\n        echo \"\u2717 Module $module n'est pas charge\"\n    fi\n    echo\n}\n\n# Execution des fonctions\nshow_module_info\nmonitor_dmesg\ncheck_system_health\n\n# Surveillance des modules de test\nmonitor_module \"error_handling\"\nmonitor_module \"security_checks\" \nmonitor_module \"debug_module\"\n\necho \"=== MONITORING TERMINE ===\"<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6-6-commandes-de-debogage-essentielles\">6.6 Commandes de d\u00e9bogage essentielles<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Commandes \u00e0 conna\u00eetre :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Surveillance en temps reel\nsudo dmesg -w\n\n# Nettoyage des logs\nsudo dmesg -C\n\n# Filtrage des messages\ndmesg | grep -i error\ndmesg | grep -i warning\ndmesg | tail -f | grep \"votre_module\"\n\n# Informations systeme\ncat \/proc\/modules\ncat \/proc\/kmsg\ncat \/proc\/kallsyms | grep votre_fonction\n\n# Debug avance\necho 8 > \/proc\/sys\/kernel\/printk  # Augmente verbosite\nsudo strace -p &lt;pid>\nsudo ltrace -p &lt;pid>\n\n# Monitoring performance\nsudo perf record -g -p &lt;pid>\nsudo perf report<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"points-cles-des-bonnes-pratiques\">Points cl\u00e9s des bonnes pratiques :<\/h2>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Gestion d&rsquo;erreurs<\/strong>&nbsp;: Toujours utiliser le pattern goto pour le nettoyage<\/li>\n\n\n\n<li><strong>S\u00e9curit\u00e9<\/strong>&nbsp;: V\u00e9rifier toutes les entr\u00e9es, utiliser BUG_ON pour les invariants<\/li>\n\n\n\n<li><strong>D\u00e9bogage<\/strong>&nbsp;: Niveaux de log appropri\u00e9s, macros de debug<\/li>\n\n\n\n<li><strong>Compilation<\/strong>&nbsp;: Makefile robuste avec diff\u00e9rentes configurations<\/li>\n\n\n\n<li><strong>Monitoring<\/strong>&nbsp;: Scripts pour surveiller l&rsquo;\u00e9tat du syst\u00e8me<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"partie-7-concepts-avances\">PARTIE 7 : CONCEPTS AVANC\u00c9S<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"7-1-interruptions-et-gestionnaires-d-irq\">7.1 Interruptions et gestionnaires d&rsquo;IRQ<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"7-1-1-module-avec-gestion-d-interruption-gpio\">7.1.1 Module avec gestion d&rsquo;interruption GPIO<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>irq_handler.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/interrupt.h>\n#include &lt;linux\/gpio.h>\n#include &lt;linux\/delay.h>\n#include &lt;linux\/atomic.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Expert IRQ\");\nMODULE_DESCRIPTION(\"Gestionnaire d'interruption pour bouton GPIO\");\n\n\/\/ Configuration - ADAPTER \u00c0 VOTRE MAT\u00c9RIEL !\nstatic int gpio_bouton = 17;    \/\/ GPIO pour le bouton (entr\u00e9e)\nstatic int gpio_led = 4;        \/\/ GPIO pour la LED (sortie)\nstatic int irq_number;          \/\/ Num\u00e9ro d'IRQ assign\u00e9\n\nmodule_param(gpio_bouton, int, 0644);\nmodule_param(gpio_led, int, 0644);\n\n\/\/ \u00c9tat global avec protection\nstatic struct {\n    atomic_t compteur_pressions;    \/\/ Compteur atomique\n    bool bouton_appuye;             \/\/ \u00c9tat actuel\n    spinlock_t lock_etat;           \/\/ Verrou pour l'\u00e9tat\n    struct timer_list timer_anti_rebond;\n} etat_irq = {\n    .compteur_pressions = ATOMIC_INIT(0),\n    .bouton_appuye = false,\n};\n\n\/\/ Fonction de timer pour anti-rebond\nstatic void timer_anti_rebond_callback(struct timer_list *t)\n{\n    unsigned long flags;\n    int valeur_bouton;\n    \n    \/\/ Lire l'\u00e9tat actuel du bouton\n    valeur_bouton = gpio_get_value(gpio_bouton);\n    \n    spin_lock_irqsave(&amp;etat_irq.lock_etat, flags);\n    \n    if (valeur_bouton &amp;&amp; !etat_irq.bouton_appuye) {\n        \/\/ Front montant d\u00e9tect\u00e9 - bouton press\u00e9\n        etat_irq.bouton_appuye = true;\n        atomic_inc(&amp;etat_irq.compteur_pressions);\n        \n        \/\/ Basculer la LED\n        gpio_set_value(gpio_led, !gpio_get_value(gpio_led));\n        \n        printk(KERN_INFO \"Bouton PRESSE (compteur: %d)\\n\", \n               atomic_read(&amp;etat_irq.compteur_pressions));\n    } \n    else if (!valeur_bouton &amp;&amp; etat_irq.bouton_appuye) {\n        \/\/ Front descendant - bouton rel\u00e2ch\u00e9\n        etat_irq.bouton_appuye = false;\n        printk(KERN_INFO \"Bouton RELACHE\\n\");\n    }\n    \n    spin_unlock_irqrestore(&amp;etat_irq.lock_etat, flags);\n}\n\n\/\/ Gestionnaire d'interruption\nstatic irqreturn_t gestionnaire_bouton(int irq, void *dev_id)\n{\n    \/\/ Programmer le timer anti-rebond (d\u00e9lai de 50ms)\n    mod_timer(&amp;etat_irq.timer_anti_rebond, jiffies + msecs_to_jiffies(50));\n    \n    return IRQ_HANDLED;\n}\n\n\/\/ Configuration des GPIO et IRQ\nstatic int configurer_gpio_irq(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"Configuration GPIO bouton: %d, LED: %d\\n\", \n           gpio_bouton, gpio_led);\n    \n    \/\/ V\u00e9rification des GPIO\n    if (!gpio_is_valid(gpio_bouton) || !gpio_is_valid(gpio_led)) {\n        printk(KERN_ERR \"GPIO invalide\\n\");\n        return -EINVAL;\n    }\n    \n    \/\/ Configuration LED (sortie)\n    ret = gpio_request(gpio_led, \"irq_led\");\n    if (ret) {\n        printk(KERN_ERR \"Erreur GPIO LED %d: %d\\n\", gpio_led, ret);\n        return ret;\n    }\n    gpio_direction_output(gpio_led, 0);\n    \n    \/\/ Configuration bouton (entr\u00e9e)\n    ret = gpio_request(gpio_bouton, \"irq_bouton\");\n    if (ret) {\n        printk(KERN_ERR \"Erreur GPIO bouton %d: %d\\n\", gpio_bouton, ret);\n        gpio_free(gpio_led);\n        return ret;\n    }\n    gpio_direction_input(gpio_bouton);\n    \n    \/\/ Obtenir le num\u00e9ro d'IRQ pour le GPIO\n    irq_number = gpio_to_irq(gpio_bouton);\n    if (irq_number &lt; 0) {\n        printk(KERN_ERR \"Impossible d'obtenir IRQ pour GPIO %d: %d\\n\", \n               gpio_bouton, irq_number);\n        gpio_free(gpio_bouton);\n        gpio_free(gpio_led);\n        return irq_number;\n    }\n    \n    printk(KERN_INFO \"GPIO %d mappe vers IRQ %d\\n\", gpio_bouton, irq_number);\n    return 0;\n}\n\n\/\/ Enregistrement du gestionnaire d'interruption\nstatic int enregistrer_irq_handler(void)\n{\n    int ret;\n    \n    \/\/ Initialiser le spinlock\n    spin_lock_init(&amp;etat_irq.lock_etat);\n    \n    \/\/ Initialiser le timer anti-rebond\n    timer_setup(&amp;etat_irq.timer_anti_rebond, timer_anti_rebond_callback, 0);\n    \n    \/\/ Enregistrer le gestionnaire d'IRQ\n    \/\/ IRQF_TRIGGER_RISING : d\u00e9clenche sur front montant\n    \/\/ IRQF_TRIGGER_FALLING : d\u00e9clenche sur front descendant  \n    ret = request_irq(irq_number, gestionnaire_bouton,\n                     IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,\n                     \"bouton_gpio\", NULL);\n    \n    if (ret) {\n        printk(KERN_ERR \"Echec enregistrement IRQ %d: %d\\n\", irq_number, ret);\n        return ret;\n    }\n    \n    printk(KERN_INFO \"Gestionnaire IRQ enregistre avec succes\\n\");\n    return 0;\n}\n\nstatic int __init irq_module_init(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"=== INITIALISATION GESTIONNAIRE IRQ ===\\n\");\n    \n    \/\/ Configuration mat\u00e9rielle\n    ret = configurer_gpio_irq();\n    if (ret) {\n        goto erreur;\n    }\n    \n    \/\/ Enregistrement IRQ\n    ret = enregistrer_irq_handler();\n    if (ret) {\n        goto erreur_cleanup_gpio;\n    }\n    \n    printk(KERN_INFO \"=== GESTIONNAIRE IRQ ACTIF ===\\n\");\n    printk(KERN_INFO \"Appuyez sur le bouton GPIO %d pour tester\\n\", gpio_bouton);\n    printk(KERN_INFO \"LED sur GPIO %d basculera a chaque pression\\n\", gpio_led);\n    \n    return 0;\n\nerreur_cleanup_gpio:\n    gpio_free(gpio_bouton);\n    gpio_free(gpio_led);\nerreur:\n    printk(KERN_ERR \"=== ECHEC INITIALISATION IRQ ===\\n\");\n    return ret;\n}\n\nstatic void __exit irq_module_exit(void)\n{\n    printk(KERN_INFO \"=== DECHARGEMENT GESTIONNAIRE IRQ ===\\n\");\n    \n    \/\/ Lib\u00e9rer l'IRQ\n    free_irq(irq_number, NULL);\n    \n    \/\/ Arr\u00eater le timer\n    del_timer_sync(&amp;etat_irq.timer_anti_rebond);\n    \n    \/\/ Lib\u00e9rer les GPIO\n    gpio_free(gpio_bouton);\n    gpio_free(gpio_led);\n    \n    \/\/ Afficher les statistiques finales\n    printk(KERN_INFO \"Statistiques finales:\\n\");\n    printk(KERN_INFO \"- Pressions totales: %d\\n\", \n           atomic_read(&amp;etat_irq.compteur_pressions));\n    \n    printk(KERN_INFO \"=== GESTIONNAIRE IRQ DESACTIVE ===\\n\");\n}\n\nmodule_init(irq_module_init);\nmodule_exit(irq_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"7-2-systemes-de-fichiers-virtuels\">7.2 Syst\u00e8mes de fichiers virtuels<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"7-2-1-interface-procfs-pour-le-module\">7.2.1 Interface procfs pour le module<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>procfs_interface.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/proc_fs.h>\n#include &lt;linux\/seq_file.h>\n#include &lt;linux\/slab.h>\n#include &lt;linux\/string.h>\n#include &lt;linux\/uaccess.h>\n#include &lt;linux\/jiffies.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Expert VFS\");\nMODULE_DESCRIPTION(\"Interface procfs pour module noyau\");\n\n#define PROC_DIR \"mon_module\"\n#define PROC_FILE_STAT \"statistiques\"\n#define PROC_FILE_CONFIG \"configuration\"\n\nstatic struct proc_dir_entry *proc_dir = NULL;\nstatic struct proc_dir_entry *proc_stat = NULL;\nstatic struct proc_dir_entry *proc_config = NULL;\n\n\/\/ Structure pour les statistiques\nstatic struct {\n    atomic_t lectures;\n    atomic_t ecritures;\n    unsigned long demarrage;\n    char derniere_commande[100];\n} stats = {\n    .lectures = ATOMIC_INIT(0),\n    .ecritures = ATOMIC_INIT(0),\n    .demarrage = 0,\n    .derniere_commande = \"\"\n};\n\n\/\/ Callback pour lecture du fichier statistiques\nstatic int proc_stat_show(struct seq_file *m, void *v)\n{\n    unsigned long uptime = jiffies - stats.demarrage;\n    \n    atomic_inc(&amp;stats.lectures);\n    \n    seq_printf(m, \"=== STATISTIQUES MODULE ===\\n\");\n    seq_printf(m, \"Uptime: %lu secondes\\n\", uptime \/ HZ);\n    seq_printf(m, \"Lectures procfs: %d\\n\", atomic_read(&amp;stats.lectures));\n    seq_printf(m, \"Ecritures procfs: %d\\n\", atomic_read(&amp;stats.ecritures));\n    seq_printf(m, \"Derniere commande: %s\\n\", stats.derniere_commande);\n    seq_printf(m, \"Timestamp: %lu\\n\", jiffies);\n    \n    return 0;\n}\n\n\/\/ Callback pour ouverture du fichier statistiques\nstatic int proc_stat_open(struct inode *inode, struct file *file)\n{\n    return single_open(file, proc_stat_show, NULL);\n}\n\n\/\/ Callback pour \u00e9criture dans le fichier configuration\nstatic ssize_t proc_config_write(struct file *file, const char __user *buffer,\n                                size_t count, loff_t *ppos)\n{\n    char *commande;\n    int ret;\n    \n    atomic_inc(&amp;stats.ecritures);\n    \n    \/\/ Allouer un buffer pour la commande\n    commande = kmalloc(count + 1, GFP_KERNEL);\n    if (!commande) {\n        return -ENOMEM;\n    }\n    \n    \/\/ Copier depuis l'espace utilisateur\n    if (copy_from_user(commande, buffer, count)) {\n        kfree(commande);\n        return -EFAULT;\n    }\n    \n    commande[count] = '\\0';\n    \n    \/\/ Supprimer le saut de ligne si pr\u00e9sent\n    if (commande[count - 1] == '\\n') {\n        commande[count - 1] = '\\0';\n    }\n    \n    \/\/ Traiter la commande\n    printk(KERN_INFO \"Commande recue via procfs: %s\\n\", commande);\n    \n    \/\/ Sauvegarder la derni\u00e8re commande\n    strncpy(stats.derniere_commande, commande, sizeof(stats.derniere_commande) - 1);\n    stats.derniere_commande[sizeof(stats.derniere_commande) - 1] = '\\0';\n    \n    kfree(commande);\n    return count;\n}\n\n\/\/ Callback pour lecture du fichier configuration\nstatic int proc_config_show(struct seq_file *m, void *v)\n{\n    atomic_inc(&amp;stats.lectures);\n    \n    seq_printf(m, \"=== CONFIGURATION MODULE ===\\n\");\n    seq_printf(m, \"Interface procfs active\\n\");\n    seq_printf(m, \"Repertoire: \/proc\/%s\\n\", PROC_DIR);\n    seq_printf(m, \"Fichiers disponibles:\\n\");\n    seq_printf(m, \" - %s (lecture seule)\\n\", PROC_FILE_STAT);\n    seq_printf(m, \" - %s (lecture\/ecriture)\\n\", PROC_FILE_CONFIG);\n    seq_printf(m, \"Ecrire une commande dans %s pour la tester\\n\", PROC_FILE_CONFIG);\n    \n    return 0;\n}\n\nstatic int proc_config_open(struct inode *inode, struct file *file)\n{\n    return single_open(file, proc_config_show, NULL);\n}\n\n\/\/ Operations pour les fichiers procfs\nstatic const struct proc_ops proc_stat_fops = {\n    .proc_open = proc_stat_open,\n    .proc_read = seq_read,\n    .proc_lseek = seq_lseek,\n    .proc_release = single_release,\n};\n\nstatic const struct proc_ops proc_config_fops = {\n    .proc_open = proc_config_open,\n    .proc_read = seq_read,\n    .proc_write = proc_config_write,\n    .proc_lseek = seq_lseek,\n    .proc_release = single_release,\n};\n\n\/\/ Cr\u00e9ation de l'interface procfs\nstatic int creer_interface_procfs(void)\n{\n    \/\/ Cr\u00e9er le r\u00e9pertoire\n    proc_dir = proc_mkdir(PROC_DIR, NULL);\n    if (!proc_dir) {\n        printk(KERN_ERR \"Echec creation repertoire \/proc\/%s\\n\", PROC_DIR);\n        return -ENOMEM;\n    }\n    \n    \/\/ Cr\u00e9er le fichier statistiques (lecture seule)\n    proc_stat = proc_create(PROC_FILE_STAT, 0444, proc_dir, &amp;proc_stat_fops);\n    if (!proc_stat) {\n        printk(KERN_ERR \"Echec creation fichier %s\\n\", PROC_FILE_STAT);\n        remove_proc_entry(PROC_DIR, NULL);\n        return -ENOMEM;\n    }\n    \n    \/\/ Cr\u00e9er le fichier configuration (lecture\/\u00e9criture)\n    proc_config = proc_create(PROC_FILE_CONFIG, 0644, proc_dir, &amp;proc_config_fops);\n    if (!proc_config) {\n        printk(KERN_ERR \"Echec creation fichier %s\\n\", PROC_FILE_CONFIG);\n        remove_proc_entry(PROC_FILE_STAT, proc_dir);\n        remove_proc_entry(PROC_DIR, NULL);\n        return -ENOMEM;\n    }\n    \n    printk(KERN_INFO \"Interface procfs creee: \/proc\/%s\/\\n\", PROC_DIR);\n    return 0;\n}\n\nstatic int __init procfs_module_init(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"=== INITIALISATION MODULE PROCFS ===\\n\");\n    \n    \/\/ Initialiser les statistiques\n    stats.demarrage = jiffies;\n    strcpy(stats.derniere_commande, \"Aucune\");\n    \n    \/\/ Cr\u00e9er l'interface procfs\n    ret = creer_interface_procfs();\n    if (ret) {\n        goto erreur;\n    }\n    \n    printk(KERN_INFO \"=== MODULE PROCFS ACTIF ===\\n\");\n    printk(KERN_INFO \"Interface disponible dans \/proc\/%s\/\\n\", PROC_DIR);\n    printk(KERN_INFO \" - cat \/proc\/%s\/%s pour les statistiques\\n\", \n           PROC_DIR, PROC_FILE_STAT);\n    printk(KERN_INFO \" - echo 'commande' > \/proc\/%s\/%s pour tester\\n\",\n           PROC_DIR, PROC_FILE_CONFIG);\n    \n    return 0;\n\nerreur:\n    printk(KERN_ERR \"=== ECHEC INITIALISATION PROCFS ===\\n\");\n    return ret;\n}\n\nstatic void __exit procfs_module_exit(void)\n{\n    printk(KERN_INFO \"=== DECHARGEMENT MODULE PROCFS ===\\n\");\n    \n    \/\/ Nettoyer l'interface procfs\n    if (proc_config) {\n        remove_proc_entry(PROC_FILE_CONFIG, proc_dir);\n    }\n    if (proc_stat) {\n        remove_proc_entry(PROC_FILE_STAT, proc_dir);\n    }\n    if (proc_dir) {\n        remove_proc_entry(PROC_DIR, NULL);\n    }\n    \n    \/\/ Afficher les statistiques finales\n    printk(KERN_INFO \"Statistiques finales procfs:\\n\");\n    printk(KERN_INFO \"- Lectures: %d\\n\", atomic_read(&amp;stats.lectures));\n    printk(KERN_INFO \"- Ecritures: %d\\n\", atomic_read(&amp;stats.ecritures));\n    \n    printk(KERN_INFO \"=== MODULE PROCFS DESACTIVE ===\\n\");\n}\n\nmodule_init(procfs_module_init);\nmodule_exit(procfs_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"7-3-peripheriques-caracteres\">7.3 P\u00e9riph\u00e9riques caract\u00e8res<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"7-3-1-driver-de-peripherique-caractere-complet\">7.3.1 Driver de p\u00e9riph\u00e9rique caract\u00e8re complet<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>char_device.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/fs.h>\n#include &lt;linux\/cdev.h>\n#include &lt;linux\/device.h>\n#include &lt;linux\/uaccess.h>\n#include &lt;linux\/slab.h>\n#include &lt;linux\/mutex.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Expert Char Device\");\nMODULE_DESCRIPTION(\"Pilote de peripherique caractere complet\");\n\n#define DEVICE_NAME \"mon_device\"\n#define CLASS_NAME \"mon_module\"\n#define BUFFER_SIZE 4096\n\n\/\/ Structure principale du device\nstruct char_device_data {\n    struct cdev cdev;\n    struct class *device_class;\n    struct device *device;\n    dev_t dev_num;\n    \n    char *buffer;\n    size_t buffer_usage;\n    struct mutex lock;  \/\/ Mutex pour la synchronisation\n    \n    atomic_t open_count;\n};\n\nstatic struct char_device_data dev_data;\n\n\/\/ Fonctions file_operations\nstatic int device_open(struct inode *inode, struct file *file)\n{\n    atomic_inc(&amp;dev_data.open_count);\n    printk(KERN_INFO \"Device ouvert (ouvertures: %d)\\n\", \n           atomic_read(&amp;dev_data.open_count));\n    return 0;\n}\n\nstatic int device_release(struct inode *inode, struct file *file)\n{\n    atomic_dec(&amp;dev_data.open_count);\n    printk(KERN_INFO \"Device ferme (ouvertures restantes: %d)\\n\",\n           atomic_read(&amp;dev_data.open_count));\n    return 0;\n}\n\nstatic ssize_t device_read(struct file *filp, char __user *buffer, \n                          size_t length, loff_t *offset)\n{\n    ssize_t bytes_read = 0;\n    \n    \/\/ Verrouiller le mutex\n    if (mutex_lock_interruptible(&amp;dev_data.lock)) {\n        return -ERESTARTSYS;\n    }\n    \n    \/\/ Verifier si on a depasse la fin des donnees\n    if (*offset >= dev_data.buffer_usage) {\n        mutex_unlock(&amp;dev_data.lock);\n        return 0;  \/\/ EOF\n    }\n    \n    \/\/ Calculer le nombre d'octets a lire\n    if (*offset + length > dev_data.buffer_usage) {\n        bytes_read = dev_data.buffer_usage - *offset;\n    } else {\n        bytes_read = length;\n    }\n    \n    \/\/ Copier vers l'espace utilisateur\n    if (copy_to_user(buffer, dev_data.buffer + *offset, bytes_read)) {\n        mutex_unlock(&amp;dev_data.lock);\n        return -EFAULT;\n    }\n    \n    \/\/ Mettre a jour l'offset\n    *offset += bytes_read;\n    \n    mutex_unlock(&amp;dev_data.lock);\n    \n    printk(KERN_DEBUG \"Lecture de %zd octets (offset: %lld)\\n\", \n           bytes_read, *offset);\n    \n    return bytes_read;\n}\n\nstatic ssize_t device_write(struct file *filp, const char __user *buffer,\n                           size_t length, loff_t *offset)\n{\n    ssize_t bytes_written = 0;\n    \n    \/\/ Verrouiller le mutex\n    if (mutex_lock_interruptible(&amp;dev_data.lock)) {\n        return -ERESTARTSYS;\n    }\n    \n    \/\/ Verifier si on depasse la taille du buffer\n    if (*offset >= BUFFER_SIZE) {\n        mutex_unlock(&amp;dev_data.lock);\n        return -ENOSPC;\n    }\n    \n    \/\/ Calculer le nombre d'octets a ecrire\n    if (*offset + length > BUFFER_SIZE) {\n        bytes_written = BUFFER_SIZE - *offset;\n    } else {\n        bytes_written = length;\n    }\n    \n    \/\/ Copier depuis l'espace utilisateur\n    if (copy_from_user(dev_data.buffer + *offset, buffer, bytes_written)) {\n        mutex_unlock(&amp;dev_data.lock);\n        return -EFAULT;\n    }\n    \n    \/\/ Mettre a jour l'usage et l'offset\n    if (*offset + bytes_written > dev_data.buffer_usage) {\n        dev_data.buffer_usage = *offset + bytes_written;\n    }\n    *offset += bytes_written;\n    \n    mutex_unlock(&amp;dev_data.lock);\n    \n    printk(KERN_DEBUG \"Ecriture de %zd octets (usage total: %zu)\\n\",\n           bytes_written, dev_data.buffer_usage);\n    \n    return bytes_written;\n}\n\nstatic loff_t device_llseek(struct file *filp, loff_t offset, int whence)\n{\n    loff_t newpos;\n    \n    if (mutex_lock_interruptible(&amp;dev_data.lock)) {\n        return -ERESTARTSYS;\n    }\n    \n    switch (whence) {\n        case 0: \/* SEEK_SET *\/\n            newpos = offset;\n            break;\n        case 1: \/* SEEK_CUR *\/\n            newpos = filp->f_pos + offset;\n            break;\n        case 2: \/* SEEK_END *\/\n            newpos = dev_data.buffer_usage + offset;\n            break;\n        default: \/* Error *\/\n            mutex_unlock(&amp;dev_data.lock);\n            return -EINVAL;\n    }\n    \n    \/\/ Validation de la nouvelle position\n    if (newpos &lt; 0 || newpos > BUFFER_SIZE) {\n        mutex_unlock(&amp;dev_data.lock);\n        return -EINVAL;\n    }\n    \n    filp->f_pos = newpos;\n    mutex_unlock(&amp;dev_data.lock);\n    \n    return newpos;\n}\n\n\/\/ Structure file_operations\nstatic const struct file_operations fops = {\n    .owner = THIS_MODULE,\n    .open = device_open,\n    .release = device_release,\n    .read = device_read,\n    .write = device_write,\n    .llseek = device_llseek,\n};\n\n\/\/ Initialisation du device\nstatic int initialiser_device(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"Initialisation du peripherique caractere...\\n\");\n    \n    \/\/ Allocation du numero de device\n    ret = alloc_chrdev_region(&amp;dev_data.dev_num, 0, 1, DEVICE_NAME);\n    if (ret &lt; 0) {\n        printk(KERN_ERR \"Echec allocation numero device\\n\");\n        return ret;\n    }\n    \n    \/\/ Initialisation du cdev\n    cdev_init(&amp;dev_data.cdev, &amp;fops);\n    dev_data.cdev.owner = THIS_MODULE;\n    \n    \/\/ Ajout du cdev au systeme\n    ret = cdev_add(&amp;dev_data.cdev, dev_data.dev_num, 1);\n    if (ret) {\n        printk(KERN_ERR \"Echec ajout cdev\\n\");\n        unregister_chrdev_region(dev_data.dev_num, 1);\n        return ret;\n    }\n    \n    \/\/ Creation de la classe\n    dev_data.device_class = class_create(CLASS_NAME);\n    if (IS_ERR(dev_data.device_class)) {\n        printk(KERN_ERR \"Echec creation classe\\n\");\n        cdev_del(&amp;dev_data.cdev);\n        unregister_chrdev_region(dev_data.dev_num, 1);\n        return PTR_ERR(dev_data.device_class);\n    }\n    \n    \/\/ Creation du device\n    dev_data.device = device_create(dev_data.device_class, NULL,\n                                   dev_data.dev_num, NULL, DEVICE_NAME);\n    if (IS_ERR(dev_data.device)) {\n        printk(KERN_ERR \"Echec creation device\\n\");\n        class_destroy(dev_data.device_class);\n        cdev_del(&amp;dev_data.cdev);\n        unregister_chrdev_region(dev_data.dev_num, 1);\n        return PTR_ERR(dev_data.device);\n    }\n    \n    \/\/ Allocation du buffer\n    dev_data.buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);\n    if (!dev_data.buffer) {\n        printk(KERN_ERR \"Echec allocation buffer\\n\");\n        device_destroy(dev_data.device_class, dev_data.dev_num);\n        class_destroy(dev_data.device_class);\n        cdev_del(&amp;dev_data.cdev);\n        unregister_chrdev_region(dev_data.dev_num, 1);\n        return -ENOMEM;\n    }\n    \n    \/\/ Initialisation des donnees\n    dev_data.buffer_usage = 0;\n    mutex_init(&amp;dev_data.lock);\n    atomic_set(&amp;dev_data.open_count, 0);\n    \n    \/\/ Message d'accueil dans le buffer\n    strncpy(dev_data.buffer, \"Bienvenue dans le pilote de peripherique caractere!\\n\", \n            BUFFER_SIZE - 1);\n    dev_data.buffer_usage = strlen(dev_data.buffer);\n    \n    printk(KERN_INFO \"Peripherique caractere initialise: %s (majeur: %d)\\n\",\n           DEVICE_NAME, MAJOR(dev_data.dev_num));\n    \n    return 0;\n}\n\nstatic int __init char_device_init(void)\n{\n    int ret;\n    \n    printk(KERN_INFO \"=== INITIALISATION PERIPHERIQUE CARACTERE ===\\n\");\n    \n    ret = initialiser_device();\n    if (ret) {\n        goto erreur;\n    }\n    \n    printk(KERN_INFO \"=== PERIPHERIQUE CARACTERE ACTIF ===\\n\");\n    printk(KERN_INFO \"Device cree: \/dev\/%s\\n\", DEVICE_NAME);\n    printk(KERN_INFO \"Testez avec: echo 'test' > \/dev\/%s\\n\", DEVICE_NAME);\n    printk(KERN_INFO \"Puis: cat \/dev\/%s\\n\", DEVICE_NAME);\n    \n    return 0;\n\nerreur:\n    printk(KERN_ERR \"=== ECHEC INITIALISATION PERIPHERIQUE ===\\n\");\n    return ret;\n}\n\nstatic void __exit char_device_exit(void)\n{\n    printk(KERN_INFO \"=== DECHARGEMENT PERIPHERIQUE CARACTERE ===\\n\");\n    \n    \/\/ Nettoyage dans l'ordre inverse\n    if (dev_data.buffer) {\n        kfree(dev_data.buffer);\n    }\n    \n    if (dev_data.device) {\n        device_destroy(dev_data.device_class, dev_data.dev_num);\n    }\n    \n    if (dev_data.device_class) {\n        class_destroy(dev_data.device_class);\n    }\n    \n    if (dev_data.cdev.ops) {\n        cdev_del(&amp;dev_data.cdev);\n    }\n    \n    if (dev_data.dev_num) {\n        unregister_chrdev_region(dev_data.dev_num, 1);\n    }\n    \n    printk(KERN_INFO \"=== PERIPHERIQUE CARACTERE DESACTIVE ===\\n\");\n}\n\nmodule_init(char_device_init);\nmodule_exit(char_device_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"7-4-synchronisation-mutex-spinlocks\">7.4 Synchronisation : mutex, spinlocks<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"7-4-1-module-de-demonstration-de-synchronisation\">7.4.1 Module de d\u00e9monstration de synchronisation<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>synchronisation.c :<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;linux\/module.h>\n#include &lt;linux\/kernel.h>\n#include &lt;linux\/init.h>\n#include &lt;linux\/kthread.h>\n#include &lt;linux\/sched.h>\n#include &lt;linux\/delay.h>\n#include &lt;linux\/mutex.h>\n#include &lt;linux\/spinlock.h>\n#include &lt;linux\/atomic.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Expert Synchronisation\");\nMODULE_DESCRIPTION(\"Demonstration mutex, spinlocks et atomic\");\n\n#define NUM_THREADS 3\n\n\/\/ Ressource partagee\nstatic struct {\n    int compteur_standard;\n    atomic_t compteur_atomique;\n    struct mutex verrou_mutex;\n    spinlock_t verrou_spin;\n    bool execution;\n} shared_data = {\n    .compteur_standard = 0,\n    .compteur_atomique = ATOMIC_INIT(0),\n    .execution = true\n};\n\n\/\/ Structure pour les threads\nstatic struct task_struct *threads[NUM_THREADS];\n\n\/\/ Fonction thread avec mutex\nstatic int thread_mutex_func(void *data)\n{\n    int thread_id = (long)data;\n    int i;\n    \n    printk(KERN_INFO \"Thread mutex %d demarre\\n\", thread_id);\n    \n    for (i = 0; i &lt; 100 &amp;&amp; shared_data.execution; i++) {\n        \/\/ Section critique protegee par mutex\n        mutex_lock(&amp;shared_data.verrou_mutex);\n        \n        \/\/ Operation non atomique\n        shared_data.compteur_standard++;\n        printk(KERN_DEBUG \"Thread %d: compteur = %d\\n\", \n               thread_id, shared_data.compteur_standard);\n        \n        mutex_unlock(&amp;shared_data.verrou_mutex);\n        \n        \/\/ Pause courte\n        usleep_range(1000, 5000);\n    }\n    \n    printk(KERN_INFO \"Thread mutex %d termine\\n\", thread_id);\n    return 0;\n}\n\n\/\/ Fonction thread avec spinlock\nstatic int thread_spinlock_func(void *data)\n{\n    int thread_id = (long)data;\n    int i;\n    unsigned long flags;\n    \n    printk(KERN_INFO \"Thread spinlock %d demarre\\n\", thread_id);\n    \n    for (i = 0; i &lt; 100 &amp;&amp; shared_data.execution; i++) {\n        \/\/ Section critique protegee par spinlock\n        spin_lock_irqsave(&amp;shared_data.verrou_spin, flags);\n        \n        \/\/ Operation non atomique\n        shared_data.compteur_standard++;\n        printk(KERN_DEBUG \"Thread %d (spin): compteur = %d\\n\", \n               thread_id, shared_data.compteur_standard);\n        \n        spin_unlock_irqrestore(&amp;shared_data.verrou_spin, flags);\n        \n        \/\/ Pause courte\n        usleep_range(1000, 5000);\n    }\n    \n    printk(KERN_INFO \"Thread spinlock %d termine\\n\", thread_id);\n    return 0;\n}\n\n\/\/ Fonction thread avec operations atomiques\nstatic int thread_atomic_func(void *data)\n{\n    int thread_id = (long)data;\n    int i;\n    \n    printk(KERN_INFO \"Thread atomic %d demarre\\n\", thread_id);\n    \n    for (i = 0; i &lt; 200 &amp;&amp; shared_data.execution; i++) {\n        \/\/ Operation atomique - pas besoin de verrou\n        atomic_inc(&amp;shared_data.compteur_atomique);\n        \n        printk(KERN_DEBUG \"Thread %d (atomic): compteur = %d\\n\", \n               thread_id, atomic_read(&amp;shared_data.compteur_atomique));\n        \n        \/\/ Pause courte\n        usleep_range(500, 2000);\n    }\n    \n    printk(KERN_INFO \"Thread atomic %d termine\\n\", thread_id);\n    return 0;\n}\n\n\/\/ Lancement des threads\nstatic int lancer_threads(void)\n{\n    int i;\n    \n    printk(KERN_INFO \"Lancement de %d threads...\\n\", NUM_THREADS);\n    \n    \/\/ Thread 1: Mutex\n    threads[0] = kthread_run(thread_mutex_func, (void *)1, \"thread_mutex\");\n    if (IS_ERR(threads[0])) {\n        printk(KERN_ERR \"Echec creation thread mutex\\n\");\n        return PTR_ERR(threads[0]);\n    }\n    \n    \/\/ Thread 2: Spinlock\n    threads[1] = kthread_run(thread_spinlock_func, (void *)2, \"thread_spinlock\");\n    if (IS_ERR(threads[1])) {\n        printk(KERN_ERR \"Echec creation thread spinlock\\n\");\n        kthread_stop(threads[0]);\n        return PTR_ERR(threads[1]);\n    }\n    \n    \/\/ Thread 3: Atomic\n    threads[2] = kthread_run(thread_atomic_func, (void *)3, \"thread_atomic\");\n    if (IS_ERR(threads[2])) {\n        printk(KERN_ERR \"Echec creation thread atomic\\n\");\n        kthread_stop(threads[0]);\n        kthread_stop(threads[1]);\n        return PTR_ERR(threads[2]);\n    }\n    \n    return 0;\n}\n\nstatic int __init sync_module_init(void)\n{\n    int ret;\n    int i;\n    \n    printk(KERN_INFO \"=== INITIALISATION SYNCHRONISATION ===\\n\");\n    \n    \/\/ Initialisation des mecanismes de synchronisation\n    mutex_init(&amp;shared_data.verrou_mutex);\n    spin_lock_init(&amp;shared_data.verrou_spin);\n    \n    \/\/ Lancement des threads\n    ret = lancer_threads();\n    if (ret) {\n        goto erreur;\n    }\n    \n    \/\/ Attendre un peu pour que les threads travaillent\n    printk(KERN_INFO \"Les threads travaillent pendant 5 secondes...\\n\");\n    msleep(5000);\n    \n    \/\/ Arreter l'execution\n    shared_data.execution = false;\n    \n    \/\/ Attendre la fin des threads\n    for (i = 0; i &lt; NUM_THREADS; i++) {\n        if (!IS_ERR(threads[i])) {\n            kthread_stop(threads[i]);\n        }\n    }\n    \n    \/\/ Afficher les resultats finaux\n    printk(KERN_INFO \"=== RESULTATS SYNCHRONISATION ===\\n\");\n    printk(KERN_INFO \"Compteur standard (mutex\/spinlock): %d\\n\", \n           shared_data.compteur_standard);\n    printk(KERN_INFO \"Compteur atomique: %d\\n\", \n           atomic_read(&amp;shared_data.compteur_atomique));\n    \n    printk(KERN_INFO \"=== MODULE SYNCHRONISATION ACTIF ===\\n\");\n    return 0;\n\nerreur:\n    printk(KERN_ERR \"=== ECHEC INITIALISATION SYNCHRONISATION ===\\n\");\n    return ret;\n}\n\nstatic void __exit sync_module_exit(void)\n{\n    int i;\n    \n    printk(KERN_INFO \"=== DECHARGEMENT SYNCHRONISATION ===\\n\");\n    \n    \/\/ S'assurer que tous les threads sont arretes\n    shared_data.execution = false;\n    \n    for (i = 0; i &lt; NUM_THREADS; i++) {\n        if (!IS_ERR(threads[i])) {\n            kthread_stop(threads[i]);\n        }\n    }\n    \n    \/\/ Detruire les mutex\n    mutex_destroy(&amp;shared_data.verrou_mutex);\n    \n    printk(KERN_INFO \"=== MODULE SYNCHRONISATION DESACTIVE ===\\n\");\n}\n\nmodule_init(sync_module_init);\nmodule_exit(sync_module_exit);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"7-5-makefile-pour-les-concepts-avances\">7.5 Makefile pour les concepts avanc\u00e9s<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Makefile :<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Configuration\nKVERSION := $(shell uname -r)\nKDIR := \/lib\/modules\/$(KVERSION)\/build\nPWD := $(shell pwd)\n\n# Modules avances\nobj-m += irq_handler.o\nobj-m += procfs_interface.o\nobj-m += char_device.o\nobj-m += synchronisation.o\n\n# Flags\nccflags-y := -Wall -Wextra -Wno-unused-parameter\nccflags-y += -DDEBUG\n\nall:\n\t@echo \"Compilation des modules avances...\"\n\t$(MAKE) -C $(KDIR) M=$(PWD) modules\n\nclean:\n\t$(MAKE) -C $(KDIR) M=$(PWD) clean\n\n# Tests specifiques\ntest-irq: all\n\tsudo dmesg -C\n\tsudo insmod irq_handler.ko gpio_bouton=17 gpio_led=4\n\tdmesg\n\t# Tester en appuyant sur le bouton physique\n\tsleep 10\n\tsudo rmmod irq_handler\n\tdmesg\n\ntest-procfs: all\n\tsudo dmesg -C\n\tsudo insmod procfs_interface.ko\n\tdmesg\n\tcat \/proc\/mon_module\/statistiques\n\techo \"test_command\" > \/proc\/mon_module\/configuration\n\tcat \/proc\/mon_module\/statistiques\n\tsudo rmmod procfs_interface\n\tdmesg\n\ntest-char: all\n\tsudo dmesg -C\n\tsudo insmod char_device.ko\n\tdmesg\n\tsudo mknod \/dev\/mon_device c $(shell cat \/proc\/devices | grep mon_device | cut -d' ' -f1) 0\n\techo \"Hello Device Driver!\" > \/dev\/mon_device\n\tcat \/dev\/mon_device\n\tsudo rmmod char_device\n\tdmesg\n\ntest-sync: all\n\tsudo dmesg -C\n\tsudo insmod synchronisation.ko\n\tdmesg\n\tsudo rmmod synchronisation\n\tdmesg\n\n# Test complet\ntest-all: test-irq test-procfs test-char test-sync\n\n.PHONY: all clean test-irq test-procfs test-char test-sync test-all<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>PARTIE 1 : FONDAMENTAUX 1.1 Architecture Linux : Espace noyau vs espace utilisateur Diff\u00e9rences cl\u00e9s : Aspect Espace utilisateur Espace noyau Acc\u00e8s m\u00e9moire M\u00e9moire virtuelle limit\u00e9e Acc\u00e8s complet \u00e0 toute [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","_uag_custom_page_level_css":"","footnotes":""},"class_list":["post-4994","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>module , allons dans le noyau - workboot<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"module , allons dans le noyau - workboot\" \/>\n<meta property=\"og:description\" content=\"PARTIE 1 : FONDAMENTAUX 1.1 Architecture Linux : Espace noyau vs espace utilisateur Diff\u00e9rences cl\u00e9s : Aspect Espace utilisateur Espace noyau Acc\u00e8s m\u00e9moire M\u00e9moire virtuelle limit\u00e9e Acc\u00e8s complet \u00e0 toute [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/\" \/>\n<meta property=\"og:site_name\" content=\"workboot\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-08T09:35:45+00:00\" \/>\n<meta name=\"twitter:label1\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data1\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/module-allons-dans-le-noyau\\\/\",\"url\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/module-allons-dans-le-noyau\\\/\",\"name\":\"module , allons dans le noyau - workboot\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/#website\"},\"datePublished\":\"2025-11-07T17:59:44+00:00\",\"dateModified\":\"2025-11-08T09:35:45+00:00\",\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/workboot.fr\\\/ciela\\\/module-allons-dans-le-noyau\\\/\"]}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/#website\",\"url\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/\",\"name\":\"workboot\",\"description\":\"Open Source, Open Minds \",\"publisher\":{\"@id\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/#organization\",\"name\":\"workboot\",\"url\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/wp-content\\\/uploads\\\/2025\\\/05\\\/logo_ciel-dorian-1.png\",\"contentUrl\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/wp-content\\\/uploads\\\/2025\\\/05\\\/logo_ciel-dorian-1.png\",\"width\":1024,\"height\":950,\"caption\":\"workboot\"},\"image\":{\"@id\":\"https:\\\/\\\/workboot.fr\\\/ciela\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"module , allons dans le noyau - workboot","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/","og_locale":"fr_FR","og_type":"article","og_title":"module , allons dans le noyau - workboot","og_description":"PARTIE 1 : FONDAMENTAUX 1.1 Architecture Linux : Espace noyau vs espace utilisateur Diff\u00e9rences cl\u00e9s : Aspect Espace utilisateur Espace noyau Acc\u00e8s m\u00e9moire M\u00e9moire virtuelle limit\u00e9e Acc\u00e8s complet \u00e0 toute [&hellip;]","og_url":"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/","og_site_name":"workboot","article_modified_time":"2025-11-08T09:35:45+00:00","twitter_misc":{"Dur\u00e9e de lecture estim\u00e9e":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/","url":"https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/","name":"module , allons dans le noyau - workboot","isPartOf":{"@id":"https:\/\/workboot.fr\/ciela\/#website"},"datePublished":"2025-11-07T17:59:44+00:00","dateModified":"2025-11-08T09:35:45+00:00","inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/workboot.fr\/ciela\/module-allons-dans-le-noyau\/"]}]},{"@type":"WebSite","@id":"https:\/\/workboot.fr\/ciela\/#website","url":"https:\/\/workboot.fr\/ciela\/","name":"workboot","description":"Open Source, Open Minds ","publisher":{"@id":"https:\/\/workboot.fr\/ciela\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/workboot.fr\/ciela\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"fr-FR"},{"@type":"Organization","@id":"https:\/\/workboot.fr\/ciela\/#organization","name":"workboot","url":"https:\/\/workboot.fr\/ciela\/","logo":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/workboot.fr\/ciela\/#\/schema\/logo\/image\/","url":"https:\/\/workboot.fr\/ciela\/wp-content\/uploads\/2025\/05\/logo_ciel-dorian-1.png","contentUrl":"https:\/\/workboot.fr\/ciela\/wp-content\/uploads\/2025\/05\/logo_ciel-dorian-1.png","width":1024,"height":950,"caption":"workboot"},"image":{"@id":"https:\/\/workboot.fr\/ciela\/#\/schema\/logo\/image\/"}}]}},"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":"admin","author_link":"https:\/\/workboot.fr\/ciela\/author\/admin\/"},"uagb_comment_info":0,"uagb_excerpt":"PARTIE 1 : FONDAMENTAUX 1.1 Architecture Linux : Espace noyau vs espace utilisateur Diff\u00e9rences cl\u00e9s : Aspect Espace utilisateur Espace noyau Acc\u00e8s m\u00e9moire M\u00e9moire virtuelle limit\u00e9e Acc\u00e8s complet \u00e0 toute [&hellip;]","_links":{"self":[{"href":"https:\/\/workboot.fr\/ciela\/wp-json\/wp\/v2\/pages\/4994","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/workboot.fr\/ciela\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/workboot.fr\/ciela\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/workboot.fr\/ciela\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/workboot.fr\/ciela\/wp-json\/wp\/v2\/comments?post=4994"}],"version-history":[{"count":7,"href":"https:\/\/workboot.fr\/ciela\/wp-json\/wp\/v2\/pages\/4994\/revisions"}],"predecessor-version":[{"id":5007,"href":"https:\/\/workboot.fr\/ciela\/wp-json\/wp\/v2\/pages\/4994\/revisions\/5007"}],"wp:attachment":[{"href":"https:\/\/workboot.fr\/ciela\/wp-json\/wp\/v2\/media?parent=4994"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}