內(nèi)容企業(yè)推廣河南seo網(wǎng)站多少錢
【Linux】【驅(qū)動(dòng)】自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)
- 續(xù)
- 驅(qū)動(dòng)代碼
- 操作指令
- linux端
- 從機(jī)端
續(xù)
這里展示了如何自動(dòng)的方式去創(chuàng)建一個(gè)字符類的節(jié)點(diǎn)
下面就是需要調(diào)用到的程序
函數(shù)
void cdev_init(struct cdev *, const struct file_operations *);
第一個(gè)參數(shù) 要初始化的 cdev
第二個(gè)參數(shù) 文件操作集 cdev->ops = fops; //實(shí)際就是把文件操作集寫給 ops
功能 cdev_init()函數(shù)用于初始化 cdev 的成員,并建立 cdev 和 file_operations 之間的連接。
函數(shù)
int cdev_add(struct cdev *, dev_t, unsigned);
第一個(gè)參數(shù) cdev 的結(jié)構(gòu)體指針
第二個(gè)參數(shù) 設(shè)備號(hào)
第三個(gè)參數(shù) 次設(shè)備號(hào)的數(shù)量
功能 cdev_alloc()函數(shù)用于動(dòng)態(tài)申請(qǐng)一個(gè) cdev 內(nèi)存
void cdev_del(struct cdev *);
cdev 的結(jié)構(gòu)體指針
生成設(shè)備節(jié)點(diǎn)
字符設(shè)備注冊(cè)完以后不會(huì)自動(dòng)生成設(shè)備節(jié)點(diǎn)。我們需要使用 mknod 命令創(chuàng)建一個(gè)設(shè)備節(jié)點(diǎn)
格式:mknod 名稱 類型 主設(shè)備號(hào) 次設(shè)備號(hào)
mknod /dev/test c 247 0
驅(qū)動(dòng)代碼
代碼實(shí)現(xiàn)的流程
從 hello_init 函數(shù)開始看,
- 注冊(cè)設(shè)備號(hào),
- 初始化 cdev
- 向系統(tǒng)注冊(cè)設(shè)備
- 創(chuàng)建 class 類
- 在 class 類下創(chuàng)建設(shè)備
從hello_exit 來看
- 注銷設(shè)備號(hào)
- 刪除設(shè)備
- 注銷設(shè)備
- 刪除類
#include <linux/init.h>
#include <linux/module.h> //最基本的文件,支持動(dòng)態(tài)添加和卸載模塊。
#include <linux/fs.h> //包含了文件操作相關(guān) struct 的定義,例如大名鼎鼎的 struct file_operations
#include <linux/kdev_t.h>
#include <linux/cdev.h> //對(duì)字符設(shè)備結(jié)構(gòu) cdev 以及一系列的操作函數(shù)的定義。//包含了 cdev 結(jié)構(gòu)及相關(guān)函數(shù)的定義。
#include <linux/device.h> //包含了 device、class 等結(jié)構(gòu)的定義#define DEVICE_NUMBER 1 //定義次設(shè)備號(hào)的個(gè)數(shù)
#define DEVICE_SNAME "schrdev" //定義靜態(tài)注冊(cè)設(shè)備的名稱
#define DEVICE_ANAME "achrdev" //定義動(dòng)態(tài)注冊(cè)設(shè)備的名稱
#define DEVICE_MINOR_NUMBER 0 //定義次設(shè)備號(hào)的起始地址#define DEVICE_CLASS_NAME "chrdev_class" //宏定義類名
#define DEVICE_NODE_NAME "chrdev_test" //宏定義設(shè)備節(jié)點(diǎn)的名字static int major_num, minor_num; //定義主設(shè)備號(hào)和次設(shè)備號(hào)struct class *class; //定義類
struct device *device; /* 設(shè)備 */
struct cdev cdev;//定義一個(gè) cdev 結(jié)構(gòu)體module_param(major_num,int,S_IRUSR); //驅(qū)動(dòng)模塊傳入普通參數(shù) major_num
module_param(minor_num ,int,S_IRUSR);//驅(qū)動(dòng)模塊傳入普通參數(shù) minor_numdev_t dev_num;/**
* @description: 打開設(shè)備
* @param {structinode} *inode:傳遞給驅(qū)動(dòng)的 inode
* @param {structfile} *file:設(shè)備文件,file 結(jié)構(gòu)體有個(gè)叫做 private_data 的成員變量,
* 一般在 open 的時(shí)候?qū)?private_data 指向設(shè)備結(jié)構(gòu)體。
* @return: 0 成功;其他 失敗
*/
int chrdev_open(struct inode *inode, struct file *file)
{printk("chrdev_open\n");return 0;
}// 設(shè)備操作函數(shù)結(jié)構(gòu)體
struct file_operations chrdev_ops = {.owner = THIS_MODULE,.open = chrdev_open};/**
* @description: 驅(qū)動(dòng)入口函數(shù)
* @param {*}無
* @return {*} 0 成功;其他 失敗
*/
static int hello_init(void)
{int ret;//函數(shù)返回值if(major_num){/*靜態(tài)注冊(cè)設(shè)備號(hào)*/printk("major_num = %d\n",major_num);//打印傳入進(jìn)來的主設(shè)備號(hào)printk("minor_num = %d\n",minor_num);//打印傳入進(jìn)來的次設(shè)備號(hào)dev_num = MKDEV(major_num,minor_num);//MKDEV 將主設(shè)備號(hào)和次設(shè)備號(hào)合并為一個(gè)設(shè)備號(hào)ret = register_chrdev_region(dev_num, DEVICE_NUMBER,DEVICE_SNAME);//注冊(cè)設(shè)備號(hào)if(ret<0){printk("register_chrdev_region error\n");}//靜態(tài)注冊(cè)設(shè)備號(hào)成功,則打印。printk("register_chrdev_region ok\n");}else{/*動(dòng)態(tài)注冊(cè)設(shè)備號(hào)*/ret = alloc_chrdev_region(&dev_num,DEVICE_MINOR_NUMBER,1, DEVICE_ANAME);if(ret<0){printk("alloc_chrdev_region error\n");}//動(dòng)態(tài)注冊(cè)設(shè)備號(hào)成功,則打印printk("alloc_chrdev_region ok\n");major_num =MAJOR(dev_num); //將主設(shè)備號(hào)取出來minor_num = MINOR(dev_num);//將次設(shè)備號(hào)取出來printk("major_num = %d\n",major_num);//打印傳入進(jìn)來的主設(shè)備號(hào)printk("minor_num = %d\n",minor_num);//打印傳入進(jìn)來的次設(shè)備號(hào)}// 初始化 cdevcdev.owner = THIS_MODULE;//cdev_init 函數(shù)初始化 cdev 結(jié)構(gòu)體成員變量cdev_init(&cdev, &chrdev_ops);//完成字符設(shè)備注冊(cè)到內(nèi)核cdev_add(&cdev, dev_num, DEVICE_NUMBER);//創(chuàng)建類class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);// 在 class 類下創(chuàng)建設(shè)備device = device_create(class, NULL, dev_num, NULL, DEVICE_NODE_NAME);return 0;
}//drivers for exit
static void hello_exit(void)
{//注銷設(shè)備號(hào)unregister_chrdev_region(MKDEV(major_num, minor_num), DEVICE_NUMBER);//刪除設(shè)備cdev_del(&cdev);//注銷設(shè)備device_destroy(class, dev_num);//刪除類class_destroy(class);printk("gooodbye! \n");}module_init(hello_init);
module_exit(hello_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chris");
下面就是app的代碼
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc,char *argv[])
{int fd;char buf[64] = {0};fd = open("/dev/chrdev_test",O_RDWR); //打開設(shè)備節(jié)點(diǎn)if(fd < 0){perror("open error \n");return fd;}//read(fd,buf,sizeof(buf)); //從文件中讀取數(shù)據(jù)放入緩沖區(qū)中close(fd);return 0;
}
操作指令
linux端
arm-buildroot-linux-gnueabihf-gcc -o app app.c
cp app /home/book/nfs_rootfs/
從機(jī)端
驅(qū)動(dòng)卸載掉,再加載新編譯好的的驅(qū)動(dòng)
rmmod chrdev
insmod chrdev.ko
我們輸入以下命令查看/sys/class 下面是否生成類,
ls /sys/class/chrdev_class/
查看下是否生成了設(shè)備節(jié)點(diǎn)
ls /sys/class/
來驗(yàn)證生成的設(shè)備節(jié)點(diǎn)是否可以使用
./app