Chinaunix首页 | 论坛 | 博客
  • 博客访问: 89209
  • 博文数量: 24
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 15
  • 用 户 组: 普通用户
  • 注册时间: 2016-03-28 14:12
文章分类

全部博文(24)

文章存档

2016年(24)

我的朋友

分类: LINUX

2016-03-28 14:26:52

本文以一个简单的LED驱动程序为例。

先说明一下LED与S3C2440芯片的连接方式:
LED1 <----> GPB5
LED2 <----> GPB6
LED3 <----> GPB7
LED4 <----> GPB8

操作LED的方式:
1.引脚功能设为输出
2.要点亮LED,令引脚输出0
3.要熄灭LED,令引脚输出1

该驱动程序采用字符驱动,设备节点在加载驱动后自动创建。驱动程序源码如下:
(drivers/char/s3c24xx_leds.c)

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <linux/delay.h>
  6. #include <linux/gpio.h>
  7. #include <asm/irq.h>
  8. #include <mach/regs-gpio.h>
  9. #include <linux/cdev.h>
  10. #include <linux/device.h>
  11. //#include <asm/hardware.h>

  12. #define DEVICE_NAME "leds" /* 加载模块后,执行”cat /proc/devices”命令看到的设备名称 */
  13. #define LED_MAJOR 231 /* 主设备号 */
  14. #define LED_MINOR 0 /* 次设备号 */
  15. #define LED_NUMBER 1 /* LED设备数 */

  16. struct cdev led_cdev; /* 字符设备 */
  17. dev_t dev = 0; /* led设备ID */
  18. struct class *led_class; /* 自动创建设备节点时,需要对应的class */

  19. /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
  20. #define IOCTL_LED_ON 0
  21. #define IOCTL_LED_OFF 1

  22. /* 用来指定LED所用的GPIO引脚 */
  23. static unsigned long led_table [] = {
  24.     S3C2410_GPB(5),
  25.     S3C2410_GPB(6),
  26.     S3C2410_GPB(7),
  27.     S3C2410_GPB(8),
  28. };

  29. /* 用来指定GPIO引脚的功能:输出 */
  30. static unsigned int led_cfg_table [] = {
  31.     S3C2410_GPIO_OUTPUT,
  32.     S3C2410_GPIO_OUTPUT,
  33.     S3C2410_GPIO_OUTPUT,
  34.     S3C2410_GPIO_OUTPUT,
  35. };

  36. /* 应用程序对设备文件/dev/leds执行open(...)时,
  37.  * 就会调用s3c24xx_leds_open函数
  38.  */
  39. static int s3c24xx_leds_open(struct inode *inode, struct file *file)
  40. {
  41.     int i;

  42.     for (i = 0; i < 4; i++) {
  43.         // 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能
  44.         s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
  45.     }
  46.     return 0;
  47. }

  48. /* 应用程序对设备文件/dev/leds执行ioclt(...)时,
  49.  * 就会调用s3c24xx_leds_ioctl函数
  50.  */
  51. static int s3c24xx_leds_ioctl(
  52.     struct inode *inode,
  53.     struct file *file,
  54.     unsigned int cmd,
  55.     unsigned long arg)
  56. {
  57.     if (arg > 4) {
  58.         return -EINVAL;
  59.     }

  60.     switch(cmd) {
  61.     case IOCTL_LED_ON:
  62.         // 设置指定引脚的输出电平为0
  63.         s3c2410_gpio_setpin(led_table[arg], 0);
  64.         return 0;

  65.     case IOCTL_LED_OFF:
  66.         // 设置指定引脚的输出电平为1
  67.         s3c2410_gpio_setpin(led_table[arg], 1);
  68.         return 0;
  69.     default:
  70.         return -EINVAL;
  71.     }
  72. }

  73. /* 这个结构是字符设备驱动程序的核心
  74.  * 当应用程序操作设备文件时所调用的open、read、write等函数,
  75.  * 最终会调用这个结构中指定的对应函数
  76.  */
  77. static struct file_operations s3c24xx_leds_fops = {
  78.     .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
  79.     .open = s3c24xx_leds_open,
  80.     .ioctl = s3c24xx_leds_ioctl,
  81. };

  82. /*
  83.  * 执行“insmod s3c24xx_leds.ko”命令时就会调用这个函数
  84.  */
  85. static int __init s3c24xx_leds_init(void)
  86. {
  87.     int ret;

  88.     //把主次设备号转换成dev_t类型
  89.     dev = MKDEV(LED_MAJOR, LED_MINOR);
  90.     //获取主设备号
  91.     ret = register_chrdev_region(dev, LED_NUMBER, DEVICE_NAME);
  92.     if (ret < 0) {
  93.       printk(KERN_WARNING "%s can't register major number %d\n", DEVICE_NAME, LED_MAJOR);
  94.       return ret;
  95.     }

  96.     //初始化led_cdev结构
  97.     cdev_init(&led_cdev, &s3c24xx_leds_fops);
  98.     led_cdev.owner = THIS_MODULE;
  99.     led_cdev.ops = &s3c24xx_leds_fops;

  100.     //在led_cdev结构设置好之后,通过下面方法告诉内核该结构的信息
  101.     ret = cdev_add(&led_cdev, dev, LED_NUMBER);
  102.     if (ret)
  103.         printk(KERN_NOTICE "Error %d adding led_cdev", ret);

  104.     /* create your own class under /sysfs */
  105.     led_class = class_create(THIS_MODULE, "led_class");
  106.     if(IS_ERR(led_class))
  107.     {
  108.         printk("Error: failed in creating led_class\n");
  109.         return -1;
  110.     }

  111.     /* register your own device in sysfs, and this will cause udev to create corresponding device node */
  112.     device_create(led_class, NULL, dev, NULL, DEVICE_NAME);

  113.     printk(KERN_INFO " Registered led driver success!\n");
  114.     return 0;
  115. }
  116. /*
  117.  * 执行”rmmod s3c24xx_leds.ko”命令时就会调用这个函数
  118.  */
  119. static void __exit s3c24xx_leds_exit(void)
  120. {
  121.     /* 卸载驱动程序 */
  122.     cdev_del(&led_cdev);
  123.     device_destroy(led_class, dev);
  124.     class_destroy(led_class);
  125.     unregister_chrdev_region(dev, LED_NUMBER);
  126.     printk(KERN_INFO "led driver cleaned up\n");
  127. }

  128. /* 这两行指定驱动程序的初始化函数和卸载函数 */
  129. module_init(s3c24xx_leds_init);
  130. module_exit(s3c24xx_leds_exit);

  131. /* 描述驱动程序的一些信息,不是必须的 */
  132. MODULE_AUTHOR("eric.hu"); // 驱动程序的作者
  133. MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver"); // 一些描述信息
  134. MODULE_LICENSE("GPL"); // 遵循的协议
测试程序代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/ioctl.h>

  5. #define IOCTL_LED_ON 0
  6. #define IOCTL_LED_OFF 1

  7. void usage(char *exename)
  8. {
  9.     printf("Usage:\n");
  10.     printf(" %s \n", exename);
  11.     printf(" led_no = 1, 2, 3 or 4\n");
  12. }

  13. int main(int argc, char **argv)
  14. {
  15.     unsigned int led_no;
  16.     int fd = -1;
  17.     
  18.     if (argc != 3)
  19.         goto err;
  20.     
  21.     fd = open("/dev/leds", 0); // 打开设备
  22.     if (fd < 0) {
  23.         printf("Can't open /dev/leds\n");
  24.         return -1;
  25.     }
  26.     
  27.     led_no = strtoul(argv[1], 0, 0) - 1; // 操作哪个LED?
  28.     if (led_no > 3)
  29.         goto err;

  30.     if (!strcmp(argv[2], "on")) {
  31.         ioctl(fd, IOCTL_LED_ON, led_no); // 点亮它
  32.     } else if (!strcmp(argv[2], "off")) {
  33.         ioctl(fd, IOCTL_LED_OFF, led_no); // 熄灭它
  34.     } else {
  35.         goto err;
  36.     }

  37.     close(fd);
  38.     return 0;

  39. err:
  40.     if (fd > 0)
  41.         close(fd);
  42.     usage(argv[0]);
  43.     return -1;
  44. }








阅读(1504) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~