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 }

 

原文地址:https://www.cnblogs.com/wenqiang/p/4803306.html