
Linux中设备一般要先注册才能注册驱动。
现在越来越多热拔插设备,在热拔插设备中刚好相反,是先注册驱动,设备来了再注册设备。
总线
查看总线的命令#ls /sys/bus/
1 2 3 4 5 6
| root@ubuntu:~ 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系统中有总线的概念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; struct device dev; u32 num_resources; struct resource * resource;
const struct platform_device_id *id_entry;
struct mfd_cell *mfd_cell;
struct pdev_archdata archdata; };
|
操作过程
操作过程
– 注册设备。将设备结构体放到平台文件中,会自动注册设备,不用去调
用注册设备的函数。
打开平台文件
1
| root@ubuntu:~/iTop4412_Kernel_3.0
|
仿照下面的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

– 生成新的zImage
执行make
进入
1
| root@ubuntu:~/iTop4412_Kernel_3.0/arch/arm/boot
|
将zImage
内核拷贝出到windows下的platform-tools
将4412进入u-bboot
执行
1 2 3
| 在PC上执行 ```platform-tools```
|
fastboot.exe flash kernel zImage
fastboot reboot
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
|
在目标板上查询注册设备 ; 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_hello_driver驱动
[源码及相关.ko文件][]
[源码及相关.ko文件]: https://github.com/vivatakethat/Embedded-System
将之前写的最小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 87
| #include<linux/init.h>
#include<linux/module.h>
#include <linux/platform_device.h>
#define DRIVER_NAME "hello_ctl"
MODULE_LICENSE("Dual BSD/GPL");
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");
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
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] [ 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: can't change directory to '/lib/modules': No such file or directory
|
解决:
1
| [root@iTOP-4412]# mkdir /lib/modules/3.0.15
|