166 | | Dans un premier temps vous allez vous contenter d'indiquer le nombre de LED et de bouton pour le module de test, mais il faudra être plus précis pour le vrai driver. |
167 | | * **Vous devez ajouter** dans module.c (faite d'équivalent pour les boutons): |
168 | | {{{#!c |
169 | | static int LED; |
170 | | module_param(LED, int, 0); |
171 | | MODULE_PARM_DESC(LED, "Nombre de led"); |
| 171 | Dans un premier temps vous allez vous contenter d'indiquer le numero du bouton pour le module de test. |
| 172 | * **Vous devez ajouter** dans module.c |
| 173 | {{{#!c |
| 174 | static int btn; |
| 175 | module_param(btn, int, 0); |
| 176 | MODULE_PARM_DESC(btn, "numéro du port du bouton"); |
182 | | $ sudo insmod ./module.ko LED=2 |
| 187 | $ sudo insmod ./module.ko btn=18 |
| 188 | }}} |
| 189 | * Pour les numéros de GPIO de LEDs, comme il peut y en avoir plusieurs, vous pouvez utiliser `module_param_array`. |
| 190 | {{{#!c |
| 191 | #define NBMAX_LED 32 |
| 192 | static int leds[NBMAX_LED]; |
| 193 | static int nbled; |
| 194 | module_param_array(nbled, int, &nbled, 0); |
| 195 | MODULE_PARM_DESC(LEDS, "tableau des numéros de port LED"); |
| 196 | |
| 197 | static int __init mon_module_init(void) |
| 198 | { |
| 199 | printk(KERN_DEBUG "Hello World !\n"); |
| 200 | for (int i=0; i < nbled; i++) |
| 201 | printk(KERN_DEBUG "LED %d = %d\n", i = leds[i]); |
| 202 | return 0; |
| 203 | } |
| 204 | }}} |
| 205 | * Le paramètre est défini au moment de l'insertion. |
| 206 | {{{#!sh |
| 207 | $ sudo insmod ./module.ko leds=4,17 |
365 | | == Étape 5 (optionnel) : Usage d'un timer dans le noyau pour faire clignoter la led == |
366 | | |
367 | | * Le code suivant fait clignoter la led GPIO04.\\ |
368 | | Vous pouvez adapter votre driver, pour demander un clignotement plutôt qu'un allumage. |
369 | | En effet, il existe un moyen de faire faire périodiquement une fonction au système grâce à une file d'attente temporelle. |
370 | | * Le code ci-dessous n'est pas un pilote, il fait clignoter la led dès son insertion dans le noyau, mais vous pouvez vous en inspirer pour votre pilote. |
371 | | * La gestion du timer passe par les fonction `setup_timer()` et `mod_timer()`, vous devez en chercher la documentation. |
372 | | {{{#!c |
373 | | #include <linux/module.h> |
374 | | #include <linux/init.h> |
375 | | #include <asm/io.h> |
376 | | #include <mach/platform.h> |
377 | | |
378 | | static const int LED0 = 2; |
379 | | |
380 | | //------------------------------------------------------------------------------ |
381 | | // GPIO ACCES |
382 | | //------------------------------------------------------------------------------ |
383 | | |
384 | | struct gpio_s |
385 | | { |
386 | | uint32_t gpfsel[7]; |
387 | | uint32_t gpset[3]; |
388 | | uint32_t gpclr[3]; |
389 | | uint32_t gplev[3]; |
390 | | uint32_t gpeds[3]; |
391 | | uint32_t gpren[3]; |
392 | | uint32_t gpfen[3]; |
393 | | uint32_t gphen[3]; |
394 | | uint32_t gplen[3]; |
395 | | uint32_t gparen[3]; |
396 | | uint32_t gpafen[3]; |
397 | | uint32_t gppud[1]; |
398 | | uint32_t gppudclk[3]; |
399 | | uint32_t test[1]; |
400 | | } |
401 | | *gpio_regs = (struct gpio_s *)__io_address(GPIO_BASE);; |
402 | | |
403 | | enum {FUN_INPUT, FUN_OUTPUT}; |
404 | | |
405 | | static void gpio_fsel(int pin, int fun) |
406 | | { |
407 | | uint32_t reg = pin / 10; |
408 | | uint32_t bit = (pin % 10) * 3; |
409 | | uint32_t mask = 0b111 << bit; |
410 | | gpio_regs->gpfsel[reg] = (gpio_regs->gpfsel[reg] & ~mask) | ((fun << bit) & mask); |
411 | | } |
412 | | |
413 | | static void gpio_write(int pin, bool val) |
414 | | { |
415 | | if (val) |
416 | | gpio_regs->gpset[pin / 32] = (1 << (pin % 32)); |
417 | | else |
418 | | gpio_regs->gpclr[pin / 32] = (1 << (pin % 32)); |
419 | | } |
420 | | |
421 | | //------------------------------------------------------------------------------ |
422 | | // TIMER PROGRAMMING |
423 | | //------------------------------------------------------------------------------ |
424 | | |
425 | | static struct timer_list led_blink_timer; |
426 | | static int led_blink_period = 1000; |
427 | | |
428 | | static void led_blink_handler(unsigned long unused) |
429 | | { |
430 | | static bool on = false; |
431 | | on = !on; |
432 | | gpio_write(LED0, on); |
433 | | mod_timer(&led_blink_timer, jiffies + msecs_to_jiffies(led_blink_period)); |
434 | | } |
435 | | |
436 | | //------------------------------------------------------------------------------ |
437 | | // MODULE INIT & EXIT |
438 | | //------------------------------------------------------------------------------ |
439 | | |
440 | | MODULE_LICENSE("GPL"); |
441 | | MODULE_AUTHOR("Franck from http://sysprogs.com/VisualKernel/tutorials/raspberry/leddriver/)"); |
442 | | MODULE_DESCRIPTION("leds on-off"); |
443 | | |
444 | | static int __init LedBlinkModule_init(void) |
445 | | { |
446 | | int result; |
447 | | |
448 | | gpio_fsel(LED0, FUN_OUTPUT); |
449 | | gpio_write(LED0, 1); |
450 | | setup_timer(&led_blink_timer, led_blink_handler, 0); |
451 | | result = mod_timer(&led_blink_timer, jiffies + msecs_to_jiffies(led_blink_period)); |
452 | | BUG_ON(result < 0); |
453 | | printk(KERN_DEBUG "blink loaded\n"); |
454 | | |
455 | | return 0; |
456 | | } |
457 | | |
458 | | static void __exit LedBlinkModule_exit(void) |
459 | | { |
460 | | gpio_fsel(LED0, FUN_INPUT); |
461 | | del_timer(&led_blink_timer); |
462 | | printk(KERN_DEBUG "blink removed\n"); |
463 | | } |
464 | | |
465 | | module_init(LedBlinkModule_init); |
466 | | module_exit(LedBlinkModule_exit); |
467 | | |
468 | | }}} |
469 | | |
470 | | }}} |
| 389 | }}} |