国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【linux驅(qū)動(dòng)開(kāi)發(fā)】在linux內(nèi)核中注冊(cè)一個(gè)雜項(xiàng)設(shè)備與字符設(shè)備以及內(nèi)核傳參的詳細(xì)教程

這篇具有很好參考價(jià)值的文章主要介紹了【linux驅(qū)動(dòng)開(kāi)發(fā)】在linux內(nèi)核中注冊(cè)一個(gè)雜項(xiàng)設(shè)備與字符設(shè)備以及內(nèi)核傳參的詳細(xì)教程。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

開(kāi)發(fā)環(huán)境: windows + ubuntu18.04 + 迅為rk3568開(kāi)發(fā)板

注冊(cè)雜項(xiàng)設(shè)備

相較于字符設(shè)備,雜項(xiàng)設(shè)備有以下兩個(gè)優(yōu)點(diǎn):

  • 節(jié)省主設(shè)備號(hào):雜項(xiàng)設(shè)備的主設(shè)備號(hào)固定為 10,在系統(tǒng)中注冊(cè)多個(gè) misc 設(shè)備驅(qū)動(dòng)時(shí),只需使用子設(shè)備號(hào)進(jìn)行區(qū)分即可。
  • 使用簡(jiǎn)單:相比如普通的字符設(shè)備驅(qū)動(dòng), misc驅(qū)動(dòng)只需要將基本信息通過(guò)結(jié)構(gòu)體傳遞給相應(yīng)處理函數(shù)即可。

在linxu系統(tǒng)中可使用 cat /proc/misc 命令查看系統(tǒng)中的雜項(xiàng)設(shè)備。注冊(cè)雜項(xiàng)設(shè)備的步驟:

  • 1.填充設(shè)備操作集結(jié)構(gòu)體struct file_operations

  • 2.填充雜項(xiàng)設(shè)備結(jié)構(gòu)體struct miscdevice;

  • 3.使用函數(shù)misc_register注冊(cè)雜項(xiàng)設(shè)備;

  • 4.使用函數(shù)misc_deregister卸載雜項(xiàng)設(shè)備;

上面三步可使用下面函數(shù)直觀用表達(dá),即:

static struct file_operations xxx_fops{
	.owner = THIS_MODULE, 
	.read = xxx_read, 
	....
};
struct miscdevice xxx_dev{
	.minor = MISC_DYNAMIC_MINOR, 
	.name = "xxx", 
	.fops = &xxx_fops
};
static int __init xxx_init(void) //驅(qū)動(dòng)入口函數(shù)
{
	int ret;
	printk(KERN_EMERG "xxx_init\r\n");
	ret = misc_register(&xxx_dev);//注冊(cè)雜項(xiàng)設(shè)備
	if(ret<0)
	{
		printk( "misc_register failed\r\n");
		return -1;
	}
	printk( "misc_register ok\r\n");
	return 0;
}
static void __exit xxx_exit(void) //驅(qū)動(dòng)出口函數(shù)
{
	printk(KERN_EMERG "xxx_exit\r\n");
	misc_deregister(&xxx_dev); //卸載雜項(xiàng)設(shè)備
}
module_init(xxx_init); //注冊(cè)入口函數(shù)
module_exit(xxx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxx");

具體實(shí)現(xiàn)注冊(cè)一個(gè)雜項(xiàng)設(shè)備的示例代碼如下:

#include <linux/kernel.h>
#include <linux/init.h>              //初始化頭文件
#include <linux/module.h>            //最基本的文件,支持動(dòng)態(tài)添加和卸載模塊。
#include <linux/miscdevice.h>        //注冊(cè)雜項(xiàng)設(shè)備頭文件
#include <linux/fs.h>                //注冊(cè)設(shè)備節(jié)點(diǎn)的文件結(jié)構(gòu)體
#include <linux/uaccess.h>

// 打開(kāi)雜項(xiàng)設(shè)備
int _open(struct inode *inode,struct file*file)
{
	printk(KERN_EMERG"hello misc");
	return 0;
}

// 關(guān)閉雜項(xiàng)設(shè)備
int close(struct inode * inode, struct file *file)
{
	printk(KERN_EMERG"close");
	return 0;
}

// 讀取雜項(xiàng)設(shè)備中的數(shù)據(jù)
ssize_t misc_read (struct file *file, char __user *buff, size_t size, loff_t *loff)
{
	char kbuff[32] = "kernel";
	if(copy_to_user(buff,kbuff,strlen(kbuff)) != 0) // 將內(nèi)核中的數(shù)據(jù)給應(yīng)用
	{
		printk("copy_to_user error\r\n");
		return -1;
	}	
	printk(KERN_EMERG"copy_to_user is successful\r\n");
	
	return size;
}

// 寫入數(shù)據(jù)到雜項(xiàng)設(shè)備中
ssize_t misc_write (struct file *file, const char __user *buff, size_t size, loff_t *loff)
{
	char kbuff[32] ;
	if(copy_from_user(kbuff,buff,size)!= 0) // 從應(yīng)用那兒獲取數(shù)據(jù)
	{
		printk("copy_from_user error\r\n");
		return -1;
	}	
	printk(KERN_EMERG"copy_from_user data:%s\r\n",kbuff);

	return size;
}

// 設(shè)備文件描述集  
struct file_operations misc_fops ={
	.owner = THIS_MODULE,
	.open = misc_open,
	.release = close,
	.read = misc_read,
	.write = misc_write
};

struct miscdevice misc_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "hello_misc", // 雜項(xiàng)設(shè)備名   注冊(cè)成功后會(huì)在 /dev目錄下顯示
	.fops = &misc_fops
};

// 驅(qū)動(dòng)的入口函數(shù)
static int __init misc_init(void)
{
	int ret = 0;
	ret = misc_register(&misc_dev);
	if(ret < 0)
		printk(KERN_EMERG"misc register is error\r\n.");
	else
		printk(KERN_EMERG"misc register is seccussful\r\n.");
	return 0;
}

//驅(qū)動(dòng)的出口函數(shù)
static void __exit misc_exit(void)
{
	misc_deregister(&misc_dev);
	printk(KERN_EMERG"baibai\r\n");
}

module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("zhouxianjie0716@qq.com");

編譯傳送到開(kāi)發(fā)板上后,先試用insmod +驅(qū)動(dòng)名.ko掛載驅(qū)動(dòng),其結(jié)果為:
【linux驅(qū)動(dòng)開(kāi)發(fā)】在linux內(nèi)核中注冊(cè)一個(gè)雜項(xiàng)設(shè)備與字符設(shè)備以及內(nèi)核傳參的詳細(xì)教程,LINUX,linux,驅(qū)動(dòng)開(kāi)發(fā),運(yùn)維

上述驅(qū)動(dòng)代碼的測(cè)試代碼如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
	char filePath[] = "/dev/hello_misc";
	// 打開(kāi)文件
	int fd = open(filePath,O_RDWR);
	if(fd < 0)
	{
		printf("opening is failed.\n");
		return -1;
	}
	else
		printf("opening is successful.\n");

	// 讀取
	char buff1[32],buff2[32] = "hello this is app";
	read(fd,buff1,sizeof(buff1));
	printf("buff1 is %s.\n",buff1);
	
	// 寫入
	write(fd,buff2,sizeof(buff2));	

	close(fd);
	return 0;
}

使用./+程序名運(yùn)行測(cè)試代碼后,得結(jié)果如下:
【linux驅(qū)動(dòng)開(kāi)發(fā)】在linux內(nèi)核中注冊(cè)一個(gè)雜項(xiàng)設(shè)備與字符設(shè)備以及內(nèi)核傳參的詳細(xì)教程,LINUX,linux,驅(qū)動(dòng)開(kāi)發(fā),運(yùn)維


驅(qū)動(dòng)模塊傳參

總所周知,應(yīng)用程序傳參是通過(guò)shell終端傳,只要將main函數(shù)按照下面格式書寫即可完成傳參操作

int main(int argc ,char *argv[])
{
	return 0;
}

相比之下,驅(qū)動(dòng)模塊傳遞參數(shù)需要借助其他函數(shù)完成傳參操作:

1. 傳遞單個(gè)參數(shù)給內(nèi)核

module_param(name, type, perm)

參數(shù)解釋:

  • name:參數(shù)名,既是外部參數(shù)名,又是內(nèi)部參數(shù)名。

  • type:參數(shù)的數(shù)據(jù)類型,可取int、charp等。

  • perm:訪問(wèn)權(quán)限。八進(jìn)制,如:0777。0表示該參數(shù)在文件系統(tǒng)中不可見(jiàn)。

注意:傳遞字符作為參數(shù)時(shí)數(shù)據(jù)類為charp,而不是char.

2.傳遞數(shù)組給內(nèi)核

module_param_array(name, type, nump, perm)
  • module_param_array(name,type,nump,perm)
  • name:數(shù)組參數(shù)名,既是外部參數(shù),又是內(nèi)部參數(shù)
  • type:參數(shù)的數(shù)據(jù)類型
  • nump:終端傳給數(shù)組的實(shí)際元素個(gè)數(shù)(指針變量)
  • perm:訪問(wèn)權(quán)限,0644。0表示該參數(shù)在文件系統(tǒng)中不可見(jiàn)

3.傳遞字符串給內(nèi)核

module_param_string(name, string, len, perm)
  • name:參數(shù)名,外部參數(shù)名
  • string:內(nèi)部參數(shù)名(內(nèi)部字符數(shù)組名)
  • len:數(shù)組長(zhǎng)度
  • perm:訪問(wèn)權(quán)限,0644。0表示該參數(shù)在文件系統(tǒng)中不可見(jiàn)

傳遞參給內(nèi)核的作用:

  • 1.設(shè)置驅(qū)動(dòng)的相關(guān)參數(shù),如:設(shè)備數(shù)量、設(shè)備緩沖區(qū)大小等等。
  • 2.可進(jìn)行安全校驗(yàn),放置驅(qū)動(dòng)被他人盜用。

說(shuō)明
參數(shù)傳遞的適用時(shí)機(jī)為 加載驅(qū)動(dòng)到內(nèi)核時(shí),命令形式為:insmod +驅(qū)動(dòng)名.ko +參數(shù)1名=參數(shù)值 參數(shù)2名=參數(shù)值 ……。例如下面示例中使用insmod file.ko date=12傳遞參數(shù):

#include <linux/module.h>
#include <linux/init.h>

// 保存參數(shù)
static int date;
static int date1;
static int data[5];
static int count;
static char str[32];
static char *strData;

// 傳遞單個(gè)參數(shù)
module_param(date,int,S_IRUGO|S_IWUSR); // 可讀可寫
module_param(date1,int,S_IRUGO); // 可讀可寫
module_param(strData,charp,S_IRUGO); // 可讀

// 傳遞多個(gè)參數(shù)
module_param_array(data,int,&count,S_IRUGO); // 可讀
module_param_string(str,str,sizeof(str),S_IRUGO); // 可讀

// 驅(qū)動(dòng)的入口函數(shù)
static int __init dev_init(void)
{
	int i=0;
	if(strcmp(str,"myTest")!=0)
	{
		printk("dev_init error\r\n");
		return -1;
	}
	printk("---------------------------------------\r\n");
	printk(KERN_EMERG"dev_init is successful!\r\n");
	for(i=0;i<count;++i)
		printk("data[%d] = %d \r\n",i,data[i]);
	printk("str:%s  strData:%s\r\n",str,strData);
	printk("date:%d  count:%d\r\n",date,count);
	
	data[1] = 111;
	date = 10;
	date1 = 111;
	
	return 0;
}

//驅(qū)動(dòng)的出口函數(shù)
static void __exit dev_exit(void)
{
	int i=0;
	for( i=0;i<count;++i)
		printk("data[%d] = %d \r\n",i,data[i]);
	printk("date:%d  count:%d\r\n",date,count);
	
	printk(KERN_EMERG"dev_exit is successful\r\n");
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("zhouxianjie0716@qq.com");

注冊(cè)字符設(shè)備

步驟一:驅(qū)動(dòng)初始化,需要申請(qǐng)?jiān)O(shè)備號(hào),初始化并且注冊(cè)cdev結(jié)構(gòu)體,初始化硬件;

可使用動(dòng)態(tài)申請(qǐng)或靜態(tài)申請(qǐng)?jiān)O(shè)備號(hào),其中動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào)一般在235-255,靜態(tài)申請(qǐng)則一般由用戶手動(dòng)輸入。

靜態(tài)申請(qǐng)的函數(shù)原型為:

 int register_chrdev_region(dev_t, unsigned, const char *);

參數(shù)含義:

  • from: 自定義的 dev_t 類型設(shè)備號(hào)。
  • count: 申請(qǐng)?jiān)O(shè)備的數(shù)量。
  • name: 申請(qǐng)的設(shè)備名稱。
    函數(shù)返回值:申請(qǐng)成功返回 0,申請(qǐng)失敗返回負(fù)數(shù)。

動(dòng)態(tài)申請(qǐng)的函數(shù)原型為:

 int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);

參數(shù)含義:

  • dev : 會(huì)將申請(qǐng)完成的設(shè)備號(hào)保存在 dev 變量中。
  • baseminor: 次設(shè)備號(hào)可申請(qǐng)的最小值。
  • count: 申請(qǐng)?jiān)O(shè)備的數(shù)量。
  • name: 申請(qǐng)的設(shè)備名稱。
    函數(shù)返回值:申請(qǐng)成功返回 0,申請(qǐng)失敗返回負(fù)

Linux 內(nèi)核中將字符設(shè)備抽象成一個(gè)具體的數(shù)據(jù)結(jié)構(gòu) (struct cdev), 我們可以理解為字符設(shè)備對(duì)象,cdev 記錄了字符設(shè)備號(hào)、內(nèi)核對(duì)象、文件操作 file_operations 結(jié)構(gòu)體(設(shè)備的打開(kāi)、讀寫、關(guān)閉等操作接口)等信息:

struct cdev {
	struct kobject kobj; //內(nèi)嵌的內(nèi)核對(duì)象.
	struct module *owner; //該字符設(shè)備所在的內(nèi)核模塊的對(duì)象指針. 
	const struct file_operations *ops; //該結(jié)構(gòu)描述了字符設(shè)備所能實(shí)現(xiàn)的方法,是極為關(guān)鍵的一個(gè)結(jié)
	構(gòu)體.struct list_head list; //用來(lái)將已經(jīng)向內(nèi)核注冊(cè)的所有字符設(shè)備形成鏈表. 
	dev_t dev; //字符設(shè)備的設(shè)備號(hào),由主設(shè)備號(hào)和次設(shè)備號(hào)構(gòu)成. 
	unsigned int count; //隸屬于同一主設(shè)備號(hào)的次設(shè)備號(hào)的個(gè)數(shù). 
};

初始化設(shè)備描述集cdev結(jié)構(gòu)體的函數(shù)原型為:

void cdev_init(struct cdev *, const struct file_operations *);

參數(shù)含義:

  • 參數(shù)1:表示是抽象設(shè)備結(jié)構(gòu)體;
  • 參數(shù)2:表示文件操作集;

注冊(cè)設(shè)備到內(nèi)驅(qū)使用下面函數(shù)

int cdev_add(struct cdev *, dev_t,  unsigned);

參數(shù)含義:

  • 參數(shù)1:為要添加的 struct cdev 類型的結(jié)構(gòu)體
  • 參數(shù)2:為申請(qǐng)的字符設(shè)備號(hào)
  • 參數(shù)3:為和該設(shè)備關(guān)聯(lián)的設(shè)備編號(hào)的數(shù)量
    若函數(shù)在內(nèi)核中添加成功返回 0,添加失敗返回負(fù)數(shù)。

步驟二:構(gòu)建設(shè)備文件操作描述集file_operations

也就是read、write、open、close等函數(shù)。

步驟三:生成并且添加設(shè)備節(jié)點(diǎn)

  • 手動(dòng)添加設(shè)備節(jié)點(diǎn):也就是在加載驅(qū)動(dòng)到內(nèi)核時(shí)添加,即mknod + 路徑/設(shè)備名 +設(shè)備類型 + 主設(shè)備號(hào) + 次設(shè)備號(hào)
  • 自動(dòng)添加設(shè)備節(jié)點(diǎn):初始化內(nèi)核時(shí),使用函數(shù)自動(dòng)添加。即先試用函數(shù)class_create創(chuàng)建一個(gè)類,在使用函數(shù)device_create創(chuàng)建并且添加設(shè)備節(jié)點(diǎn)。

class_create函數(shù)說(shuō)明:

#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \ __class_create(owner, name, &__key); \
})

函數(shù)作用:
用于動(dòng)態(tài)創(chuàng)建設(shè)備的邏輯類,并完成部分字段的初始化,然后將其添加進(jìn) Linux 內(nèi)核系統(tǒng)。

參數(shù)含義:

  • owner:指向函數(shù)即將創(chuàng)建的這個(gè) struct class 的模塊。一般為 THIS_MODULE。
  • name:代表即將創(chuàng)建的 struct class 變量的名字。
    返回值:struct class * 類型的類。

device_create函數(shù)說(shuō)明:


struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt,...);

函數(shù)作用:
用來(lái)在 class 類中下創(chuàng)建一個(gè)設(shè)備屬性文件,udev 會(huì)自動(dòng)識(shí)別從而進(jìn)行設(shè)備節(jié)點(diǎn)的創(chuàng)建。

參數(shù)含義:

  • cls:指定所要?jiǎng)?chuàng)建的設(shè)備所從屬的類。
  • parent:指定該設(shè)備的父設(shè)備,如果沒(méi)有就指定為 NULL。
  • devt:指定創(chuàng)建設(shè)備的設(shè)備號(hào)。
  • drvdata:被添加到該設(shè)備回調(diào)的數(shù)據(jù),沒(méi)有則指定為 NULL。
  • fmt:添加到系統(tǒng)的設(shè)備節(jié)點(diǎn)名稱。

返回值:struct device * 類型結(jié)構(gòu)體的設(shè)備

步驟四:注銷字符設(shè)備驅(qū)動(dòng)

  • 步驟一:使用函數(shù)unregister_chrdev_region釋放設(shè)備號(hào)
void unregister_chrdev_region(dev_t, unsigned)

該函數(shù)只有一個(gè)參數(shù),為要?jiǎng)h除設(shè)備的設(shè)備號(hào),并且函數(shù)無(wú)返回值。

  • 步驟二:使用函數(shù)cdev_del步驟二:刪除設(shè)備操作集卸載cdev
void cdev_del(struct cdev *);

該函數(shù)只有一個(gè)參數(shù),為要?jiǎng)h除的 struct cdev 類型的結(jié)構(gòu)體,并且函數(shù)無(wú)返回值。

  • 步驟三:使用函數(shù)device_destroy卸載設(shè)備
void device_destroy(struct class *cls, dev_t devt);

用來(lái)刪除 cls 類中的devt設(shè)備屬性文件,udev 會(huì)自動(dòng)識(shí)別從而進(jìn)行設(shè)備節(jié)點(diǎn)的刪除。

  • 步驟四:使用函數(shù)class_destroy刪除類class
 void class_destroy(struct class *cls);

該函數(shù)只有一個(gè)參數(shù),為要?jiǎng)h除的類,并且函數(shù)無(wú)返回值。

示例代碼

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>

#define DEVICE_NUMBER 1 // 設(shè)備數(shù)量
#define DEVICE_SNAME "schrdev" // 靜態(tài)申請(qǐng)時(shí)設(shè)備名
#define DEVICE_ANAME "achrdev" // 動(dòng)態(tài)申請(qǐng)時(shí)設(shè)備名
#define DEVICE_MINOR_NUM 0 // 次設(shè)備號(hào)起始地址
#define DEVICE_CLASS_NAME "myTestClass" // 類名
#define DEVICE_MYNAME "mytest"

// 打開(kāi)設(shè)備
int chrdev_open(struct inode*inode,struct file*file)
{
	printk("chrdev_open is opened\r\n");

	return 0;
}

// 保存設(shè)備號(hào) 其中前12位為主設(shè)備號(hào) 后20位為次設(shè)備號(hào)
static dev_t dev_num;

// 定義主設(shè)備號(hào) 次設(shè)備號(hào)
static int major_num,minor_num; 

// 設(shè)備信息描述集
struct cdev cdev;

// 類描述集
struct class *cls;

// 設(shè)備描述集
struct device*device;

// 傳遞單個(gè)參數(shù)
module_param(major_num,int,S_IRUGO); // 可讀
module_param(minor_num,int,S_IRUGO); // 可讀

// 文件操作集
struct file_operations chrdev_opr = {
	.owner = THIS_MODULE,
	.open = chrdev_open
};

// 驅(qū)動(dòng)的入口函數(shù)
static int __init dev_init(void)
{
	int ret;
	/* 步驟一:申請(qǐng)?jiān)O(shè)備號(hào) */
	// 有傳遞主設(shè)備號(hào)就靜態(tài)申請(qǐng)
	if(major_num)
	{	
		dev_num = MKDEV(major_num, minor_num);//將主設(shè)備號(hào) 次設(shè)備號(hào)合并成設(shè)備號(hào)
		//參數(shù)分別表示 設(shè)備號(hào) 設(shè)備數(shù)量 設(shè)備名稱
		ret = register_chrdev_region(dev_num, DEVICE_NUMBER, DEVICE_SNAME); 
		if(ret < 0)
		{
			printk("dev_init error\r\n");
			return -1;
		}
	}	
	// 否則就動(dòng)態(tài)申請(qǐng)
	else
	{
		// 參數(shù):設(shè)備號(hào) 次設(shè)備號(hào)起始地址 設(shè)備數(shù)量 設(shè)備名稱
		ret = alloc_chrdev_region(&dev_num , DEVICE_MINOR_NUM, DEVICE_NUMBER, DEVICE_ANAME);
		if(ret < 0)
		{
			printk("dev_init error\r\n");
			return -1;
		}
		// 獲取主設(shè)備號(hào) 次設(shè)備號(hào)
		major_num = MAJOR(dev_num);
		minor_num = MINOR(dev_num);
	}
	printk("---------------------------------------\r\n");
	printk("dev_num:%d major_num:%d minor_num:%d\r\n",dev_num,major_num,minor_num);

	/* 步驟二:初始化設(shè)備 */
	// 初始化cdev
	cdev.owner = THIS_MODULE;
	// 初始化設(shè)備  
	cdev_init(&cdev, &chrdev_opr);

	/* 步驟三:注冊(cè)設(shè)備到內(nèi)核 */
	//添加(注冊(cè))到內(nèi)核 參數(shù): 設(shè)備   設(shè)備號(hào)  設(shè)備數(shù)量
	cdev_add(&cdev, dev_num, DEVICE_NUMBER);

	/* 步驟四:先創(chuàng)建類再自動(dòng)創(chuàng)建添加設(shè)備名稱*/
	// 創(chuàng)建類 參數(shù)1: 類的歸屬   參數(shù)2: 類名
	cls = class_create(THIS_MODULE,DEVICE_CLASS_NAME);
	// 創(chuàng)建設(shè)備 參數(shù)1: 歸屬到類   參數(shù)2:設(shè)備的父設(shè)備 參數(shù)3:設(shè)備號(hào) 參數(shù)4:添加到設(shè)備的回調(diào)數(shù)據(jù) 參數(shù)5:設(shè)備名
	device = device_create(cls,NULL,dev_num,NULL,DEVICE_MYNAME);
	printk("auto add device name\r\n");
	return 0;
}

//驅(qū)動(dòng)的出口函數(shù)
static void __exit dev_exit(void)
{
	/* 步驟一:注銷設(shè)備號(hào) 參數(shù):設(shè)備號(hào)   設(shè)備數(shù)量 */ 
	unregister_chrdev_region(MKDEV(major_num, minor_num), DEVICE_NUMBER);
	/* 步驟二:刪除設(shè)備操作集 */
	cdev_del(&cdev);
	/* 步驟三:刪除設(shè)備*/
	device_destroy(cls,dev_num);
	/* 步驟四: 刪除類*/
	class_destroy( cls);
	
	printk(KERN_EMERG"dev_exit is successful\r\n");
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("zhouxianjie0716@qq.com");

使用加載驅(qū)動(dòng)到內(nèi)核insmod file.ko命令,得結(jié)果
【linux驅(qū)動(dòng)開(kāi)發(fā)】在linux內(nèi)核中注冊(cè)一個(gè)雜項(xiàng)設(shè)備與字符設(shè)備以及內(nèi)核傳參的詳細(xì)教程,LINUX,linux,驅(qū)動(dòng)開(kāi)發(fā),運(yùn)維

在測(cè)試驅(qū)動(dòng)前需要使用mknod /dev/mytest c 236 0創(chuàng)建設(shè)備文件,命令格式為:mknod + /路徑/設(shè)備名稱 +設(shè)備類型+主設(shè)備號(hào) + 次設(shè)備號(hào)。

然后就可寫一個(gè)應(yīng)用程序來(lái)測(cè)試我們的字符驅(qū)動(dòng)是否成功注冊(cè),測(cè)試源碼如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char* argv[])
{
	char name[] = "/dev/mytest";

	int fd = open(name,O_RDONLY); // 僅讀
	if(fd < 0)
	{
		printf("open is failed\n");
		return -1;
	}

	close(fd);

	return 0;
}

執(zhí)行測(cè)試程序后結(jié)果如下:
【linux驅(qū)動(dòng)開(kāi)發(fā)】在linux內(nèi)核中注冊(cè)一個(gè)雜項(xiàng)設(shè)備與字符設(shè)備以及內(nèi)核傳參的詳細(xì)教程,LINUX,linux,驅(qū)動(dòng)開(kāi)發(fā),運(yùn)維

注意:在運(yùn)行測(cè)試程序時(shí),一定要先創(chuàng)建驅(qū)動(dòng)文件,否則就會(huì)報(bào)段錯(cuò)誤,具體如下:
【linux驅(qū)動(dòng)開(kāi)發(fā)】在linux內(nèi)核中注冊(cè)一個(gè)雜項(xiàng)設(shè)備與字符設(shè)備以及內(nèi)核傳參的詳細(xì)教程,LINUX,linux,驅(qū)動(dòng)開(kāi)發(fā),運(yùn)維


雜項(xiàng)設(shè)備與字符設(shè)備的比較文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-810314.html

  • 雜項(xiàng)設(shè)備的主設(shè)備號(hào)固定為10,而字符設(shè)備的主設(shè)備號(hào)需要?jiǎng)?chuàng)建。
  • 雜項(xiàng)設(shè)備的創(chuàng)建相對(duì)簡(jiǎn)單,只需要填充設(shè)備操作集結(jié)構(gòu)體、雜項(xiàng)設(shè)備結(jié)構(gòu)體再注冊(cè)即可。而字符設(shè)備需要經(jīng)過(guò) 申請(qǐng)?jiān)O(shè)備號(hào)、初始化并且注冊(cè)cdev結(jié)構(gòu)體、初始化硬件、構(gòu)建設(shè)備文件操作描述集、生成并且添加設(shè)備節(jié)點(diǎn)。
  • 雜項(xiàng)設(shè)備與字符設(shè)備都需要構(gòu)建文件操作描述集。(應(yīng)用層調(diào)用驅(qū)動(dòng)的核心)

到了這里,關(guān)于【linux驅(qū)動(dòng)開(kāi)發(fā)】在linux內(nèi)核中注冊(cè)一個(gè)雜項(xiàng)設(shè)備與字符設(shè)備以及內(nèi)核傳參的詳細(xì)教程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Linux字符設(shè)備驅(qū)動(dòng)(設(shè)備文件,用戶空間與內(nèi)核空間進(jìn)行數(shù)據(jù)交互,ioctl接口)

    Linux字符設(shè)備驅(qū)動(dòng)(設(shè)備文件,用戶空間與內(nèi)核空間進(jìn)行數(shù)據(jù)交互,ioctl接口)

    在Linux系統(tǒng)中“一切皆文件”,上一篇講述了cdev結(jié)構(gòu)體就描述了一個(gè)字符設(shè)備驅(qū)動(dòng),主要包括設(shè)備號(hào)和操作函數(shù)集合。但是要怎么操作這個(gè)驅(qū)動(dòng)呢?例如,使用open()該打開(kāi)誰(shuí),read()該從哪讀取數(shù)據(jù)等等。所以就需要?jiǎng)?chuàng)建一個(gè)設(shè)備文件來(lái)代表設(shè)備驅(qū)動(dòng)。 應(yīng)用程序要操縱外部硬件

    2024年02月12日
    瀏覽(26)
  • 4、Linux驅(qū)動(dòng)開(kāi)發(fā):設(shè)備-設(shè)備號(hào)&設(shè)備號(hào)注冊(cè)

    4、Linux驅(qū)動(dòng)開(kāi)發(fā):設(shè)備-設(shè)備號(hào)&設(shè)備號(hào)注冊(cè)

    ??點(diǎn)擊這里查看所有博文 ??隨著自己工作的進(jìn)行,接觸到的技術(shù)棧也越來(lái)越多。給我一個(gè)很直觀的感受就是,某一項(xiàng)技術(shù)/經(jīng)驗(yàn)在剛開(kāi)始接觸的時(shí)候都記得很清楚。往往過(guò)了幾個(gè)月都會(huì)忘記的差不多了,只有經(jīng)常會(huì)用到的東西才有可能真正記下來(lái)。存在很多在特殊情況下有

    2024年02月15日
    瀏覽(44)
  • 【IMX6ULL驅(qū)動(dòng)開(kāi)發(fā)學(xué)習(xí)】02.hello驅(qū)動(dòng)程序之cdev注冊(cè)字符設(shè)備驅(qū)動(dòng)程序和設(shè)置次設(shè)備號(hào)

    【IMX6ULL驅(qū)動(dòng)開(kāi)發(fā)學(xué)習(xí)】02.hello驅(qū)動(dòng)程序之cdev注冊(cè)字符設(shè)備驅(qū)動(dòng)程序和設(shè)置次設(shè)備號(hào)

    目錄 一、register_chrdev 二、解決方法 2.1?alloc_chrdev_region函數(shù):注冊(cè)一系列字符設(shè)備編號(hào) 2.2?cdev_init函數(shù):初始化cdev結(jié)構(gòu)體? 2.3??cdev_add函數(shù):將字符設(shè)備添加到系統(tǒng)中 ?三、驅(qū)動(dòng)程序 【IMX6ULL驅(qū)動(dòng)開(kāi)發(fā)學(xué)習(xí)】01.編寫第一個(gè)hello驅(qū)動(dòng)+自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)(不涉及硬件操作)_阿龍還

    2024年02月14日
    瀏覽(24)
  • Linux -- 字符設(shè)備驅(qū)動(dòng)--LED的驅(qū)動(dòng)開(kāi)發(fā)(初級(jí)框架)

    Linux -- 字符設(shè)備驅(qū)動(dòng)--LED的驅(qū)動(dòng)開(kāi)發(fā)(初級(jí)框架)

    看原理圖確定引腳,確定引腳輸出什么電平才能點(diǎn)亮 / 熄滅 LED 看主芯片手冊(cè),確定寄存器操作方法:哪些寄存器?哪些位?地址是? 編寫驅(qū)動(dòng):先寫框架,再寫硬件操作的代碼 注意 :在芯片手冊(cè)中確定的寄存器地址被稱為 物理地址 ,在 Linux 內(nèi)核中無(wú)法直接使用。 需要使

    2024年04月28日
    瀏覽(27)
  • Linux下字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)以及流程介紹

    Linux下字符設(shè)備驅(qū)動(dòng)開(kāi)發(fā)以及流程介紹

    首先我們介紹一下什么是字符設(shè)備,然后講解一下字符設(shè)備開(kāi)發(fā)的具體的流程,分別詳細(xì)介紹每一個(gè)流程中涉及到的結(jié)構(gòu)體以及知識(shí)點(diǎn),最后我們編寫代碼實(shí)現(xiàn)字符設(shè)備的開(kāi)發(fā)以及測(cè)試。 Linux內(nèi)核設(shè)計(jì)哲學(xué)是把所有的東西都抽象成文件進(jìn)行訪問(wèn),這樣對(duì)設(shè)備的訪問(wèn)都是通過(guò)文

    2024年02月01日
    瀏覽(36)
  • 字符設(shè)備驅(qū)動(dòng)(內(nèi)核態(tài)用戶態(tài)內(nèi)存交互)

    字符設(shè)備驅(qū)動(dòng)(內(nèi)核態(tài)用戶態(tài)內(nèi)存交互)

    內(nèi)核驅(qū)動(dòng):運(yùn)行在內(nèi)核態(tài)的動(dòng)態(tài)模塊,遵循內(nèi)核模塊框架接口,更傾向于插件。 應(yīng)用程序:運(yùn)行在用戶態(tài)的進(jìn)程。 應(yīng)用程序與內(nèi)核驅(qū)動(dòng)交互通過(guò)既定接口,內(nèi)核態(tài)和用戶態(tài)訪問(wèn)依然遵循內(nèi)核既定接口。 系統(tǒng):openEuler-20.03-LTS-SP3 char_module.c Makefile 驅(qū)動(dòng)構(gòu)建 驅(qū)動(dòng)信息確認(rèn) 應(yīng)用程

    2024年02月11日
    瀏覽(25)
  • Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)學(xué)習(xí)筆記(等待隊(duì)列,鎖,字符驅(qū)動(dòng)程序,設(shè)備樹,i2C...)

    container_of函數(shù)可以通過(guò)結(jié)構(gòu)體的成員變量檢索出整個(gè)結(jié)構(gòu)體 函數(shù)原型: 內(nèi)核開(kāi)發(fā)者只實(shí)現(xiàn)了循環(huán)雙鏈表,因?yàn)檫@個(gè)結(jié)構(gòu)能夠?qū)崿F(xiàn)FIFO和LIFO,并且內(nèi)核開(kāi)發(fā)者要保持最少代碼。 為了支持鏈表,代碼中要添加的頭文件是linux/list.h。內(nèi)核中鏈表實(shí)現(xiàn)核心部分的數(shù)據(jù)結(jié)構(gòu) 是struct li

    2024年01月22日
    瀏覽(19)
  • 【嵌入式Linux內(nèi)核驅(qū)動(dòng)】04_Jetson nano GPIO應(yīng)用 | 驅(qū)動(dòng)開(kāi)發(fā) | 官方gpiolib、設(shè)備樹與chip_driver

    【嵌入式Linux內(nèi)核驅(qū)動(dòng)】04_Jetson nano GPIO應(yīng)用 | 驅(qū)動(dòng)開(kāi)發(fā) | 官方gpiolib、設(shè)備樹與chip_driver

    0.暴露給應(yīng)用層 應(yīng)用 解決調(diào)試目錄為空的問(wèn)題 調(diào)試信息 1.最簡(jiǎn)讀寫文件(在/SYS下) 設(shè)備樹 驗(yàn)證測(cè)試 編譯文件 驅(qū)動(dòng) of_get_named_gpio_flags //獲取設(shè)備樹節(jié)點(diǎn)的屬性 gpio_is_valid //判斷是否合法 devm_gpio_request //申請(qǐng)使用gpio,并調(diào)用設(shè)置pinctrl device_create_file //根據(jù)設(shè)備樹節(jié)點(diǎn)屬性,創(chuàng)建

    2024年02月07日
    瀏覽(53)
  • 字符設(shè)備實(shí)現(xiàn)內(nèi)部驅(qū)動(dòng)原理及分步注冊(cè)流程

    字符設(shè)備實(shí)現(xiàn)內(nèi)部驅(qū)動(dòng)原理及分步注冊(cè)流程

    ?應(yīng)用層:open函數(shù)回調(diào)到驅(qū)動(dòng)中open操作方法的路線: open()---sys_open()---struct inode結(jié)構(gòu)體---struct cdev結(jié)構(gòu)體---struct file_operations結(jié)構(gòu)體---mycdev_open() 1、分配對(duì)象空間 2、對(duì)象空間的初始化 3、對(duì)象的注冊(cè) 4、對(duì)象的注銷 流程模板(非詳細(xì)) open函數(shù)參數(shù)是路徑下的文件名字,根據(jù)

    2024年02月09日
    瀏覽(19)
  • 驅(qū)動(dòng)開(kāi)發(fā):內(nèi)核注冊(cè)表增刪改查

    驅(qū)動(dòng)開(kāi)發(fā):內(nèi)核注冊(cè)表增刪改查

    注冊(cè)表是Windows中的一個(gè)重要的數(shù)據(jù)庫(kù),用于存儲(chǔ)系統(tǒng)和應(yīng)用程序的設(shè)置信息,注冊(cè)表是一個(gè)巨大的樹形結(jié)構(gòu),無(wú)論在應(yīng)用層還是內(nèi)核層操作注冊(cè)表都有獨(dú)立的API函數(shù)可以使用,而在內(nèi)核中讀寫注冊(cè)表則需要使用內(nèi)核裝用API函數(shù),如下將依次介紹并封裝一些案例,實(shí)現(xiàn)對(duì)注冊(cè)表

    2024年02月09日
    瀏覽(17)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包