1. 程式人生 > 其它 >迅為iTOP-RK3568開發板編寫LED驅動

迅為iTOP-RK3568開發板編寫LED驅動

我們在 ubuntu 的 home/nfs/07 目錄下新建 led.c 檔案,可以在上次實驗的驅動程式碼基礎上進行修改,以
下程式碼為完整的驅動程式碼。
我們已經學會了雜項裝置驅動編寫的基本流程,其實需求已經完成了一半了,我們已經註冊了雜項設
備,並生成了裝置節點。接下來我們要完成控制 BEEP 的邏輯操作,那麼控制 BEEP 就涉及到了對暫存器的
操作,但是對暫存器的操作我們是不能直接訪問的,因為 linux 不能直接訪問我們的實體地址,需要把物理
地址先對映成虛擬地址,我們完成這一步轉換需要用到 ioremap 函式。
完整的驅動檔案如下所示:
/*
* @Descripttion: 基於雜項裝置的 LED 驅動
* @version:
* @Author:
* @Date: 2021-02-23 13:54:49
*/
#include <linux/init.h>
//初始化標頭檔案
#include <linux/module.h>
//最基本的檔案,支援動態新增和解除安裝模組。
#include <linux/miscdevice.h> //包含了 miscdevice 結構的定義及相關的操作函式。
#include <linux/fs.h>
//檔案系統標頭檔案,定義檔案表結構(file,buffer_head,m_inode 等)
#include <linux/uaccess.h>
//包含了 copy_to_user、copy_from_user 等核心訪問使用者程序記憶體地址的函
數定義。
#include <linux/io.h>
//包含了 ioremap、iowrite 等核心訪問 IO 記憶體等函式的定義。
#include <linux/kernel.h>
//驅動要寫入核心,與核心相關的標頭檔案
#define GPIO_DR 0xfdd60000 //LED 實體地址,通過檢視原理圖得知
unsigned int *vir_gpio_dr; //存放對映完的虛擬地址的首地址
/**
* @name: misc_read
* @test: 從裝置中讀取資料,當用戶層呼叫函式 read 時,對應的,核心驅動就會呼叫這個函式。
* @msg:
* @param {structfile} *file file 結構體
* @param {char__user} *ubuf 這是對應使用者層的 read 函式的第二個引數 void *buf
* @param {size_t} size 對應應用層的 read 函式的第三個引數
* @param {loff_t} *loff_t 這是用於存放檔案的偏移量的,回想一下系統程式設計時,讀寫檔案的操作都會使
偏移量往後移。
* @return {*} 當返回正數時,核心會把值傳給應用程式的返回值。一般的,呼叫成功會返回成功讀取
的位元組數。
如果返回負數,核心就會認為這是錯誤,應用程式返回-1
*/
ssize_t misc_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{
printk("misc_read\n ");
return 0;
}
/**
* @name: misc_write
* @test: 往裝置寫入資料,當用戶層呼叫函式 write 時,對應的,核心驅動就會呼叫這個函式。
* @msg:
* @param {structfile} * filefile 結構體
* @param {constchar__user} *ubuf 這是對應使用者層的 write 函式的第二個引數 const void *buf
* @param {size_t} size 對應使用者層的 write 函式的第三個引數 count。
* @param {loff_t} *loff_t 這是用於存放檔案的偏移量的,回想一下系統程式設計時,讀寫檔案的操作都會使
偏移量往後移。
* @return {*} 當返回正數時,核心會把值傳給應用程式的返回值。一般的,呼叫成功會返回成功讀取
的位元組數。
如果返回負數,核心就會認為這是錯誤,應用程式返回-1。
*/
ssize_t misc_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{
/*應用程式傳入資料到核心空間,然後控制蜂鳴器的邏輯,在此新增*/
// kbuf 儲存的是從應用層讀取到的資料
char kbuf[64] = {0};
// copy_from_user 從應用層傳遞資料給核心層
if(copy_from_user(kbuf,ubuf,size)!= 0)
{
// copy_from_user 傳遞失敗列印
printk("copy_from_user error \n ");
return -1;
}
//列印傳遞進核心的資料
printk("kbuf is %d\n ",kbuf[0]);
if(kbuf[0]==1) //傳入資料為 1 ,LED 亮
{
*vir_gpio_dr = 0x80008000;
}
else if(kbuf[0]==0) //傳入資料為 0,LED 滅
*vir_gpio_dr = 0x80000000;
return 0;
}
/**
* @name: misc_release
* @test: 當裝置檔案被關閉時核心會呼叫這個操作,當然這也可以不實現,函式預設為 NULL。關閉設
備永遠成功。
* @msg:
* @param {structinode} *inode 裝置節點
* @param {structfile} *file filefile 結構體
* @return {0}
*/
int misc_release(struct inode *inode,struct file *file){
printk("hello misc_relaease bye bye \n ");
return 0;
}
/**
* @name: misc_open
* @test: 在操作裝置前必須先呼叫 open 函式開啟檔案,可以幹一些需要的初始化操作。
* @msg:
* @param {structinode} *inode 裝置節點
* @param {structfile} *file filefile 結構體
* @return {0}
*/
int misc_open(struct inode *inode,struct file *file){
printk("hello misc_open\n ");
return 0;
}
//檔案操作集
struct file_operations misc_fops={
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
.read = misc_read,
.write = misc_write,
};
//miscdevice 結構體
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "hello_misc",
.fops = &misc_fops,
};
static int misc_init(void)
{
int ret;
//註冊雜項裝置
ret = misc_register(&misc_dev);
if(ret<0)
{
printk("misc registe is error \n");
}
printk("misc registe is succeed \n");
//將實體地址轉化為虛擬地址
vir_gpio_dr = ioremap(GPIO_DR,4);
if(vir_gpio_dr == NULL)
{
printk("GPIO_DR ioremap is error \n");
return EBUSY;
}
printk("GPIO_DR ioremap is ok \n");
return 0;
}
static void misc_exit(void){
//解除安裝雜項裝置
misc_deregister(&misc_dev);
iounmap(vir_gpio_dr);
printk(" misc gooodbye! \n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
更多內容請關注:北京迅為