Rk3568驅動開發_Key驅動_13

設備樹配置

	key{compatible = "alientek,key";pinctrl-0 = <&key_gpio>;pinctrl-names = "alientek,key";key-gpio = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;status = "okay";};

配置信息方便后面直接引用:

	// Narnat 2025-6-14key-gpios{/omit-if-no-ref/key_gpio: key-pin {rockchip,pins=<3 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;};};

在這里插入圖片描述
注冊節點,將信息寫入設備,方便后續驅動讀取設備

驅動代碼

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <asm/uaccess.h>
#include <asm/io.h>#define KEY_CNT   1  // 設備號個數
#define KEY_NAME  "key" // 名字#define KEY0VALUE  0xf0 // 按鍵值
#define INVAKEY    0x00 // 無效按鍵值/* 設備結構體 */
struct key_dev{dev_t devid;                   // 設備號struct cdev cdev;             // cdevstruct class* class;         // 類struct device* device;       // 設備int major;                  // 主設備號int minor;                 // 次設備號struct device_node* nd;   // 設備節點int key_gpio;            // key所使用的gpio編號atomic_t  keyvalue;     // 按鍵值
};static struct key_dev keydev;  // 按鍵值static int keyio_init(void){int ret;const char* str;/*設置LED所使用GPIO*/// 1.獲取節點keydevkeydev.nd = of_find_node_by_path("/key");if(keydev.nd == NULL){printk("keydev node not find! \r\n");return -1;}// 2.讀取status屬性ret = of_property_read_string(keydev.nd, "status", &str);if(ret < 0) return -1;if(strcmp(str, "okay")) return -1;// 3.獲取compatible屬性并對比ret = of_property_read_string(keydev.nd, "compatible", &str);if(ret < 0){printk("failed to get compatible\n");return -1;}if(strcmp(str, "alientek,key")){printk("compatible match failed\n");return -1;}// 4.獲取gpio屬性,得到kEY編號keydev.key_gpio = of_get_named_gpio(keydev.nd, "key-gpio", 0);if(keydev.key_gpio < 0){printk("cant get key-gpio \n");return -1;}printk("key-gpio num= %d \n", keydev.key_gpio);// 5.向gpio子系統申請使用gpioret = gpio_request(keydev.key_gpio, "KEY0");if(ret){printk("failed to request key-gpio \n");return ret;}// 6.設置gpio輸入模式ret = gpio_direction_input(keydev.key_gpio);if(ret < 0){printk("cant set gpio \n");return ret;}return 0;
}static int key_open(struct inode* inode, struct file* filp){int ret = 0;filp->private_data = &keydev;ret = keyio_init();if(ret < 0) return ret;return 0;
}static ssize_t key_read(struct file* filp, char __user* buf, size_t cnt, loff_t* offt){int ret = 0;int value;struct key_dev* dev = filp->private_data;if(gpio_get_value(dev->key_gpio) == 1){while(gpio_get_value(dev->key_gpio));atomic_set(&dev->keyvalue, KEY0VALUE);}else{atomic_set(&dev->keyvalue, INVAKEY);}value = atomic_read(&dev->keyvalue);ret = copy_to_user(buf, &value, sizeof(value));return ret;
}static ssize_t key_write(struct file* filp, const char __user* buf, size_t cnt, loff_t* offt){return 0;
}static int key_release(struct inode* inode, struct file* filp){struct key_dev* dev = filp->private_data;gpio_free(dev->key_gpio);return 0;
}
// 設備操作函數
static struct file_operations key_fops = {.owner = THIS_MODULE,.open = key_open,.read = key_read,.write = key_write,.release = key_release,
};/* 驅動入口 */
static int __init mykey_init(void){int ret;// 1.初始化原子變量keydev.keyvalue = (atomic_t)ATOMIC_INIT(0);// 2.初始值設置為INVAKEYatomic_set(&keydev.keyvalue, INVAKEY);/*注冊字符驅動*/// 1.創建設備號if(keydev.major){ // 定義了設備號keydev.devid = MKDEV(keydev.major, 0);ret = register_chrdev_region(keydev.devid, KEY_CNT, KEY_NAME);if(ret < 0){printk("cannt register %s char driver \n", KEY_NAME);return -1;}}else{ // 未定義設備號ret = alloc_chrdev_region(&keydev.devid, 0, KEY_CNT, KEY_NAME); // 申請設備號if(ret < 0){printk("%s couldnot alloc_chrdev_region \n", KEY_NAME);return -1;}keydev.major = MAJOR(keydev.devid); // 分配主設備號keydev.minor = MINOR(keydev.devid); // 分配次設備}printk("keydev major=%d, minor=%d \r\n", keydev.major, keydev.minor);// 2.初始化cdevkeydev.cdev.owner = THIS_MODULE;cdev_init(&keydev.cdev, &key_fops);// 3.添加一個cdevret = cdev_add(&keydev.cdev, keydev.devid, KEY_CNT);if(ret < 0) goto del_unregister;// 4.創建類keydev.class = class_create(THIS_MODULE, KEY_NAME);if(IS_ERR(keydev.class)) goto del_cdev;// 5.創建設備keydev.device = device_create(keydev.class, NULL, keydev.devid, NULL, KEY_NAME);if(IS_ERR(keydev.device)) goto destroy_class; return 0;
destroy_class:device_destroy(keydev.class, keydev.devid);
del_cdev:cdev_del(&keydev.cdev);  
del_unregister:unregister_chrdev_region(keydev.devid, KEY_CNT);return -1;
}/* 驅動出口 */
static void __exit mykey_exit(void){// 注銷字符設備驅動cdev_del(&keydev.cdev); // 刪除cdevunregister_chrdev_region(keydev.devid, KEY_CNT); // 注銷設備號device_destroy(keydev.class, keydev.devid);class_destroy(keydev.class);
}module_init(mykey_init);
module_exit(mykey_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Narnat");

補全read函數,應用層調用read命令后讀取到驅動發送的數據

應用層:

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
/***************************************************************
Copyright ? ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名		: keyApp.c
作者	  	: 正點原子Linux團隊
版本	   	: V1.0
描述	   	: 按鍵輸入測試應用程序
其他	   	: 無
使用方法	 :./keyApp /dev/key  
論壇 	   	: www.openedv.com
日志	   	: 初版V1.0 2021/01/5 正點原子Linux團隊創建
***************************************************************//* 定義按鍵值 */
#define KEY0VALUE	0XF0
#define INVAKEY		0X00/** @description		: main主程序* @param - argc 	: argv數組元素個數* @param - argv 	: 具體參數* @return 			: 0 成功;其他 失敗*/
int main(int argc, char *argv[])
{int fd, ret;char *filename;int keyvalue;if(argc != 2){printf("Error Usage!\r\n");return -1;}filename = argv[1];/* 打開key驅動 */fd = open(filename, O_RDWR);if(fd < 0){printf("file %s open failed!\r\n", argv[1]);return -1;}/* 循環讀取按鍵值數據! */while(1) {read(fd, &keyvalue, sizeof(keyvalue));if (keyvalue == KEY0VALUE) {	/* KEY0 */printf("KEY0 Press, value = %#X\r\n", keyvalue);	/* 按下 */}}ret= close(fd); /* 關閉文件 */if(ret < 0){printf("file %s close failed!\r\n", argv[1]);return -1;}return 0;
}

效果:
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/88596.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/88596.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/88596.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

參展回顧 | AI應用創新場景:數據分析助手ChatBI、璞公英教學平臺亮相2025四川國際職教大會暨產教融合博覽會

2025年6月11日-13日&#xff0c;以“數字賦能產教融合&#xff0c;創新驅動技能未來”為主題的2025四川國際職業教育大會暨產教融合博覽會在成都盛大開幕。璞華聯合百度共同參展&#xff0c;并攜旗下創新產品ChatBI數據分析助手、璞公英教學平臺重磅亮相&#xff0c;憑借前沿的…

動態規劃之01背包問題

動態規劃算法 動態規劃算法介紹 動態規劃(Dynamic Programming)算法的核心思想是&#xff1a;將大問題劃分為小問題進行解決&#xff0c;從而一步步獲取最優解的處理算法動態規劃算法與分治法類似&#xff0c;其基本思想也是將待解決問題分解成若干個子問題&#xff0c;先求解…

人大金倉新建用戶,并且賦值查詢權限

-- 1. 創建用戶 visitor&#xff0c;并且設置密碼 CREATE USER visitor WITH PASSWORD 1234qwer; -- 2. 授予該用戶連接到數據庫 "yonbip_db" 的權限 GRANT CONNECT ON DATABASE yonbip_db TO visitor; -- 3. 假設你要讓 visitor 查詢的模式是 public&#xff08;或…

學習筆記丨信號處理新趨勢:量子計算將如何顛覆傳統DSP?

在算力需求爆炸式增長的今天&#xff0c;傳統數字信號處理&#xff08;DSP&#xff09;芯片正面臨物理極限的嚴峻挑戰。當經典計算機架構在摩爾定律的黃昏中掙扎時&#xff0c;量子計算正以顛覆性姿態崛起&#xff0c;準備重新定義信號處理的未來圖景。 目錄 傳統DSP的瓶頸&am…

react day.js使用及經典場景

簡介 Day.js 是一個輕量級的 JavaScript 日期庫&#xff0c;它提供了簡單易用的 API 來處理日期和時間。以及更加輕量級&#xff0c;并且具有更快的性能。 安裝 npm install dayjs 使用 import dayjs from "dayjs";dayjs().format("YYYY-MM-DD HH:mm:ss&qu…

【機器學習深度學習】線性回歸

目錄 一、定義 二、舉例說明 三、 數學形式 四、 訓練過程&#xff08;機器怎么學會這條線&#xff1f;&#xff09; 五、在 PyTorch 中怎么實現線性回歸&#xff1f; 六、如果你學懂了線性回歸&#xff0c;你也能理解這些 七、綜合應用&#xff1a;線性回歸示例 7.1 執…

如何在 Manjaro Linux 上安裝 .NET Core

.NET 是一個開源的開發框架平臺,可在所有流行的操作系統(如 Windows、Linux 和 macOS)上免費使用和安裝。它是跨平臺的,是主要由微軟員工在 .NET 基金會下開發的專有 .NET Framework 的繼承者。.NET 是一個統一的平臺,用于開發各種操作系統上的軟件,如 Web、移動、桌面應…

Mysql解惑(一)

使用 or 可能不走索引 使用 union替代 使用in&#xff0c;可能不走索引 如果優化&#xff1a; 臨時表強制索引exists代替

基于機器學習的側信道分析(MLSCA)Python實現(帶測試)

一、MLSCA原理介紹 基于機器學習的側信道分析(MLSCA)是一種結合傳統側信道分析技術與現代機器學習算法的密碼分析方法。該方法通過分析密碼設備運行時的物理泄漏信息(如功耗、電磁輻射等)&#xff0c;利用機器學習模型建立泄漏數據與密鑰信息之間的關聯模型&#xff0c;從而實…

【LLM】位置編碼

【LLM】位置編碼 1 絕對位置嵌入為什么用 1000 0 2 t d 10000^{\frac{2t}{d}} 10000d2t?? 2 相對位置嵌入2.1 Shaw等人的方法&#xff08;2018&#xff09;2.2 Dai等人的方法&#xff08;2019&#xff09;2.3 Raffel 等人的方法&#xff08;2020&#xff09;2.4 He 等人的方法…

Java 根據分組key構建合并數據集

文章目錄 前言背景總結 前言 請各大網友尊重本人原創知識分享&#xff0c;謹記本人博客&#xff1a;南國以南i、 提示&#xff1a;以下是本篇文章正文內容&#xff0c;下面案例可供參考 背景 Java 需要返回一組數據供前端展示&#xff0c;獲取到的數據格式如下&#xff1a; …

Linux平臺Oracle開機自啟動設置

網上和官方文檔已經有不少介紹如何設置開機啟動Oracle實例的文章(Linux平臺)&#xff0c;不過以sysvinit和service這種方式居多。最近遇到了UAT環境的服務器打補丁后需要重啟服務器的情況&#xff0c; 需要DBA去手工啟動Oracle實例的情形&#xff0c;和同事討論&#xff0c;決定…

商品中心—商品B端搜索系統的實現文檔(二)

8.步驟四&#xff1a;基于索引實現搜索功能 (1)基于suggest索引的自動補全實現 實現自動補全的代碼比較簡單&#xff0c;其原理是&#xff1a;把搜索詞匯和倒排索引里的所有前綴匹配的詞條進行score比較&#xff0c;然后把分數最高的那些返回&#xff0c;其中會涉及到suggest索…

Codeforces Round 1027 (Div. 3)

A. Square Year 題目大意 給你一個四個字符的字符串&#xff0c;代表一個數字s 問是否存在a,b兩個數字&#xff0c;使得 ( a b ) 2 s (ab)^2s (ab)2s 思路 如果s是奇數或不能被開根號一定不行 設sq為s開根號后的結果 將sq一分為2&#xff0c;考慮sq/2有沒有余數的情況 //…

時序數據庫IoTDB的架構、安裝啟動方法與數據模式總結

一、IoTDB的架構 IoTDB的架構主要分為三個部分&#xff1a; ?時序文件&#xff08;Tsfile&#xff09;?&#xff1a; 專為時序數據設計的文件存儲格式。支持高效的壓縮和查詢性能。可獨立使用&#xff0c;并可通過TsFileSync工具同步至HDFS進行大數據處理。 ?數據庫引擎?…

ArrayList和LinkedList詳解

在Java后端開發中&#xff0c;集合框架是我們日常編程不可或缺的工具&#xff0c;它為數據存儲和操作提供了豐富的實現方式。作為Java集合框架中最常用的兩種List實現&#xff0c;ArrayList和LinkedList各自具有獨特的特性和適用場景。 1. 基本概念 1.1 ArrayList的定義與特性…

警惕微軟Entra ID風險:訪客賬戶存在隱蔽的權限提升策略

訪客用戶訂閱權限漏洞解析 微軟Entra ID的訂閱管理存在訪問控制缺陷&#xff0c;允許訪客用戶在受邀租戶中創建和轉移訂閱&#xff0c;同時保留對這些訂閱的完全所有權。訪客用戶只需具備在源租戶創建訂閱的權限&#xff0c;以及受邀成為外部租戶訪客的身份即可實施此操作。這…

EEG分類攻略2-Welch 周期圖

在EEG信號處理的上下文中&#xff0c;使用Welch方法來估算信號的功率譜密度&#xff08;Power Spectral Density, PSD&#xff09;是一種常見的做法。你的代碼片段是利用**scipy.signal.welch**函數來進行功率譜密度估算&#xff0c;并且涉及到一些關鍵的參數和步驟。讓我們逐步…

開疆智能CCLinkIE轉ModbusTCP網關連接脈沖計數器配置案例

本案例是三菱PLC通過CCLinkIE轉ModbusTCP網關連接脈沖計數器的配置案例&#xff0c;具體配置如下。 配置過程&#xff1a; 首先設置從站通訊參數 主要設置IP地址&#xff0c;工作模式以及端口號&#xff08;Modbus默認502&#xff09; 找到通訊點表&#xff0c;找到需要讀寫的…

gRPC 使用(python 版本)

.proto 文件 .proto 文件 是 gRPC 和 Protocol Buffers 的接口定義文件&#xff0c;它描述了&#xff1a; 要傳遞什么數據&#xff08;也就是消息體 message&#xff09;。要暴露什么接口&#xff08;也就是服務 service 和它們的 方法&#xff09;。 也就是一份規范文件&am…