文章目录
  1. 1. 总线
  2. 2. 设备注册
    1. 2.1. 操作过程
    2. 2.2. 其他
  3. 3. 驱动注册
  4. 4. 实例:probe_hello_driver驱动
    1. 4.1. 无法卸载驱动

red alert 2 : boom

Linux中设备一般要先注册才能注册驱动。

现在越来越多热拔插设备,在热拔插设备中刚好相反,是先注册驱动,设备来了再注册设备。

总线

查看总线的命令#ls /sys/bus/

1
2
3
4
5
6
root@ubuntu:~# ls /sys/bus
ac97 gameport memory platform serio xen-backend
acpi hid mmc pnp spi
clocksource i2c node rapidio usb
cpu machinecheck pci scsi virtio
event_source mdio_bus pci_express sdio xen

platfor:虚拟总线

虚拟总线挂着各种设备

Linux总线设备驱动注册流程

在Linux系统中有总线的概念bus,设备(device)注册时候挂在虚拟总线上。一个设备(device)对应一个驱动(driver),先挂在设备再注册驱动。

设备通过结构体platform_device挂载,结构体数据写进链条 内。

驱动通过结构体platform_driver挂载

当注册驱动时,会把platform_device结构体中的id.name与platform_driver结构体中的id.name做个对比(通过platform_match()进行对比,该函数是Linux是系统调用),成功则调用probe。


  • 查看设备号的命令#cat /proc/devices

    • 设备都有主设备号和次设备号,否则255个设备号不够用

– 查看杂项设备号的命令#cat /proc/misc


设备注册

早先的Linux会使用单独的文件注册设备,现在大多引入虚拟平台,使用虚拟平台注册设备会容易很多。

注册设备使用的结构体platfor_device,

该结构体在/include/linux/platform_device.h中

该头文件也有注册设别也有卸载设备的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct platform_device {
const char * name; //设备名称
int id; //设备id,用于插入总线并且具有相同name的设备编号; 如果只有1个设备那么是-1
struct device dev; //结构体内中的内嵌device结构体
u32 num_resources; //使用设备资源的数量
struct resource * resource; //设备使用的资源组

const struct platform_device_id *id_entry;

/* MFD cell pointer */
struct mfd_cell *mfd_cell;

/* arch specific additions */
struct pdev_archdata archdata;
};

操作过程

操作过程
– 注册设备。将设备结构体放到平台文件中,会自动注册设备,不用去调
用注册设备的函数。

打开平台文件

1
root@ubuntu:~/iTop4412_Kernel_3.0# vi arch/arm/mach-exynos/mach-itop4412.c

仿照下面的LEDS_CTL来写HELLO_CTL

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifdef CONFIG_HELLO_CTL
struct platform_device s3c_device_hello_ctl = {
.name = "hello_that,ctl",
.id = -1,
};
#endif

#ifdef CONFIG_LEDS_CTL
struct platform_device s3c_device_leds_ctl = {
.name = "leds",
.id = -1,
};
#endif

以及编写宏定义   在文件开头

1
2
3
4
5
6
7
#ifdef CONFIG_HELLO_CTL
&s3c_device_hello_ctl,
#endif

#ifdef CONFIG_LEDS_CTL
&s3c_device_leds_ctl,
#endif

– 在Kconfig文件中添加编译HELLO设备的宏定义(跟前面的实例配置一样

root@ubuntu:~/iTop4412_Kernel_3.0# vi drivers/char/Kconfig添加宏定义

– 配置menuconfig中的HELLO宏定义,生成新的.config文件

在源码中执行make menuconfig
配置menuconfig中的HELLO宏定义

– 生成新的zImage

执行make

进入

1
root@ubuntu:~/iTop4412_Kernel_3.0/arch/arm/boot#

zImage内核拷贝出到windows下的platform-tools
将4412进入u-bboot
执行

1

在PC上执行
```platform-tools

1
fastboot.exe flash kernel zImage

然后PC长执行重启设备

1
fastboot reboot

在目标板上查询注册设备
在目标板上查询注册设备

其他

win10若显示android1.0黄色叹号,请手动更新设备选择兼容设备


驱动注册

  • 驱动注册头文件
    • 驱动注册使用结构体platform_driver,该结构体在头文件vim include/linux/platform_device.h
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    extern struct platform_device *platform_device_alloc(const char *name, int id);
    extern int platform_device_add_resources(struct platform_device *pdev,
    const struct resource *res,
    unsigned int num)
    ;

    extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);
    extern int platform_device_add(struct platform_device *pdev);
    extern void platform_device_del(struct platform_device *pdev);
    extern void platform_device_put(struct platform_device *pdev);

    struct platform_driver {
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
    const struct platform_device_id *id_table;
    };

    extern int platform_driver_register(struct platform_driver *);
    extern void platform_driver_unregister(struct platform_driver *);

驱动注册platform_driver_register,驱动卸载函数

platform_driver_unregister也在这个头文件中

这两个函数的参数都只有结构体platform_driver

注册结构体
• 驱动常见的几种状态,初始化,移除,休眠,复位
– 就像PC一样,有的驱动休眠之后无法使用,有的可以使用;有的系统唤
醒之后,驱动需要重新启动才能正常工作,也有直接就可以使用等等

  • probe函数
    – platform_match函数匹配之后,驱动调用的初始化函数
  • remove函数
    – 移除驱动函数
  • suspend函数
    – 悬挂(休眠)驱动函数

  • resume函数
    – 休眠后恢复驱动

  • device_driver数据结构的两个参数
    – name和注册的设备name要一致
    – owner一般赋值THIS_MODULE

实例:probe_hello_driver驱动

源码及相关.ko文件

将之前写的最小Linux驱动-4412:first_linux_driver添加驱动注册 修改

probe_hello_driver.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include<linux/init.h>
/*包含初始化宏定义的头文件,代码中的Module_init和module_exit在此文件中*/

#include<linux/module.h>
/*包含初始化加载模块的头文件,代码中的MODULE_LICENSE在此头文件中*/

#include <linux/platform_device.h>
/*驱动注册的头文件platform_device.h,包含
驱动注册使用的结构体 platform_driver
驱动注册:platform_driver_register
驱动卸载:platform_driver_unregister
*/

#define DRIVER_NAME "hello_ctl"

MODULE_LICENSE("Dual BSD/GPL"); //GPL:声明开源; Dual BSD:没有版本限制

MODULE_AUTHOR("takethat"); //声明作者信息


static int hello_probe(struct platform_device *pdv){
printk(KERN_EMERG "\tinitialized\n");
return 0;
}


static int hello_remove(struct platform_device *pdv){
return 0;
}

static void hello_shutdown(struct platform_device *pdv){
;
}

static int hello_suspend(struct platform_device *pdv){
return 0;
}

static int hello_resume(struct platform_device *pdv){
return 0;
}

struct platform_driver hello_driver = {
.probe = hello_probe,
.remove = hello_remove,
.shutdown = hello_shutdown,
.suspend = hello_suspend,
.resume = hello_resume,
.driver = {

.name = DRIVER_NAME,

.owner = THIS_MODULE,
}

};

static int hello_init(void)
{


int DriverState;
printk(KERN_EMERG "HELLO WORLD takethat,Enter that!\n"); //KERN_EMERG 表示紧急的信息,无论你是什么权限都可以打印出来.

DriverState = platform_driver_register(&hello_driver);

printk(KERN_EMERG "\tDriverState is %d\n",DriverState);

return 0;
}


static void hello_exit(void)

{

printk(KERN_EMERG "So,let's exit !Good bye~\n");

platform_driver_unregister(&hello_driver);

}

module_init(hello_init);

/* 初始化函数 */

module_exit(hello_exit);

/* 卸载函数 */

Makefile文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash

obj-m +=probe_hello_driver.o
# obj-m 意思是将后面跟的东东编译成内核模块。相对应还有:
# obj-y 编译进内核
# obj-n 不编译

KDIR := /root/iTop4412_Kernel_3.0

PWD ?= $(shell pwd)

all:
make -C $(KDIR) M=$(PWD) modules


clean:
rm -rf *.o

执行make生成.ko文件

再在4412目标板加载.ko模块

1
2
3
4
[root@iTOP-4412]# insmod probe_hello_driver.ko
[ 802.231839] HELLO WORLD takethat,Enter that!
[ 802.236454] DriverState is 0
[root@iTOP-4412]#

卸载模块

1
2
[root@iTOP-4412]# rmmod probe_hello_driver
[ 249.274737] So,let's exit !Good bye~

无法卸载驱动

报错:

1
2
[root@iTOP-4412]# rmmod probe_hello_driver
rmmod: can't change directory to '/lib/modules': No such file or directory

解决:

1
[root@iTOP-4412]# mkdir /lib/modules/3.0.15

文章目录
  1. 1. 总线
  2. 2. 设备注册
    1. 2.1. 操作过程
    2. 2.2. 其他
  3. 3. 驱动注册
  4. 4. 实例:probe_hello_driver驱动
    1. 4.1. 无法卸载驱动