一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Openwrt開(kāi)發(fā)指南 第16章 驅(qū)動(dòng)開(kāi)發(fā)之字符設(shè)備驅(qū)動(dòng)程序框架

嵌入式大雜燴 ? 來(lái)源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2023-06-30 09:01 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1 字符設(shè)備驅(qū)動(dòng)程序框架簡(jiǎn)介

我們?cè)趯W(xué)習(xí) C 語(yǔ)言的時(shí)候,知道每個(gè)應(yīng)用程序的入口函數(shù),即第一個(gè)被執(zhí)行的函數(shù)是 main函數(shù),那么,我們自己的驅(qū)動(dòng)程序,哪個(gè)函數(shù)是入口函數(shù)呢?

在寫(xiě)驅(qū)動(dòng)程序的時(shí)候,如果函數(shù)的名字可以任意取,常常為 xxxx_init(),當(dāng)實(shí)現(xiàn)好這個(gè) xxxx_init()函數(shù)以后,內(nèi)核其實(shí)并不知道這個(gè)就是我們驅(qū)動(dòng)的入口函數(shù),因此我們要想辦法告訴內(nèi)核,我們的入口函數(shù)是哪個(gè)?我們通過(guò) module_init()函數(shù)來(lái)告訴內(nèi)核,具體如下。

module_init(RT5350_drv_init);

通過(guò)上面的修飾以后, RT5350_drv_init()這個(gè)函數(shù)就變成了我們的驅(qū)動(dòng)程序的入口函數(shù)了。當(dāng)然,有入口函數(shù),自然還需要一個(gè)出口函數(shù),我們通過(guò) module_exit()函數(shù)來(lái)告訴內(nèi)核,具體如下。

module_exit(RT5350_drv_exit);

從上一章中,我們知道,應(yīng)用程序是通過(guò) open、read、write ...函數(shù)來(lái)和我們的驅(qū)動(dòng)程序進(jìn)行交互的,那么我們的驅(qū)動(dòng)程序是怎么給應(yīng)用程序提供這些接口的呢?我們?cè)趯?xiě)驅(qū)動(dòng)程序的時(shí)候,我們首先需要定義出一個(gè) file_operations 結(jié)構(gòu)體,該結(jié)構(gòu)體便是驅(qū)動(dòng)和應(yīng)用程序交互的接口。具體定義如下。

struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long,loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long,loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long,
unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *,
size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t,
unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
};

我們的驅(qū)動(dòng)程序要給應(yīng)用程序提供哪些接口,就只需要填充相應(yīng)的成員即可。比如我們想提供 open、read、write 這三個(gè)接口,就應(yīng)該如下定義。

static struct file_operations RT5350_drv_fops = {
.owner = THIS_MODULE, /*這是一個(gè)宏,推向編譯模塊時(shí)自動(dòng)創(chuàng)建的__this_module 變量 */
.open = RT5350_drv_open,
.read = RT5350_drv_read,
.write = RT5350_drv_write,
};

當(dāng) file_operations 結(jié)構(gòu)體定義、設(shè)置好以后,我們只需要通過(guò) register_chrdev()函數(shù)將該機(jī)構(gòu)圖注冊(cè)進(jìn)內(nèi)核即可。

2 字符設(shè)備驅(qū)動(dòng)程序框架實(shí)現(xiàn)

經(jīng)過(guò)前面部分的講解,相信大家一定對(duì)如何寫(xiě)一個(gè)自己的驅(qū)動(dòng)程序,有所感悟了。接下來(lái),給大家一個(gè)簡(jiǎn)單的驅(qū)動(dòng)程序的例子,可以用于作為框架模板,以后的驅(qū)動(dòng)都可以基于該驅(qū)動(dòng)進(jìn)行修改。

#include < linux/mm.h >
#include < linux/miscdevice.h >
#include < linux/slab.h >
#include < linux/vmalloc.h >
#include < linux/mman.h >
#include < linux/random.h >
#include < linux/init.h >
#include < linux/raw.h >
#include < linux/tty.h >
#include < linux/capability.h >
#include < linux/ptrace.h >
#include < linux/device.h >
#include < linux/highmem.h >
#include < linux/crash_dump.h >
#include < linux/backing-dev.h >
#include < linux/bootmem.h >
#include < linux/splice.h >
#include < linux/pfn.h >
#include < linux/export.h >
#include < linux/io.h >
#include < linux/aio.h >
#include < linux/kernel.h >
#include < linux/module.h >

#include < asm/uaccess.h >

#define DEVICE_NAME     "RT5350"  /* 加載模式后,執(zhí)行”cat /proc/devices”命令看到的設(shè)備名稱(chēng) */
#define RT5350_MAJOR       0       /* 主設(shè)備號(hào) */

static struct class *RT5350_drv_class;

static int RT5350_drv_open(struct inode *inode, struct file *file)
{
	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驅(qū)動(dòng)中添加打印,用法和應(yīng)用程序中的printf一樣

	return 0;
}

static ssize_t RT5350_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驅(qū)動(dòng)中添加打印,用法和應(yīng)用程序中的printf一樣

	return 0;
}

static ssize_t RT5350_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
{
	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驅(qū)動(dòng)中添加打印,用法和應(yīng)用程序中的printf一樣

	return 0;
}

/* 這個(gè)結(jié)構(gòu)是字符設(shè)備驅(qū)動(dòng)程序的核心
** 當(dāng)應(yīng)用程序操作設(shè)備文件時(shí)所調(diào)用的open、read、write等函數(shù),
** 最終會(huì)調(diào)用這個(gè)結(jié)構(gòu)中指定的對(duì)應(yīng)函數(shù)
**/
static struct file_operations RT5350_drv_fops = {
	.owner  	= THIS_MODULE,    /* 這是一個(gè)宏,推向編譯模塊時(shí)自動(dòng)創(chuàng)建的__this_module變量 */
	.open   	= RT5350_drv_open,     
	.read	= RT5350_drv_read,	   
	.write	= RT5350_drv_write,	   
};

int major;
/*
** 執(zhí)行insmod命令時(shí)就會(huì)調(diào)用這個(gè)函數(shù) 
*/
static int __init RT5350_drv_init(void)
{
	/* 注冊(cè)字符設(shè)備
	** 這步是寫(xiě)字符設(shè)備驅(qū)動(dòng)程序所必須的
	** 參數(shù)為主設(shè)備號(hào)、設(shè)備名字、file_operations結(jié)構(gòu);
	** 這樣,主設(shè)備號(hào)就和具體的file_operations結(jié)構(gòu)聯(lián)系起來(lái)了,
	** 操作主設(shè)備為RT5350_MAJOR的設(shè)備文件時(shí),就會(huì)調(diào)用RT5350_drv_fops中的相關(guān)成員函數(shù)
	** RT5350_MAJOR可以設(shè)為0,表示由內(nèi)核自動(dòng)分配主設(shè)備號(hào)
	*/
	major = register_chrdev(RT5350_MAJOR, DEVICE_NAME, &RT5350_drv_fops);
	if (major < 0)
	{
		printk(DEVICE_NAME " can't register major number
");
		return major;
	}

	/*
	** 以下兩行代碼用于創(chuàng)建設(shè)備節(jié)點(diǎn),是必須的。
	** 當(dāng)然,如果不寫(xiě)這兩行,那么就必須在linux系統(tǒng)命令行中通過(guò)mknod這個(gè)命令來(lái)創(chuàng)建設(shè)備節(jié)點(diǎn)
	*/
	/* 創(chuàng)建類(lèi) */
	RT5350_drv_class = class_create(THIS_MODULE, "RT5350");
	/* 類(lèi)下面創(chuàng)建設(shè)備節(jié)點(diǎn) */
	device_create(RT5350_drv_class, NULL, MKDEV(major, 0), NULL, "RT5350");		// /dev/RT5350

	/*
	** 打印一個(gè)調(diào)試信息
	*/
	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驅(qū)動(dòng)中添加打印,用法和應(yīng)用程序中的printf一樣

	return 0;
}

/*
 * 執(zhí)行rmmod命令時(shí)就會(huì)調(diào)用這個(gè)函數(shù) 
 */
static void __exit RT5350_drv_exit(void)
{
	unregister_chrdev(major, "RT5350");		// 與入口函數(shù)的register_chrdev函數(shù)配對(duì)使用
	device_destroy(RT5350_drv_class, MKDEV(major, 0));	// 與入口函數(shù)的device_create函數(shù)配對(duì)使用
	class_destroy(RT5350_drv_class);	// 與入口函數(shù)的class_create函數(shù)配對(duì)使用

	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驅(qū)動(dòng)中添加打印,用法和應(yīng)用程序中的printf一樣
}

/* 這兩行指定驅(qū)動(dòng)程序的初始化函數(shù)和卸載函數(shù) */
module_init(RT5350_drv_init);
module_exit(RT5350_drv_exit);

/* 描述驅(qū)動(dòng)程序的一些信息,不是必須的 */
MODULE_AUTHOR("BruceOu");
MODULE_VERSION("0.1.0");
MODULE_DESCRIPTION("RT5350 FIRST Driver");
MODULE_LICENSE("GPL");
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7630

    瀏覽量

    140971
  • 驅(qū)動(dòng)程序
    +關(guān)注

    關(guān)注

    19

    文章

    860

    瀏覽量

    48963
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4376

    瀏覽量

    64534
  • 驅(qū)動(dòng)開(kāi)發(fā)

    關(guān)注

    0

    文章

    133

    瀏覽量

    12279
  • OpenWrt
    +關(guān)注

    關(guān)注

    10

    文章

    131

    瀏覽量

    40141
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    【北京迅為】iTOP-RK3568開(kāi)發(fā)板OpenHarmony系統(tǒng)南向驅(qū)動(dòng)開(kāi)發(fā)-4 UART基礎(chǔ)知識(shí)

    【北京迅為】iTOP-RK3568開(kāi)發(fā)板OpenHarmony系統(tǒng)南向驅(qū)動(dòng)開(kāi)發(fā)-4 UART基礎(chǔ)知識(shí)
    的頭像 發(fā)表于 03-17 15:50 ?412次閱讀
    【北京迅為】iTOP-RK3568<b class='flag-5'>開(kāi)發(fā)</b>板OpenHarmony系統(tǒng)南向<b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>開(kāi)發(fā)</b>-<b class='flag-5'>第</b>4<b class='flag-5'>章</b> UART基礎(chǔ)知識(shí)

    嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-字符驅(qū)動(dòng)字符驅(qū)動(dòng)框架描述

    ):主設(shè)備號(hào)用于標(biāo)識(shí)字符設(shè)備驅(qū)動(dòng)程序所控制的設(shè)備類(lèi)型。驅(qū)動(dòng)程序在注冊(cè)時(shí)可以選擇由內(nèi)核分配主
    發(fā)表于 03-17 14:05

    飛凌嵌入式ElfBoard ELF 1板卡-字符驅(qū)動(dòng)字符驅(qū)動(dòng)框架描述

    ):主設(shè)備號(hào)用于標(biāo)識(shí)字符設(shè)備驅(qū)動(dòng)程序所控制的設(shè)備類(lèi)型。驅(qū)動(dòng)程序在注冊(cè)時(shí)可以選擇由內(nèi)核分配主
    發(fā)表于 03-14 09:45

    迅為RK3568開(kāi)發(fā)驅(qū)動(dòng)指南Linux中通用SPI設(shè)備驅(qū)動(dòng)

    迅為RK3568開(kāi)發(fā)驅(qū)動(dòng)指南Linux中通用SPI設(shè)備驅(qū)動(dòng)
    的頭像 發(fā)表于 01-23 11:02 ?2663次閱讀
    迅為RK3568<b class='flag-5'>開(kāi)發(fā)</b>板<b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>指南</b>Linux中通用SPI<b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動(dòng)</b>

    Linux驅(qū)動(dòng)程序程序指南

    電子發(fā)燒友網(wǎng)站提供《Linux驅(qū)動(dòng)程序程序指南.pdf》資料免費(fèi)下載
    發(fā)表于 11-22 15:53 ?0次下載
    Linux<b class='flag-5'>驅(qū)動(dòng)程序</b><b class='flag-5'>程序</b>員<b class='flag-5'>指南</b>

    pcie設(shè)備驅(qū)動(dòng)程序安裝步驟

    PCIe(Peripheral Component Interconnect Express)是一種高速串行計(jì)算機(jī)擴(kuò)展總線標(biāo)準(zhǔn),用于計(jì)算機(jī)內(nèi)部硬件組件之間的連接。安裝PCIe設(shè)備驅(qū)動(dòng)程序是確保硬件
    的頭像 發(fā)表于 11-13 10:32 ?3186次閱讀

    迅為iTOP-RK3568開(kāi)發(fā)驅(qū)動(dòng)開(kāi)發(fā)指南-第十八篇 PWM

    實(shí)驗(yàn) 11 創(chuàng)建設(shè)備節(jié)點(diǎn)實(shí)驗(yàn) 12 字符設(shè)備
    發(fā)表于 10-29 10:13

    文檔更新 | 迅為RK3568驅(qū)動(dòng)指南-第十七篇(串口)

    框架編寫(xiě) 172 使用C文件編寫(xiě)I2C client代碼 173 完善FT5X06設(shè)備節(jié)
    發(fā)表于 09-24 10:42

    LVGL開(kāi)發(fā)指南介紹

    電子發(fā)燒友網(wǎng)站提供《LVGL開(kāi)發(fā)指南介紹.pdf》資料免費(fèi)下載
    發(fā)表于 09-09 10:24 ?20次下載

    【北京迅為】《stm32mp157開(kāi)發(fā)板嵌入式linux開(kāi)發(fā)指南》第五 Ubuntu使用apt-get下載

    【北京迅為】《stm32mp157開(kāi)發(fā)板嵌入式linux開(kāi)發(fā)指南》第五 Ubuntu使用apt-get下載
    的頭像 發(fā)表于 09-03 16:26 ?1142次閱讀
    【北京迅為】《stm32mp157<b class='flag-5'>開(kāi)發(fā)</b>板嵌入式linux<b class='flag-5'>開(kāi)發(fā)指南</b>》第五<b class='flag-5'>章</b> Ubuntu使用apt-get下載

    Linux設(shè)備驅(qū)動(dòng)程序分類(lèi)有哪些

    Linux設(shè)備驅(qū)動(dòng)程序是操作系統(tǒng)與硬件設(shè)備之間的橋梁,負(fù)責(zé)實(shí)現(xiàn)硬件設(shè)備與操作系統(tǒng)之間的通信和控制。Linux設(shè)備
    的頭像 發(fā)表于 08-30 15:11 ?1176次閱讀

    linux驅(qū)動(dòng)程序如何加載進(jìn)內(nèi)核

    在Linux系統(tǒng)中,驅(qū)動(dòng)程序是內(nèi)核與硬件設(shè)備之間的橋梁。它們?cè)试S內(nèi)核與硬件設(shè)備進(jìn)行通信,從而實(shí)現(xiàn)對(duì)硬件設(shè)備的控制和管理。 驅(qū)動(dòng)程序的編寫(xiě)
    的頭像 發(fā)表于 08-30 15:02 ?1039次閱讀

    【好書(shū)推薦】RT-Thread設(shè)備驅(qū)動(dòng)開(kāi)發(fā)指南

    強(qiáng)烈,他們迫切地希望有一本可以指導(dǎo)他們?cè)赗T-Thread上開(kāi)發(fā)驅(qū)動(dòng)指南。為了解決開(kāi)發(fā)者的燃眉急,《RT-Thread
    的頭像 發(fā)表于 08-01 08:35 ?1231次閱讀
    【好書(shū)推薦】RT-Thread<b class='flag-5'>設(shè)備</b><b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>開(kāi)發(fā)指南</b>

    文檔更新 |迅為 RK3568開(kāi)發(fā)驅(qū)動(dòng)指南-第十五/十六篇

    i2cget 180.2.5 i2ctransfer 181 使用GPIO模擬I2C驅(qū)動(dòng) 181.1 設(shè)備樹(shù)的修改 181.2編寫(xiě)驅(qū)動(dòng)程序
    發(fā)表于 07-08 11:04

    3_UART 開(kāi)發(fā)基礎(chǔ)

    3_UART 開(kāi)發(fā)基礎(chǔ)
    的頭像 發(fā)表于 06-29 14:27 ?1167次閱讀
    <b class='flag-5'>第</b>3<b class='flag-5'>章</b>_UART <b class='flag-5'>開(kāi)發(fā)</b>基礎(chǔ)