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