日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux设备和驱动注册,Linux驱动第五篇-----驱动注册和生成设备节点

發(fā)布時(shí)間:2024/8/1 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux设备和驱动注册,Linux驱动第五篇-----驱动注册和生成设备节点 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

加載驅(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。