註冊字符設備號
chrdev.c
/*
* @Author:topeet
* @Description:字符設備自動創建設備節點步驟一創建類,創建設備
*/
#include <linux/init.h> //初始化頭文件
#include <linux/module.h> //最基本的文件,支持動態添加和卸載模塊。
#include <linux/fs.h> //包含了文件操作相關struct的定義,例如大名鼎鼎的struct file_operations
#include <linux/kdev_t.h>
#include <linux/cdev.h> //對字符設備結構cdev以及一系列的操作函數的定義。//包含了cdev 結構及相關函數的定義。
#define DEVICE_NUMBER 1 //定義次設備號的個數
#define DEVICE_SNAME "schrdev" //定義靜態註冊設備的名稱
#define DEVICE_ANAME "achrdev" //定義動態註冊設備的名稱
#define DEVICE_MINOR_NUMBER 0 //定義次設備號的起始地址
#include <linux/device.h> //包含了device、class 等結構的定義
#define DEVICE_CLASS_NAME "chrdev_class"
#define DEVICE_NODE_NAME "chrdev_test" //宏定義設備節點的名字
static int major_num, minor_num; //定義主設備號和次設備號
struct class *class; /* 類 */
struct device *device; /* 設備 */
struct cdev cdev; //定義一個cdev結構體
module_param(major_num, int, S_IRUSR); //驅動模塊傳入普通參數major_num
module_param(minor_num, int, S_IRUSR); //驅動模塊傳入普通參數minor_num
dev_t dev_num; /* 設備號 */
/**
* @description: 打開設備
* @param {structinode} *inode:傳遞給驅動的 inode
* @param {structfile} *file:設備文件,file 結構體有個叫做 private_data 的成員變量,
* 一般在 open 的時候將 private_data 指向設備結構體。
* @return: 0 成功;其他 失敗
*/
int chrdev_open(struct inode *inode, struct file *file)
{
printk("chrdev_open\n");
return 0;
}
// 設備操作函數結構體
struct file_operations chrdev_ops = {
.owner = THIS_MODULE,
.open = chrdev_open};
/**
* @description: 驅動入口函數
* @param {*}無
* @return {*} 0 成功;其他 失敗
*/
static int hello_init(void)
{
int ret; //函數返回值
if (major_num)
{
/*靜態註冊設備號*/
printk("major_num = %d\n", major_num); //打印傳入進來的主設備號
printk("minor_num = %d\n", minor_num); //打印傳入進來的次設備號
dev_num = MKDEV(major_num, minor_num); //MKDEV將主設備號和次設備號合併為一個設備號
ret = register_chrdev_region(dev_num, DEVICE_NUMBER, DEVICE_SNAME); //註冊設備號
if (ret < 0)
{
printk("register_chrdev_region error\n");
}
printk("register_chrdev_region ok\n"); //靜態註冊設備號成功
}
else
{
/*動態註冊設備號*/
ret = alloc_chrdev_region(&dev_num, DEVICE_MINOR_NUMBER, 1, DEVICE_ANAME);
if (ret < 0)
{
printk("alloc_chrdev_region error\n");
}
printk("alloc_chrdev_region ok\n"); //動態註冊設備號成功
major_num = MAJOR(dev_num); //將主設備號取出來
minor_num = MINOR(dev_num); //將次設備號取出來
printk("major_num = %d\n", major_num); //打印傳入進來的主設備號
printk("minor_num = %d\n", minor_num); //打印傳入進來的次設備號
}
// 初始化 cdev
cdev.owner = THIS_MODULE;
cdev_init(&cdev, &chrdev_ops);
// 向系統註冊設備
cdev_add(&cdev, dev_num, DEVICE_NUMBER);
// 創建 class 類
class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
// 在 class 類下創建設備
device = device_create(class, NULL, dev_num, NULL, DEVICE_NODE_NAME);
return 0;
}
/**
* @description: 驅動出口函數
* @param {*}無
* @return {*}無
*/
static void hello_exit(void)
{
//註銷設備號
unregister_chrdev_region(MKDEV(major_num, minor_num), DEVICE_NUMBER);
//刪除設備
cdev_del(&cdev);
//註銷設備
device_destroy(class, dev_num);
//刪除類
class_destroy(class);
printk("gooodbye! \n");
}
// 將上面兩個函數指定為驅動的入口和出口函數
module_init(hello_init);
module_exit(hello_exit);
// LICENSE 和作者信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");
Makefile
obj-m += chrdev.o #先寫生成的中間文件的名字是什麼,-m的意思是把我們的驅動編譯成模塊
KDIR:=/home/topeet/driver/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga/
PWD?=$(shell pwd) #獲取當前目錄的變量
all:
make -C $(KDIR) M=$(PWD) modules #make會進入內核源碼的路徑,然後把當前路徑下的代碼編譯成模塊
應用
#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);
if(fd < 0)
{
perror("open error \n");
return fd;
}
read(fd,buf,sizeof(buf));
close(fd);
return 0;
}
本文章為轉載內容,我們尊重原作者對文章享有的著作權。如有內容錯誤或侵權問題,歡迎原作者聯繫我們進行內容更正或刪除文章。