8.总线设备驱动模型
總線設備驅動模型
總線:創建一條總線,跟我們前面的按鍵一樣,首先是描述總線結構,接著是注冊總線,注銷總線。總線設備,例如usb總線,上面會有很多類型的usb的驅動,例如鼠標、鍵盤.....等,當我們把之一的usb插上的時候,usb總線會把每個驅動遍歷一遍,找到相應的驅動程序執行。
接下來用bus.c創建一條總線。
?
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
int my_match(struct device *dv, struct device_driver *drv)
{
????return 0;
}
?
struct bus_type my_bus_type=
{
????.name="mybus",
????.match=my_match,
};
?
int mybus_init()
{
????int ret;
????ret=bus_register(&my_bus_type);
????return ret;
}
void mybus_exit()
{
????bus_unregister(&my_bus_type);
}
module_init(mybus_init);
module_exit(mybus_exit);
Make通過,拷貝到開發板運行:出現這錯誤:
錯誤的提示是未定義的bus總線相關的未定義符號。主要的要用是,我們的驅動程序沒有遵循GPL協議,加上MODULE_LICENSE("GPL");就可以了。
下面的mybus總線就是我們剛新建的:
接下來是總線驅動的實現:
上面的prode函數,當我們有設備加到總線的時候,當設備與總線的某個借口相匹配的時候,系統就會調用prode函數。對我的設備進行相應的初始化。
接下來在我們上面的總線掛接個驅動。
我們的driver.c的代碼:
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
extern struct bus_type my_bus_type;
?
int my_probe(struct device *dev)
{
????printk("<0> driver found the device it can handle!\n");
????return 0;
????//如果是實際應用的驅動,這里會做很多的硬件初始化操作。
}
?
?
struct device_driver my_driver=
{
????.name="my_dev",
????.bus = &my_bus_type,//驅動是屬于那一條總線的。來自外部的。所以總線的代碼
//要有EXPORT_SYMBOL符號導出標志
????.probe=my_probe,
};
?
int mydriver_init()
{
????int ret;
????ret=driver_register(&my_driver);
????return ret;
}
?
void mydriver_exit()
{
????driver_unregister(&my_driver);
}
module_init(mydriver_init);
module_exit(mydriver_exit);
由于驅動程序用到bus.c里的my_bus_type。所以在該結構的下面導出這個符號:EXPORT_SYMBOL(my_bus_type);//符號輸出。最后重新make一遍。把生成的bus.ko和driver.ko拷貝到開發板執行的結果如下:
?
[root@FORLINX6410]# insmod bus.ko
[root@FORLINX6410]# insmod driver.ko
[root@FORLINX6410]# cd /sys/bus/
[root@FORLINX6410]# ls
ac97 i2c mybus sdio usb
event_source mdio_bus platform serio usb-serial
hid mmc scsi spi
[root@FORLINX6410]# cd mybus/
[root@FORLINX6410]# ls
devices drivers_autoprobe uevent
drivers drivers_probe
[root@FORLINX6410]# cd drivers/
[root@FORLINX6410]# ls
my_dev
[root@FORLINX6410]#
上面的目錄/sys/bus/存的是系統總線的各類接口,我們看到了我們創建的mybus總線,進去,打開驅動drivers的目錄,里面有我們創建的驅動my_dev。這說明了我們在總線上成功地掛載了我們的驅動。
接下來在我們上面的總線掛接個設備。
Device.c的代碼:
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/init.h>
?
MODULE_LICENSE("GPL");
extern struct bus_type my_bus_type;
struct device my_dev=
{
????.init_name = "my_dev",//與驅動一致
????.bus = &my_bus_type,
};
int my_device_init()
{
????int ret;
????ret=device_register(&my_dev);
????return ret;
?
}
void my_device_exit()
{
????device_unregister(&my_dev);
}
?
?
module_init(my_device_init);
module_exit(my_device_exit);
?
對于我們的bus.c也需要做相應的修改。就是驅動程序和設備文件要對應上才能實現操作。把my_match函數修改如下:
int my_match(struct device *dev, struct device_driver *drv)
{
return !strncmp(dev->init_name,drv->name,strlen(drv->name));
//驅動程序和設備的匹配程序
}
最后就是在我們的Makefile里面添加device.o。后執行Make:
[root@FORFISH bus]# make
make -C /home/samba/linux-ok6410 M=/home/module/bus modules ARCH=arm CROSS_COMPILE=arm-linux-
make[1]: Entering directory `/home/samba/linux-ok6410'
CC [M] /home/module/bus/device.o
/home/module/bus/device.c:14: warning: function declaration isn't a prototype
/home/module/bus/device.c:21: warning: function declaration isn't a prototype
Building modules, stage 2.
MODPOST 3 modules
CC /home/module/bus/bus.mod.o
LD [M] /home/module/bus/bus.ko
CC /home/module/bus/device.mod.o
LD [M] /home/module/bus/device.ko
CC /home/module/bus/driver.mod.o
LD [M] /home/module/bus/driver.ko
make[1]: Leaving directory `/home/samba/linux-ok6410'
完成之后,拷貝bus.ko driver.ko.device.ko到開發板,測試。
?
[root@FORLINX6410]# insmod bus.ko
[root@FORLINX6410]# insmod driver.ko
[root@FORLINX6410]# insmod device.ko
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = cbcdc000
[0te=00000000
Internal error: Oop
Modules linked in: device(+) driver bus
CPU: 0 Tainted: G W (3.0.1 #439)
PC is at strncmp+0x14/0x68
LR is at my_match+0x2c/0x38 [bus]
pc : [<c01f9348>] lr : [<bf000064>] psr: 20000013
sp : cbd83e10 ip : cbd83e20 fp : cbd83e1c
r10: 00000000 r9 : bf008098 r8 : c07b121c
r7 : c0244e48 r6 : bf008090 r5 : bf008090 r4 : bf0040e4
r3 : 00000000 r2 : 00000006 r1 : bf0040e4 r0 : 00000000
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 00c5387d Table: 5bcdc008 DAC: 00000015
Process insmod (pid: 128, stack limit = 0xcbd82268)
Stack: (0xcbd83e10 to 0xcbd84000)
3e00: cbd83e34 cbd83e20 bf000064 c01f9340
3e20: bf0040ec bf008090 cbd83e4c cbd83e38 c0244e78 bf000044 00000000 cbd83e50
3e40: cbd83e74 cbd83e50 c024405c c0244e54 cbc67b88 cc716874 bf008090 bf008090
3e60: bf0080c4 00000000 cbd83e94 cbd83e78 c0244f44 c0244000 00000000 bf008090
3e80: c0706008 00000000 cbd83ea4 cbd83e98 c0243e20 c0244ec8 cbd83efc cbd83ea8
3ea0: c0242994 c0243e00 00000000 00000000 00000001 00000000 cbd83f0c cbd83ec8
3ec0: cbd83ee4 cbd83ed0 c01f48f8 d1a3548d bf008090 bf008090 00000000 bf008138
3ee0: 00000000 cbd82000 bf00801c 00000000 cbd83f14 cbd83f00 c0242c4c c024257c
3f00: c07463c0 00000000 cbd83f24 cbd83f18 bf008030 c0242c3c cbd83f7c cbd83f28
3f20: c00343c8 bf008028 cbd83f64 cbd83f38 c0073e24 00000000 00000000 00000000
3f40: 00000000 000088a4 000d5bf9 bf008138 00000000 000088a4 000d5bf9 bf008138
3f60: 00000000 c0034ce8 cbd82000 00000000 cbd83fa4 cbd83f80 c0085960 c0034398
3f80: c00e8738 c00e8610 402704a8 000dfcf8 00000000 00000080 00000000 cbd83fa8
3fa0: c0034b40 c00858e0 402704a8 000dfcf8 01327038 000088a4 000d5bf9 ffff5f01
3fc0: 402704a8 000dfcf8 00000000 00000080 00000069 00000001 becf2e84 becf2e88
3fe0: becf2e88 becf2b34 00021cfc 40331d74 60000010 01327038 5fffe821 5fffec21
[<c01f9348>] (strncmp+0x14/0x68) from [<bf000064>] (my_match+0x2c/0x38 [bus])
[<bf000064>] (my_match+0x2c/0x38 [bus]) from [<c0244e78>] (__device_attach+0x30)
[<c0244e78>] (__device_attach+0x30/0x48) from [<c024405c>] (bus_for_each_drv+0x)
[<c024405c>] (bus_for_each_drv+0x68/0x94) from [<c0244f44>] (device_attach+0x88)
[<c0244f44>] (device_attach+0x88/0xa0) from [<c0243e20>] (bus_probe_device+0x2c)
[<c0243e20>] (bus_probe_device+0x2c/0x4c) from [<c0242994>] (device_add+0x424/0)
[<c0242994>] (device_add+0x424/0x6c0) from [<c0242c4c>] (device_register+0x1c/0)
[<c0242c4c>] (device_register+0x1c/0x20) from [<bf008030>] (init_module+0x14/0x)
[<bf008030>] (init_module+0x14/0x1c [device]) from [<c00343c8>] (do_one_initcal)
[<c00343c8>] (do_one_initcall+0x3c/0x188) from [<c0085960>] (sys_init_module+0x)
[<c0085960>] (sys_init_module+0x8c/0x1a4) from [<c0034b40>] (ret_fast_syscall+0)
Code: e92dd800 e24cb004 e3520000 0a00000e (e5d03000)
---[ end trace da227214a82491b9 ]---
Segmentation fault
[root@FORLINX6410]#
上面出現了空指針:是在strncmp里出現了空指針,這個空指針是init_name;但是我們在我的device.c里已經.init_name="my_dev",為什么還是空指針呢?接下來看內核代碼:
首先是找device_register:
進入上面的device_add函數:會有下面的代碼:
上面的代碼就是把不為空的init_name,賦值給dev_set_name,然后自身的值變為NULL。所以,我們的程序出現空指針的原因。這個值被賦值到了成員kobj.name:
重新編譯安裝:
我們該了之后,看到了,我們的驅動使能了我們的設備,設備開始工作了。這樣我們就實現了該功能。
流程:當我們往總線加設備的時候,我的總線會把設備和總線上的驅動,一一進行匹配,當匹配成功的時候,就會去調用驅動的my_probe這個函數。看到了打印的出現。
?
上面是先有驅動,再有設備,工作的。
那么現有設備,再有驅動呢。同樣能實現:
轉載于:https://www.cnblogs.com/FORFISH/p/5188565.html
總結
以上是生活随笔為你收集整理的8.总线设备驱动模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编程福利:50本C语言电子书,你还怕没书
- 下一篇: 【Zigbee】进阶篇(2) Zigbe