linux设备和驱动注册,Linux驱动第五篇-----驱动注册和生成设备节点
加載驅(qū)動(dòng)的指令是:insmod xx.ko
查看驅(qū)動(dòng)的指令是: lsmod
卸載驅(qū)動(dòng)的指令是:rmmod xx
在include/linux/platform_device.h這個(gè)文件中定義了平臺(tái)驅(qū)動(dòng)注冊和卸載文件函數(shù)
platform_driver_register 和 platform_driver_unregister 函數(shù)
這個(gè)兩個(gè)函數(shù)參數(shù)調(diào)用了結(jié)構(gòu)體platform_driver
該結(jié)構(gòu)中包含了一組操作函數(shù)和一個(gè) struct device_driver 的對像。在驅(qū)動(dòng)中首先要做的
就是定義 platform_driver 中的函數(shù),并創(chuàng)建這個(gè)結(jié)構(gòu)的一個(gè)對象實(shí)例, 然后在 init()函數(shù)中調(diào)用
platform_driver_register()向系統(tǒng)注冊驅(qū)動(dòng)。
函數(shù) int (*probe)(struct platform_device *);
主要是進(jìn)行設(shè)備的探測和初始化。例如想調(diào)用一個(gè) GPIO,那么首先需要探測這個(gè) GPIO 是
否被占用了,如果被占用了那么初始化失敗,驅(qū)動(dòng)注冊也就失敗了;如果沒有被占用,那么就
申明要占用它。該函數(shù)中一般還會(huì)添加生成設(shè)備節(jié)點(diǎn)的函數(shù),如果初始化成功,那么就會(huì)需要添加設(shè)備節(jié)點(diǎn)。
函數(shù) int (*remove)(struct platform_device *);
移除驅(qū)動(dòng),該函數(shù)中一般用于去掉設(shè)備節(jié)點(diǎn)或者釋放軟硬件資源
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
從字面上就很好理解了,關(guān)閉驅(qū)動(dòng),懸掛(休眠)驅(qū)動(dòng)以及恢復(fù)的時(shí)候該驅(qū)動(dòng)要做什么
接著的結(jié)構(gòu)體 struct device_driver driver;
主要包含兩個(gè)參數(shù),一個(gè)是 name 參數(shù),驅(qū)動(dòng)名稱(需要和設(shè)備驅(qū)動(dòng)結(jié)構(gòu)體中的 name 參
數(shù)一樣,這點(diǎn)很重要);一個(gè)是 owner,一般是 THIS_MODULE。
接下來編寫驅(qū)動(dòng)代碼:
#include #include /*驅(qū)動(dòng)注冊的頭文件,包含驅(qū)動(dòng)的結(jié)構(gòu)體和注冊和卸載的函數(shù)*/
#include #define DRIVER_NAME "hello_ctl" //這個(gè)和前面設(shè)備的注冊的hello結(jié)構(gòu)體里面的名字相同
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");
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, //和devices名稱相同
.owner = THIS_MODULE,
}
};
static int hello_init(void)
{
int DriverState;
printk(KERN_EMERG "HELLO WORLD enter!\n");
DriverState = platform_driver_register(&hello_driver); //然后在模塊入口調(diào)用platform_driver_register
printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
return 0;
}
static void hello_exit(void)
{
printk(KERN_EMERG "HELLO WORLD exit!\n");
platform_driver_unregister(&hello_driver);//在函數(shù)的出口調(diào)用platform_driver_unregister
}
module_init(hello_init);
module_exit(hello_exit);
如果設(shè)備和驅(qū)動(dòng)匹配成功就會(huì)進(jìn)入函數(shù) hello_probe 打印“initialized
接著需要編寫一下 Makefile 文件
#!/bin/bash
obj-m += probe_linux_module.o //文件名
#源碼目錄變量,這里用戶需要根據(jù)實(shí)際情況選擇路徑
KDIR := /home/birate/topeet/iTop4412_Kernel_3.0 #linux源碼目錄
#當(dāng)前目錄變量
PWD ?= $(shell pwd)
#make命名默認(rèn)尋找第一個(gè)目標(biāo)
#make -C就是指調(diào)用執(zhí)行的路徑
#$(KDIR)Linux源碼目錄
#$(PWD)當(dāng)前目錄變量
#modules要執(zhí)行的操作
all:
make -C $(KDIR) M=$(PWD) modules
#make clean執(zhí)行的操作是刪除后綴為o的文件
clean:
rm -rf *.o
使用make編譯,生成模塊文件probe_linux_module.ko
然后使用adb push probe_linux_module.ko /data 放到arm系統(tǒng)的/data目錄下
之后加載insmod probe_linux_module.ko
如果沒有錯(cuò)誤將會(huì)打印initialized等內(nèi)容
之后查看設(shè)備
卸載設(shè)備
后面我們生成雜項(xiàng)設(shè)備節(jié)點(diǎn)
雜項(xiàng)設(shè)備節(jié)點(diǎn)在include/linux/miscdevice.h這個(gè)文件中,我們也可以使用cat /proc/misc查看對應(yīng)的雜項(xiàng)設(shè)備
extern int misc_register(struct miscdevice * misc);
雜項(xiàng)設(shè)備注冊函數(shù);一般在 probe 中調(diào)用,參數(shù)是 miscdevice
extern int misc_deregister(struct miscdevice *misc);
雜項(xiàng)設(shè)備卸載函數(shù);一般是在 hello_remove 中用于卸載驅(qū)動(dòng)
結(jié)構(gòu)體 miscdevice 中參數(shù)很多,下面幾個(gè)是常用的。
int .minor;設(shè)備號(hào),賦值為 MISC_DYNAMIC_MINOR,這個(gè)宏定義可以查到為 10
const char *name;設(shè)備名稱
const struct file_operations *fops
file_operations 結(jié)構(gòu)體在頭文件“include/linux/fs.h”中,如下圖所示,使用命令“vim
include/linux/fs.h”打開頭文件。
查找file_operations
struct module *owner;一般是 THIS_MODULE。
int (*open) (struct inode *, struct file *);對應(yīng)上層的 open 函數(shù),打開文件。
int (*release) (struct inode *, struct file *);對應(yīng)上層的 close 函數(shù),打開文件操作之后一
般需要關(guān)閉。
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);讀函數(shù),上層應(yīng)用從底層讀取
函數(shù)。
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);寫函數(shù),上層應(yīng)用向底
層傳輸數(shù)據(jù)。
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);這個(gè)函數(shù)功能和寫
函數(shù)稍微有點(diǎn)重合,但是這個(gè)函數(shù)占用的內(nèi)存非常小,主要針對 IO 口的控制
#include #include /*驅(qū)動(dòng)注冊的頭文件,包含驅(qū)動(dòng)的結(jié)構(gòu)體和注冊和卸載的函數(shù)*/
#include /*注冊雜項(xiàng)設(shè)備頭文件*/
#include /*注冊設(shè)備節(jié)點(diǎn)的文件結(jié)構(gòu)體*/
#include #define DRIVER_NAME "hello_ctl"
#define DEVICE_NAME "hello_ctl123" //雜項(xiàng)節(jié)點(diǎn)名稱
MODULE_LICENSE("Dual BSD/GPL");
static long hello_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
printk("cmd is %d,arg is %d\n",cmd,arg);
return 0;
}
static int hello_release(struct inode *inode, struct file *file){
printk(KERN_EMERG "hello release\n");
return 0;
}
static int hello_open(struct inode *inode, struct file *file){
printk(KERN_EMERG "hello open\n");
return 0;
}
static struct file_operations hello_ops = { //定義file_operations 參數(shù)
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.unlocked_ioctl = hello_ioctl,
};
static struct miscdevice hello_dev = {
.minor = MISC_DYNAMIC_MINOR, //參數(shù) minor 為 MISC_DYNAMIC_MINOR,也就是 10
.name = DEVICE_NAME,//參數(shù) name 為 DEVICE_NAME,也就是 hello_ctl123
.fops = &hello_ops,//參數(shù) fops 為“hello_ops”
};
static int hello_probe(struct platform_device *pdv){
printk(KERN_EMERG "\tinitialized\n");
misc_register(&hello_dev); 向添加 hello_probe 中添加注冊雜項(xiàng)設(shè)備的函數(shù) misc_register,如下圖所示,
將 miscdevice 參數(shù)定義為 hello_dev
return 0;
}
static int hello_remove(struct platform_device *pdv){
printk(KERN_EMERG "\tremove\n");
misc_deregister(&hello_dev);
return 0;
}
static void hello_shutdown(struct platform_device *pdv){
;
}
static int hello_suspend(struct platform_device *pdv,pm_message_t pmt){
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 enter!\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 "HELLO WORLD exit!\n");
platform_driver_unregister(&hello_driver);
}
module_init(hello_init);
module_exit(hello_exit);
修改makefile函數(shù)
#!/bin/bash
obj-m += devicenode_linux_module.o
#源碼目錄變量,這里用戶需要根據(jù)實(shí)際情況選擇路徑
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0
#當(dāng)前目錄變量
PWD ?= $(shell pwd)
#make命名默認(rèn)尋找第一個(gè)目標(biāo)
#make -C就是指調(diào)用執(zhí)行的路徑
#$(PWD)當(dāng)前目錄變量
#modules要執(zhí)行的操作
all:
make -C $(KDIR) M=$(PWD) modules
#make clean執(zhí)行的操作是刪除后綴為o的文件
clean:
rm -rf *.o
生成.ko文件
傳到 /data目錄中
加載驅(qū)動(dòng) 在/dev查看設(shè)備節(jié)點(diǎn)
已經(jīng)生成了設(shè)備節(jié)點(diǎn)
卸載 完成
總結(jié)
以上是生活随笔為你收集整理的linux设备和驱动注册,Linux驱动第五篇-----驱动注册和生成设备节点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux线程间通信优点,进程间通信与线
- 下一篇: linux字符设备移动硬盘,Red Ha