字元裝置驅動第十一課----裝置樹
介面
1.出處:
include/linux/of.h
2.資料結構:
struct device_node {
const char *name;
const char *type;
phandle phandle;
const char *full_name;
struct fwnode_handle fwnode;
struct property *properties;
struct property *deadprops; /* removed properties */
struct device_node *parent;
struct device_node *child;
struct device_node *sibling;
struct kobject kobj;
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
const char *path_component_name;
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
3.從裝置樹中查詢節點
/*
* 功能:通過名字找到裝置節點
* 輸入引數: struct device_node *from: 開始節點,比如從/I2C節點開始,搜尋它下面的所有子節點
* const char *name: 節點名
* 返回值:搜尋到的節點
*/
struct device_node *of_find_node_by_name(struct device_node *from,const char *name)
/*
* 功能:通過型別找到裝置節點
* 輸入引數: struct device_node *from: 開始節點,比如從/I2C節點開始,搜尋它下面的所有子節點
* const char *type: 型別名
* 返回值:搜尋到的節點
*/
struct device_node *of_find_node_by_type(struct device_node *from,const char *type );
/*
* 功能:通過compatible屬性查詢節點
* 引數:struct device_node *from: - 開始節點
* const char *type: - 裝置型別
* const char *compat: - compatible值"廠商,裝置"
* 返回值: 失敗:NULL
*/
struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compat);
/*
* 功能:從匹配表中查詢裝置ID相匹配的節點
* 引數:struct device_node *from: - 開始節點
const struct of_device_id *matches: - 表,用於匹配
const struct of_device_id **match: - 表中的該項開始,從後面匹配
* 返回值: 失敗:NULL
*/
struct device_node *of_find_matching_node_and_match(
struct device_node *from,
const struct of_device_id *matches,
const struct of_device_id **match);
/*
* 功能:通過路徑查詢節點
* 引數:const char *path: - 路徑
* 返回值: 失敗:NULL 成功:找到的節點
*/
struct device_node *of_find_node_by_path(const char *path);
/*
* 功能:得到父節點
* 輸入引數: const struct device_node *node: 當前節點
* 返回值: 失敗:NULL 成功:找到的節點
*/
struct device_node *of_get_parent(const struct device_node *node);
/*
* 功能:得到父節點
* 輸入引數: const struct device_node *node: 當前節點
* 返回值: 失敗:NULL 成功:找到的節點
*/
struct device_node *of_get_next_parent(struct device_node *node);
/*
* 功能: 獲得子節點
* 輸入引數: const struct device_node *node: 當前節點
* struct device_node *prev: 前一個子節點
*/
struct device_node *of_get_next_child(const struct device_node *node,struct device_node *prev);
/*
* 功能:通過名字獲取子節點
* 輸入引數: const struct device_node *node:當前節點
* const char *name: 子節點的名字
*/
struct device_node *of_get_child_by_name(const struct device_node *node,
const char *name);
4.從裝置節點中提取資訊
struct property {
char *name; // 屬性名
int length; //值長度
void *value; //值的首地址
};
/*
* 功能:提取屬性
* 輸入引數:const struct device_node *np: 節點指標
* const char *name,: 屬性名
* int *lenp: 長度
*/
struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp);
/*
* 功能:通過索引提取屬性
* 輸入引數:const struct device_node *np: 裝置節點
* const char *propname: 被搜尋的compatible屬性名
* u32 index: 索引
* 輸出引數:u32 *out_value:提取到的屬性值
* 返回值: 成功:0 失敗:返回負數,其絕對值是錯誤碼
*/
int of_property_read_u32_index(const struct device_node *np,
const char *propname,
u32 index, u32 *out_value);
/*
* 功能:提取陣列型別的屬性
* 輸入引數:const struct device_node *np: 裝置節點
* const char *propname: 被搜尋的compatible屬性名
* 輸出引數:u32 *out_value:提取到的屬性陣列的首地址
* size_t sz: 提取到的屬性陣列的大小
* 返回值: 成功:0 失敗:返回負數,其絕對值是錯誤碼
*/
int of_property_read_u8_array(const struct device_node *np,
const char *propname, u8 *out_values, size_t sz);
/*
* 功能:提取字串型別的屬性
* 輸入引數:const struct device_node *np: 裝置節點
* const char *propname: 被搜尋的compatible屬性名
* 輸出引數:u32 *out_value:提取到的屬性字串的首地址
* 返回值: 成功:0 失敗:返回負數,其絕對值是錯誤碼
*/
int of_property_read_string(struct device_node *np,
const char *propname,
const char **out_string);
5.從裝置樹中提取地址
5.1 地址資料結構
<linux/of_address.h>
struct resource {
resource_size_t start; //開始位置
resource_size_t end; //結束位置
unsigned long flags; //資源型別:IORESOURCE_MEM(地址類資源)
// IORESOURCE_IRQ(中斷類資源)
};
/*
* 功能:提取資源
* 輸入引數:struct device_node *dev: - 當前節點
* int index: - 資源編號 0開始
* 輸出引數:struct resource *r: - 輸出找到結果
*/
int of_address_to_resource(struct device_node *dev, int index,
struct resource *r);
/*
* 功能:以虛擬地址形式提取
* 輸入引數: struct device_node *node: 裝置節點
* index: 索引
* 返回值:成功:虛擬地址 失敗:NULL
*/
void __iomem *of_iomap(struct device_node *node, int index);
/*
* 功能:以虛擬地址形式提取某項屬性中的某個地址
* 輸入引數: struct device_node *node: 裝置節點
* index: 該項屬性中的第幾個
* const char *name: 該項屬性的名字
* 返回值:成功:虛擬地址 失敗:NULL
*/
void __iomem *of_io_request_and_map(struct device_node *device,
int index, const char *name);
/*
* 功能:提取地址
* 輸入引數: struct device_node *dev: 裝置節點
* int index: 索引
* u64 *size: 大小
* unsigned int *flags:
*/
const __be32 *of_get_address(struct device_node *dev, int index,
u64 *size, unsigned int *flags);
從裝置樹中提取中斷
/*
* 功能:提取中斷
* 輸入引數: struct device_node *dev: 裝置節點
* int index: 索引
* 輸出引數: struct resource *r:獲得的中斷號
* 返回值成功:0 失敗:負數
*/
int of_irq_to_resource(struct device_node *dev, int index,
struct resource *r);
/*
* 功能:提取中斷
* 輸入引數: struct device_node *dev: 裝置節點
* int index: 索引
* 返回值:成功:中斷號 失敗:負數
*/
int of_irq_get(struct device_node *dev, int index);
/*
* 功能:通過名字提取中斷
* 輸入引數: struct device_node *dev: 裝置
* const char *name: 名字
* 返回值:成功:中斷號 失敗:負數
*/
int of_irq_get_byname(struct device_node *dev, const char *name);
/*
* 功能:通過索引提取中斷,並將物理中斷號對映成系統中的中斷號
* 輸入引數: struct device_node *dev: 裝置
* int index: 索引
* 返回值:成功:中斷號 失敗:負數
*/
unsigned int irq_of_parse_and_map(struct device_node *node, int index);
自定義中斷號
/*
* 功能:從裝置樹獲取gpio編號
* 輸入引數:@np: 裝置節點
* @propname: 屬性域名字
* @index: 索引
* 返回值: gpio編號
*/
int of_get_named_gpio(struct device_node *np, const char *propname, int index)
<include/linux/gpio.h>
/*
* 功能:將一個gpio編號繫結一些資訊,使其成為核心認可的一個完整的GPIO
* 輸入引數:@gpio: GPIO 編號
* @flags: GPIOF_IN還是GPIOF_OUT
* @label: 取個名字來標識一下
*/
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
/*
* 功能: 為該gpio資源申請一箇中斷號
* 輸入引數: gpio: GPIO編號
* 返回值: 中斷號
*/
fsirq = gpio_to_irq(gpio);
/*
* 功能: 將使用者申請到的中斷號繫結回撥函式,並向核心註冊
* 輸入引數: fsirq: 中斷號
* key_interrupt: 回撥函式名
* IRQF_TRIGGER_RISING: 中斷觸發方式
* DEVNAME: 裝置名
* devid: 裝置ID(一般可填NULL)
* 返回值:成功:0 失敗:負數
*/
int request_irq(fsirq, key_interrupt, IRQF_TRIGGER_RISING, DEVNAME, NULL)
工程例項
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/current.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/device.h>
static struct class *cls = NULL;
static int major = 0;
static int minor = 0;
const int count = 6;
#define DEVNAME "fskey"
static struct cdev *fskeyp = NULL;
static struct device_node *fsnd = NULL;
static int fsirq;
static int gpio;
static atomic_t tv;
/*
*功能:通過路徑查詢節點
*引數:
const char *nodepath - 節點路徑或引用
*返回值:
失敗:NULL
成功:節點指標
*/
static struct device_node *getnodebypath(const char *nodepath)
{
/*匹配路徑查詢節點*/
return of_find_node_by_path(nodepath);
}
static irqreturn_t key_interrupt(int irqno, void *devid)
{
printk("irqno=%d; %s : %d\n", irqno, __func__, __LINE__);
return IRQ_HANDLED;
}
//開啟裝置
static int fskey_open(struct inode *inode, struct file *filp)
{
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//get major and minor from inode
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
if(!atomic_dec_and_test(&tv)){//原子操作,防止重複開啟
atomic_inc(&tv);
return -EBUSY;
}
/* 為一箇中斷號繫結回撥函式並註冊進核心*/
if (request_irq(fsirq, key_interrupt, IRQF_TRIGGER_RISING, DEVNAME, NULL)){
printk(KERN_ERR"ERROR: request IRQ[%d] fail.\n", fsirq);
return -EAGAIN;
}
return 0;
}
//關閉裝置
static int fskey_release(struct inode *inode, struct file *filp)
{
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//get major and minor from inode
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
free_irq(fsirq, NULL);//釋放中斷號
atomic_inc(&tv);
return 0;
}
//讀裝置
//ssize_t read(int fd, void *buf, size_t count)
static ssize_t fskey_read(struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = fskey_open,
.release= fskey_release,
.read = fskey_read,
};
static int __init fskey_init(void)
{
dev_t devnum;
int ret, i;
struct resource r;
void __iomem *ioaddr = NULL;
struct device *devp = NULL;
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
fsnd = getnodebypath("/key@26");//從裝置樹中找到裝置
if(NULL == fsnd){
return -EINVAL;
}
#if 1
#if 0
//fsirq = irq_of_parse_and_map(fsnd, 0);
//if(0 > fsirq){
// return fsirq;
//}
of_irq_to_resource(fsnd, 0, &r);//獲取資源,中斷資源
if(IORESOURCE_IRQ == r.flags)//確保獲得的資源是中斷資源而不是IO資源
printk("irq 0: %d\n", r.start);
of_irq_to_resource(fsnd, 1, &r);
if(IORESOURCE_IRQ == r.flags)
printk("irq 1: %d\n", r.start);
fsirq = of_irq_get(fsnd, 0);//獲取該裝置節點中的第0箇中斷資源
printk("fsirq = %d\n", fsirq);
fsirq = of_irq_get(fsnd, 1);
printk("fsirq = %d\n", fsirq);
#endif
of_address_to_resource(fsnd, 0, &r);//獲取該裝置節點中的地址資源
if(IORESOURCE_MEM == r.flags)
printk("iomem 0: 0x%x\n", r.start);
of_address_to_resource(fsnd, 1, &r);
if(IORESOURCE_MEM == r.flags)
printk("iomem 1: 0x%x\n", r.start);
ioaddr = of_iomap(fsnd, 0);//獲取該裝置節點中的地址資源並對映到虛擬地址
printk("iomem 0: 0x%p\n", ioaddr);
ioaddr = of_iomap(fsnd, 1);
printk("iomem 0: 0x%p\n", ioaddr);
#else
gpio = of_get_named_gpio(fsnd, "key-intr", 0);//獲取該裝置節點中的IO資源
if (gpio_is_valid(gpio)) {//該gpio可用
ret = gpio_request_one(gpio, GPIOF_IN, "key-intr");//將一個gpio編號繫結一些資訊,使其成為核心認可的一個完整的GPIO
if (ret) {
printk(KERN_ERR"ERROR: gpio_request_one fail.\n");
return ret;
}
fsirq = gpio_to_irq(gpio); //為該gpio資源申請一箇中斷號
if(0 > fsirq){
printk(KERN_ERR"ERROR: gpio_to_irq fail.\n");
return -ENODEV;
}
}else{
printk(KERN_ERR"ERROR: gpio is invalid.\n");
return -EINVAL;
}
#endif
//1. alloc cdev obj
fskeyp = cdev_alloc();
if(NULL == fskeyp){
return -ENOMEM;
}
//2. init cdev obj
cdev_init(fskeyp, &fops);
ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);
if(ret){
goto ERR_STEP;
}
major = MAJOR(devnum);
//3. register cdev obj
ret = cdev_add(fskeyp, devnum, count);
if(ret){
goto ERR_STEP1;
}
cls = class_create(THIS_MODULE, DEVNAME);
if(IS_ERR(cls)){
ret = PTR_ERR(cls);
goto ERR_STEP1;
}
for(i = minor; i < (count+minor); i++){
devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i);
if(IS_ERR(devp)){
ret = PTR_ERR(devp);
goto ERR_STEP2;
}
}
// init atomic_t
atomic_set(&tv, 1);//初始化原子變數
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - ok.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
return 0;
ERR_STEP2:
for(--i; i >= minor; i--){
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR_STEP1:
unregister_chrdev_region(devnum, count);
ERR_STEP:
cdev_del(fskeyp);
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - fail.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
return ret;
}
static void __exit fskey_exit(void)
{
int i;
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
for(i=minor; i < (count+minor); i++){
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
unregister_chrdev_region(MKDEV(major, minor), count);
cdev_del(fskeyp);
gpio_free(gpio); //釋放申請的gpio
}
module_init(fskey_init);
module_exit(fskey_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Farsight");
MODULE_DESCRIPTION("Demo for kernel module");
相關推薦
字元裝置驅動第十一課----裝置樹
介面 1.出處: include/linux/of.h 2.資料結構: struct device_node { const char *name; const char *type; phandle phandle;
嵌入式Linux驅動筆記(十一)------i2c裝置之mpu6050驅動
你好!這裡是風箏的部落格, 歡迎和我一起交流。 上一節講了i2c框架: 嵌入式Linux驅動筆記(十)——通俗易懂式瞭解i2c框架 這次就來寫一寫真正的i2c裝置驅動: mpu6050是一款6軸運動處理元件,採用i2c通訊介面。 首先是廠家提供的m
第十一課、異常類的構建-------------狄泰軟件學院
end ++ pla ini images 數據 pointer oid 變量 一、自定義異常類 1、異常的類型可以是自定義的類類型 2、對於類類型的匹配依舊是之上而下的嚴格匹配 3、賦值兼容性原則在異常匹配中依然適用 所以要 (1)、匹配子類異常的catch放在上部 (2
Ng第十一課:機器學習系統的設計(Machine Learning System Design)
未能 計算公式 pos 構建 我們 行動 mic 哪些 指標 11.1 首先要做什麽 11.2 誤差分析 11.3 類偏斜的誤差度量 11.4 查全率和查準率之間的權衡 11.5 機器學習的數據 11.1 首先要做什麽 在接下來的視頻將談到機器
java-web——第十一課 時間類
osc 題目 其中 ima cal pid end 不能 sch 前言: 在我們學習java web之中,實體類的屬性經常會遇到時間類 時間類也是一個很重要的類, 首先我們先了解一下經常使用的時間類 經常使用的時間類也就是這三個類 具體的可以查閱api http://to
第十一課 集合類Collection和Map
什麽是 基本數據類型 16px 開始 有序 面向對象 style 數據 取出 集合類 面向對象語言對事物的體現都是以對象的形式,所以為了方便對多個對象的操作,就對對象進行存儲,集合就是存儲對象最常用的方式。 數組和集合類都是容器,他們有什麽不同? 數組雖然也可以存儲對象,但
第十一課:結合律
tin 結合 .com com img es2017 images get image http://www.52investing.com/jpkecheng/payRoom_31_109.html 第十一課:結合律
第十一課 語句的嵌套
得到 post 嵌套for 語句 嵌套 color pre pan 我們 說個小故事:話說一個人買到一個治療瘙癢的偏方,在拆開無數層的包裝後,得到的只是一張寫著“撓撓”的小紙條兒。 嵌套,類似於在一個語句中,嵌套另一個語句。舉個栗子-_-!! 我們要計算從1到100之間,
第十一課 xshell實現linux與windows互文件、用戶與密碼的配置文件、用戶和用戶組的管理
20180403一、Xshell 上實現Linux 與windows互傳1、先用命令 yum install -y lrzsz ;2、向windosw 系統傳文件,sz filename ,向Linux上傳文件,直接輸入rz命令,然在WINDOWS選擇文件即可 二、用戶與密碼的配置文件cat /etc/pa
潭州課堂25班:Ph201805201 第十一課 繼承,多繼承和魔術方法,屬性和方法 (課堂筆記)
筆記 父類 當前 TE -s __del__ color true ont 繼承: class p : cls_name = ‘p‘ def __init__(self): print(‘正在實例化‘) def __del__(se
斯坦福大學-自然語言處理入門 筆記 第十一課 最大熵模型與判別模型(2)
一、最大熵模型 1、模型介紹 基本思想:我們希望資料是均勻分佈的,除非我們有其他的限制條件讓給我們相信資料不是均勻分佈的。均勻分佈代表高熵(high entropy)。所以,最大熵模型的基本思想就是我們要找的分佈是滿足我們限制條件下,同時熵最高的分佈。 熵:表示分佈的不
C++筆記 第十一課 新型的型別轉換---狄泰學院
如果在閱讀過程中發現有錯誤,望評論指正,希望大家一起學習,一起進步。 學習C++編譯環境:Linux 第十一課 新型的型別轉換 1.強制型別轉換 C方式的強制型別轉換 (Type)(Expression) Type (Expression)—老式型別 11-1 粗暴的型別轉
潭州課堂25班:Ph201805201 django 專案 第十一課 手機號是否存在,簡訊驗證分析 (課堂筆記)
判斷手機號是否註冊功能實現 1.分析 請求方法:GET url定義:/mobiles/(?P<mobile>1[3-9]\d{9})/ 請求引數:url路徑引數 引數 型別 前端是否必須傳 描述 mobile
C語言筆記 第十一課 enum,sizeof,typedef分析
第十一課 enum,sizeof,typedef分析 列舉型別的使用方法 enum是C語言中的一種自定義型別 enum值是可以根據需要自定義的整型值 第一個定義的enum值預設為0 預設情況下的enum值是在前一個定義值的基礎上加1 enum型別的變數只能取定義時的離散值
【問鏈-EOS公開課】第十一課 EOS 智慧合約相互呼叫
EOS中合約之間是可以相互呼叫的,主要通過inline action完成合約之間的呼叫。 譬如在擲骰子游戲中,存在兩個玩家先下注資金,然後比較骰子大小後決定勝負,贏的那一方將獲得所有的下注資金。在eosio原始碼eos/build/contract/dice 智
第十一課:UI Elements:Fragments(基於AndroidStudio3.2)
執行Android APP的裝置繁多,螢幕大小更是多種多樣。針對不同螢幕尺寸,通常情況下,開發者都是先針對手機開發一套原始碼,然後拷貝一份,修改佈局以適應大螢幕裝置,或平板,電視等。為了決解這樣的麻煩,Google推出了Fragment。你可以把Fragment當成Activ
MATLAB第十一課:線性迴歸方程式與線性系統
目標: 線性方程 線性系統 一、線性方程 Linear Equation: 給定一個線性方程的例子: 把線性方程寫成矩陣的形式。 通常,我們求解線性方程時,A和b是已知的,x是未知的。 Solving Linear Equations: Success
javaweb基礎第十一課:完善登入功能
這節課我們來完善登入功能: Login.jsp: <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> &n
北大AI公開課第十一課--語言智慧的進展by微軟亞洲研究院周明
想做的事情很多,但是時間卻很有限。所以我們更應當在開始任何事情之前,做好足夠的計劃和準備,這樣才能在有限的時間裡做出最恰當的選擇,為自己真正值得做的事爭取出更多時間。之所以有這個感悟是因為最近太多事情要做,但是卻一團糟,所以突然發現,或許應當做一個更為嚴密的計劃! 第十一講
【深度學習框架Caffe學習與應用】 第十一課
1.車輛檢測實踐:使用Caffe訓練的深度學習模型做目標檢測——以車輛檢測為例 有關檔案都放在以下資料夾中: 對vehicle_detetc.cpp進行編譯: 編譯之前,需要修改一下程式碼中的檔