Chinaunix首页 | 论坛 | 博客
  • 博客访问: 436106
  • 博文数量: 67
  • 博客积分: 2468
  • 博客等级: 上尉
  • 技术积分: 1050
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-05 01:21
文章分类

全部博文(67)

文章存档

2013年(1)

2012年(65)

2011年(1)

分类: 嵌入式

2012-01-05 10:30:41

一般来说,Linux设备驱动程序的大致流程如下:
(1)查看原理图,数据手册,了解设备操作方法、
(2)在内核中找到相近的驱动程序,以它为模板进行开发,有时候需从零开始。
(3)实现驱动程序初始化函数和卸载函数:module_init(),module_exit()。
(4)填充file_operations类型的数据结构(在内核include/linux/fs.h)中需要的操作。

  1. /*
  2.  * NOTE:
  3.  * all file operations except setlease can be called without
  4.  * the big kernel lock held in all filesystems.
  5.  */
  6. struct file_operations {
  7.     struct module *owner;
  8.     loff_t (*llseek) (struct file *, loff_t, int);
  9.     ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
  10.     ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
  11.     ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
  12.     ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
  13.     int (*readdir) (struct file *, void *, filldir_t);
  14.     unsigned int (*poll) (struct file *, struct poll_table_struct *);
  15.     long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
  16.     long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
  17.     int (*mmap) (struct file *, struct vm_area_struct *);
  18.     int (*open) (struct inode *, struct file *);
  19.     int (*flush) (struct file *, fl_owner_t id);
  20.     int (*release) (struct inode *, struct file *);
  21.     int (*fsync) (struct file *, int datasync);
  22.     int (*aio_fsync) (struct kiocb *, int datasync);
  23.     int (*fasync) (int, struct file *, int);
  24.     int (*lock) (struct file *, int, struct file_lock *);
  25.     ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
  26.     unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
  27.     int (*check_flags)(int);
  28.     int (*flock) (struct file *, int, struct file_lock *);
  29.     ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
  30.     ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
  31.     int (*setlease)(struct file *, long, struct file_lock **);
  32. };
(5)看是否需要实现中断服务。
(6)编译该驱动程序到内核中,或者用insmod命令加载。
(6)驱动程序的应用。

eg.
leds.c驱动程序,FROM此书

  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 <asm/irq.h>
  7. #include <asm/arch/regs-gpio.h>
  8. #include <asm/hardware.h>

  9. #define DEVICE_NAME "leds" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
  10. #define LED_MAJOR 231 /* 主设备号 */

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

  14. /* 用来指定LED所用的GPIO引脚 */
  15. static unsigned long led_table [] = {
  16.     S3C2410_GPB5,
  17.     S3C2410_GPB6,
  18.     S3C2410_GPB7,
  19.     S3C2410_GPB8,
  20. };

  21. /* 用来指定GPIO引脚的功能:输出 */
  22. static unsigned int led_cfg_table [] = {
  23.     S3C2410_GPB5_OUTP,
  24.     S3C2410_GPB6_OUTP,
  25.     S3C2410_GPB7_OUTP,
  26.     S3C2410_GPB8_OUTP,
  27. };

  28. /* 应用程序对设备文件/dev/leds执行open(...)时,
  29.  * 就会调用s3c24xx_leds_open函数
  30.  */
  31. static int s3c24xx_leds_open(struct inode *inode, struct file *file)
  32. {
  33.     int i;
  34.     
  35.     for (i = 0; i < 4; i++) {
  36.         // 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能
  37.         s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
  38.     }
  39.     return 0;
  40. }

  41. /* 应用程序对设备文件/dev/leds执行ioclt(...)时,
  42.  * 就会调用s3c24xx_leds_ioctl函数
  43.  */
  44. static int s3c24xx_leds_ioctl(
  45.     struct inode *inode,
  46.     struct file *file,
  47.     unsigned int cmd,
  48.     unsigned long arg)
  49. {
  50.     if (arg > 4) {
  51.         return -EINVAL;
  52.     }
  53.     
  54.     switch(cmd) {
  55.     case IOCTL_LED_ON:
  56.         // 设置指定引脚的输出电平为0
  57.         s3c2410_gpio_setpin(led_table[arg], 0);
  58.         return 0;

  59.     case IOCTL_LED_OFF:
  60.         // 设置指定引脚的输出电平为1
  61.         s3c2410_gpio_setpin(led_table[arg], 1);
  62.         return 0;

  63.     default:
  64.         return -EINVAL;
  65.     }
  66. }

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

  76. /*
  77.  * 执行“insmod s3c24xx_leds.ko”命令时就会调用这个函数
  78.  */
  79. static int __init s3c24xx_leds_init(void)
  80. {
  81.     int ret;

  82.     /* 注册字符设备驱动程序
  83.      * 参数为主设备号、设备名字、file_operations结构;
  84.      * 这样,主设备号就和具体的file_operations结构联系起来了,
  85.      * 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数
  86.      * LED_MAJOR可以设为0,表示由内核自动分配主设备号
  87.      */
  88.     ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);
  89.     if (ret < 0) {
  90.       printk(DEVICE_NAME " can't register major number\n");
  91.       return ret;
  92.     }
  93.     
  94.     printk(DEVICE_NAME " initialized\n");
  95.     return 0;
  96. }

  97. /*
  98.  * 执行”rmmod s3c24xx_leds.ko”命令时就会调用这个函数
  99.  */
  100. static void __exit s3c24xx_leds_exit(void)
  101. {
  102.     /* 卸载驱动程序 */
  103.     unregister_chrdev(LED_MAJOR, DEVICE_NAME);
  104. }

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

  108. /* 描述驱动程序的一些信息,不是必须的 */
  109. MODULE_AUTHOR(""); // 驱动程序的作者
  110. MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver"); // 一些描述信息
  111. MODULE_LICENSE("GPL"); // 遵循的协议
leds_test.c
  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.     
  31.     if (!strcmp(argv[2], "on")) {
  32.         ioctl(fd, IOCTL_LED_ON, led_no); // 点亮它
  33.     } else if (!strcmp(argv[2], "off")) {
  34.         ioctl(fd, IOCTL_LED_OFF, led_no); // 熄灭它
  35.     } else {
  36.         goto err;
  37.     }
  38.     
  39.     close(fd);
  40.     return 0;
  41.     
  42. err:
  43.     if (fd > 0)
  44.         close(fd);
  45.     usage(argv[0]);
  46.     return -1;
  47. }

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