zoukankan      html  css  js  c++  java
  • linux设备驱动之字符设备驱动模型(2)

      在上一篇中我们已经了解了字符设备驱动的原理,也了解了应用层调用内核函数的机制,但是我们每次操作设备,都必须首先通过mknod命令创建一个设备文件名,比如说我们要打开u盘,硬盘等这些设备,难道我们还要自己创建,就如同刘老师常说的一句话,这也太山寨了吧,所以我们今天我们来点比较专业的,让函数帮我们自动创建;

      在Linux 下,设备和驱动通常都需要挂接在一种总线上,总线有PCI、USB、I2C、SPI 等等,总线是处理器和设备之间的通道,在设备模型中,所有的设备都通过总线相连,一总线来管理设备和驱动函数

      因此我们先了解一下sys下的目录

      block:用于管理块设备,系统中的每一个块设备会在该目录下对应一个子目录;

      bus:用于管理总线,没注册一条总线,在该目录下有一个对应的子目录,其中,每个总线子目录下会有两个子目录:devices和drivers。

      devices包含里系统中所有属于该总线的的设备。

      drivers包含里系统中所有属于该总线的的驱动。

      class:将系统中的设备按功能分类。

      devices:该目录提供了系统中设备拓扑结构图。

      dev:该目录已注册的设备节点的视图。

      kernel:内核中的相关参数。

      module:内核中的模块信息。

      fireware:内核中的固件信息。

      Fs:描述内核中的文件系统。

      下面的代码是我们在sys/class中创建一个名为dog的类,然后在创建一个设备(wangcai);

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 #include <linux/cdev.h>
     4 #include <linux/fs.h>
     5 #include <linux/device.h>
     6 #include <linux/err.h>
     7 
     8 MODULE_LICENSE("GPL");
     9 MODULE_AUTHOR("bunfly");
    10 
    11 struct class *dog;
    12 struct device *wangcai;
    13 
    14 int bunfly_init()
    15 {
    16     dog = class_create(THIS_MODULE, "dog");//创建一个dog类
    17     if(IS_ERR(dog)) {
    18         PTR_ERR(dog);
    19         return 1;
    20     }
    21     
    22     wangcai = device_create(dog, NULL, MKDEV(9, 0), NULL, "wangcai%d", 1);//创建一个名为旺财的设备
    23     if(IS_ERR(wangcai)) {
    24         PTR_ERR(wangcai);
    25         return 1;
    26     }
    27 
    28     return 0;
    29 }
    30 
    31 int bunfly_exit()
    32 {
    33     printk("this is bunfly_exit
    ");
    34 
    35     return 0;
    36 }
    37 
    38 module_init(bunfly_init);
    39 module_exit(bunfly_exit);
    40  

     

      在实际的工作中我们一般都不需要创建类,设备等,linux系统都为常见的设备分好了类,而设备厂商都已经提供了,我们做的就是来驱动这些设备;在sys/class类中我们经常用的就是misc(杂项类)

      杂项设备也是在嵌入式系统中用得比较多的一种设备驱动,其定义如下:

     1  struct device;  
     2   
     3 struct miscdevice  {  
     4         int minor;  //次设备号
     5         const char *name;  //设备名
     6         const struct file_operations *fops;//文件操作  
     7         struct list_head list;  //形成链表
     8         struct device *parent;  
     9         struct device *this_device;  
    10         const char *nodename;  
    11         mode_t mode;  
    12 };  
    13   
    14 extern int misc_register(struct miscdevice * misc);  //混杂设备注册
    15 extern int misc_deregister(struct miscdevice *misc);  //混杂设备注销
    16   
    17 #define MODULE_ALIAS_MISCDEV(minor)                               
    18         MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR)        
    19         "-" __stringify(minor))  
    20 #endif  

      下面代码是在misc下注册一个名为bunfly_led的设备;插入模块后,在/dev下生成一个名为bunfly_led的设备名

      

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 #include <linux/cdev.h>
     4 #include <linux/fs.h>
     5 #include <linux/device.h>
     6 #include <linux/err.h>
     7 #include <linux/miscdevice.h>
     8 
     9 MODULE_LICENSE("GPL");
    10 MODULE_AUTHOR("bunfly");
    11 
    12 struct file_operations fops;//方法
    13 struct miscdevice led;
    14 
    15 int bunfly_init()
    16 {
    17     led.name = "bunfly_led";//设备名
    18     led.fops = &fops;//关联方法
    19     misc_register(&led);//在杂项类中注册led
    20 
    21     return 0;
    22 }
    23 
    24 int bunfly_exit()
    25 {
    26     printk("this is bunfly_exit
    ");
    27     misc_deregister(&led);//注销
    28 
    29     return 0;
    30 }
    31 
    32 module_init(bunfly_init);
    33 module_exit(bunfly_exit);
    34  

     

      下面代码的功能是用ioctl()函数控制led灯,格式:./ioctl /dev/bunfly_led 0 (灯亮)  | 1(灯灭)

     

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <fcntl.h>
     4 
     5 //输入 ./ioctl /dev/bunly_led 1(灯灭) : 0(灯亮)
     6 int main(int argc, char *argv[])
     7 {
     8     if(argc != 3) {
     9         printf("using %s <devname> 1:0
    ", argv[0]);
    10         return 1;
    11     }
    12 
    13     int fd = 0;
    14     fd = open(argv[2], O_RDWR);
    15     if(fd < 0) {
    16         perror("open");
    17         return 1;
    18     }    
    19     
    20     //argv【2】为字符,需要atoi转换为数字
    21     ioctl(fd, atoi(argv[2]));
    22     close(fd);
    23     return 0;
    24 }

     

       内核中:

      

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 #include <linux/cdev.h>
     4 #include <linux/fs.h>
     5 #include <linux/device.h>
     6 #include <linux/err.h>
     7 #include <linux/miscdevice.h>
     8 #include <linux/fs.h>
     9 #include <linux/io.h>
    10 #include <linux/gpio.h>
    11 
    12 MODULE_LICENSE("GPL");
    13 MODULE_AUTHOR("bunfly");
    14 
    15 int bunfly_open(struct inode *n, struct file *fp);
    16 long bunfly_ioctl(struct file *fp, unsigned int num, unsigned long vlaue);
    17 void led_on();
    18 void led_off();
    19 
    20 struct file_operations fops;//方法
    21 struct miscdevice led;
    22 
    23 unsigned long gpio_virt;
    24 unsigned long *gpm4con, *gpm4dat;
    25 
    26 int bunfly_init()
    27 {
    28     fops.open = bunfly_open;//调用系统函数
    29     fops.unlocked_ioctl = bunfly_ioctl;
    30     
    31     gpio_virt = ioremap(0x11000000, SZ_4K);//led物理地址到虚拟地址的映射
    32      gpm4con = gpio_virt + 0x02e0;
    33      gpm4dat = gpio_virt + 0x02e4;
    34 
    35     led.name = "bunfly_led";
    36     led.fops = &fops;
    37     misc_register(&led);//注册杂项类设备led
    38 
    39     return 0;
    40 }
    41 
    42 int bunfly_exit()
    43 {
    44     printk("this is bunfly_exit
    ");
    45     misc_deregister(&led);//注销设备
    46 
    47     return 0;
    48 }
    49 
    50 module_init(bunfly_init);
    51 module_exit(bunfly_exit);
    52  
    53 int bunfly_open(struct inode *n, struct file *fp)
    54 {
    55     printk("this is bunfly_open
    ");
    56     return 0;
    57 }
    58 
    59 long bunfly_ioctl(struct file *fp, unsigned int num, unsigned long vlaue)
    60 {
    61     if(num == 0) {
    62         led_on();
    63     }
    64     else {
    65         if(num == 1) {
    66             led_off();
    67         }
    68         else {
    69             printk("unkonw command %d
    ", num);
    70         }
    71     }
    72     
    73     return 0;
    74 }
    75 
    76 void led_on()
    77 {
    78     *gpm4con &= ~0xffff;
    79     *gpm4con |= 0x1111;
    80     *gpm4dat = 0x0;
    81 }
    82 
    83 void led_off()
    84 {
    85     *gpm4con &= ~0xffff;
    86     *gpm4con |= 0x1111;
    87     *gpm4dat = 0xf;
    88 
    89 }

     

  • 相关阅读:
    ognl的应用1
    未命名
    flash钟表的实现
    文本显示输入字数
    HttpServlet session的用法: (2)
    $.fx与$.fn.fx 区别
    javascript 事件冒泡 和 冒泡事件阻止
    (function($){...})(jQuery) 含义
    选择城市插件 jQuery
    offset().left 用法
  • 原文地址:https://www.cnblogs.com/wenqiang/p/4803306.html
Copyright © 2011-2022 走看看