imx6ull-驅動開發篇20——linux互斥體實驗

目錄

實驗程序編寫

修改設備樹文件

LED 驅動修改

mutex.c

測試mutexApp.c

Makefile 文件

運行測試


在之前的文章里,我們學習了:驅動開發篇16——信號量與互斥體。

本講實驗里,我們來使用互斥體mutex實現?LED 燈互斥訪問的功能,編寫驅動代碼,并運行測試結果。

實驗程序編寫

修改設備樹文件

和之前文章一致,GPIO子系統驅動LED,主要是以下幾點:

  • 添加 pinctrl 節點
  • 添加 LED 設備節點
  • 檢查 PIN 是否被其他外設使用

LED 驅動修改

mutex.c

前面我們使用原子操作、自旋鎖和信號量實現了對 LED 燈的互斥訪問,但是最適合互斥的就是互斥體 mutex 了。

代碼如下:

#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/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>#define GPIOLED_CNT			1		  	/* 設備號個數 */
#define GPIOLED_NAME		"gpioled"	/* 名字 */
#define LEDOFF 				0			/* 關燈 */
#define LEDON 				1			/* 開燈 *//* gpioled設備結構體 */
struct gpioled_dev{dev_t devid;			/* 設備號 	 */struct cdev cdev;		/* cdev 	*/struct class *class;	/* 類 		*/struct device *device;	/* 設備 	 */int major;				/* 主設備號	  */int minor;				/* 次設備號   */struct device_node	*nd; /* 設備節點 */int led_gpio;			/* led所使用的GPIO編號		*/struct mutex lock;		/* 互斥體 */
};struct gpioled_dev gpioled;	/* led設備 *//** @description		: 打開設備* @param - inode 	: 傳遞給驅動的inode* @param - filp 	: 設備文件,file結構體有個叫做private_data的成員變量* 					  一般在open的時候將private_data指向設備結構體。* @return 			: 0 成功;其他 失敗*/
static int led_open(struct inode *inode, struct file *filp)
{filp->private_data = &gpioled; /* 設置私有數據 *//* 獲取互斥體,可以被信號打斷 */if (mutex_lock_interruptible(&gpioled.lock)) {return -ERESTARTSYS;}
#if 0mutex_lock(&gpioled.lock);	/* 不能被信號打斷 */
#endifreturn 0;
}/** @description		: 從設備讀取數據 * @param - filp 	: 要打開的設備文件(文件描述符)* @param - buf 	: 返回給用戶空間的數據緩沖區* @param - cnt 	: 要讀取的數據長度* @param - offt 	: 相對于文件首地址的偏移* @return 			: 讀取的字節數,如果為負值,表示讀取失敗*/
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{return 0;
}/** @description		: 向設備寫數據 * @param - filp 	: 設備文件,表示打開的文件描述符* @param - buf 	: 要寫給設備寫入的數據* @param - cnt 	: 要寫入的數據長度* @param - offt 	: 相對于文件首地址的偏移* @return 			: 寫入的字節數,如果為負值,表示寫入失敗*/
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int retvalue;unsigned char databuf[1];unsigned char ledstat;struct gpioled_dev *dev = filp->private_data;retvalue = copy_from_user(databuf, buf, cnt);if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0];		/* 獲取狀態值 */if(ledstat == LEDON) {	gpio_set_value(dev->led_gpio, 0);	/* 打開LED燈 */} else if(ledstat == LEDOFF) {gpio_set_value(dev->led_gpio, 1);	/* 關閉LED燈 */}return 0;
}/** @description		: 關閉/釋放設備* @param - filp 	: 要關閉的設備文件(文件描述符)* @return 			: 0 成功;其他 失敗*/
static int led_release(struct inode *inode, struct file *filp)
{struct gpioled_dev *dev = filp->private_data;/* 釋放互斥鎖 */mutex_unlock(&dev->lock);return 0;
}/* 設備操作函數 */
static struct file_operations gpioled_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = 	led_release,
};/** @description	: 驅動入口函數* @param 		: 無* @return 		: 無*/
static int __init led_init(void)
{int ret = 0;/* 初始化互斥體 */mutex_init(&gpioled.lock);/* 設置LED所使用的GPIO *//* 1、獲取設備節點:gpioled */gpioled.nd = of_find_node_by_path("/gpioled");if(gpioled.nd == NULL) {printk("gpioled node not find!\r\n");return -EINVAL;} else {printk("gpioled node find!\r\n");}/* 2、 獲取設備樹中的gpio屬性,得到LED所使用的LED編號 */gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0);if(gpioled.led_gpio < 0) {printk("can't get led-gpio");return -EINVAL;}printk("led-gpio num = %d\r\n", gpioled.led_gpio);/* 3、設置GPIO1_IO03為輸出,并且輸出高電平,默認關閉LED燈 */ret = gpio_direction_output(gpioled.led_gpio, 1);if(ret < 0) {printk("can't set gpio!\r\n");}/* 注冊字符設備驅動 *//* 1、創建設備號 */if (gpioled.major) {		/*  定義了設備號 */gpioled.devid = MKDEV(gpioled.major, 0);register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);} else {						/* 沒有定義設備號 */alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);	/* 申請設備號 */gpioled.major = MAJOR(gpioled.devid);	/* 獲取分配號的主設備號 */gpioled.minor = MINOR(gpioled.devid);	/* 獲取分配號的次設備號 */}printk("gpioled major=%d,minor=%d\r\n",gpioled.major, gpioled.minor);	/* 2、初始化cdev */gpioled.cdev.owner = THIS_MODULE;cdev_init(&gpioled.cdev, &gpioled_fops);/* 3、添加一個cdev */cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);/* 4、創建類 */gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);if (IS_ERR(gpioled.class)) {return PTR_ERR(gpioled.class);}/* 5、創建設備 */gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);if (IS_ERR(gpioled.device)) {return PTR_ERR(gpioled.device);}return 0;
}/** @description	: 驅動出口函數* @param 		: 無* @return 		: 無*/
static void __exit led_exit(void)
{/* 注銷字符設備驅動 */cdev_del(&gpioled.cdev);/*  刪除cdev */unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); /* 注銷設備號 */device_destroy(gpioled.class, gpioled.devid);class_destroy(gpioled.class);
}module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("huax");

在 open 函數中,調用 mutex_lock_interruptible 或者 mutex_lock 獲取 mutex,成功的話就表示可以使用 LED 燈,失敗的話就會進入休眠狀態,和信號量一樣。

static int led_open(struct inode *inode, struct file *filp)
{filp->private_data = &gpioled; /* 設置私有數據 *//* 獲取互斥體,可以被信號打斷 */if (mutex_lock_interruptible(&gpioled.lock)) {return -ERESTARTSYS;}
#if 0mutex_lock(&gpioled.lock);	/* 不能被信號打斷 */
#endifreturn 0;
}

在 release 函數中,調用 mutex_unlock 函數釋放 mutex,這樣其他應用程序就可以獲取 mutex 了。

static int led_release(struct inode *inode, struct file *filp)
{struct gpioled_dev *dev = filp->private_data;/* 釋放互斥鎖 */mutex_unlock(&dev->lock);return 0;
}

這段代碼里,互斥體關鍵實現如下:

測試mutexApp.c

mutexApp.c測試代碼和之前的一樣,沒有修改。

代碼里模擬占用 25 秒 LED ,測試 APP 在獲取到 LED 燈驅動的使用權以后會使用 25S,在使用的這段時間,如果有其他的應用也去獲取 LED 燈使用權的話肯定會失敗。

代碼如下:

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"#define LEDOFF 	0
#define LEDON 	1/** @description		: main主程序* @param - argc 	: argv數組元素個數* @param - argv 	: 具體參數* @return 			: 0 成功;其他 失敗*/
int main(int argc, char *argv[])
{int fd, retvalue;char *filename;unsigned char cnt = 0;unsigned char databuf[1];if(argc != 3){printf("Error Usage!\r\n");return -1;}filename = argv[1];fd = open(filename, O_RDWR);if(fd < 0){printf("file %s open failed!\r\n", argv[1]);return -1;}databuf[0] = atoi(argv[2]);	/* 要執行的操作:打開或關閉 *//* 向/dev/gpioled文件寫入數據 */retvalue = write(fd, databuf, sizeof(databuf));if(retvalue < 0){printf("LED Control Failed!\r\n");close(fd);return -1;}/* 模擬占用25S LED */while(1) {sleep(5);cnt++;printf("App running times:%d\r\n", cnt);if(cnt >= 5) break;}printf("App running finished!");retvalue = close(fd); /* 關閉文件 */if(retvalue < 0){printf("file %s close failed!\r\n", argv[1]);return -1;}return 0;
}

Makefile 文件

makefile文件只需要修改?obj-m 變量的值,改為mutex.o

KERNELDIR := /home/huax/linux/linux_test/linux-imx-rel_imx_4.1.15_2.1.0_gaCURRENT_PATH := $(shell pwd)
obj-m := mutex.obuild: kernel_modules
kernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

運行測試

編譯代碼:

make -j32 //編譯makefile文件
arm-linux-gnueabihf-gcc mutexApp.c -o mutexApp  //編譯測試程序

編譯成功以后,就會生成一個名為“mutex.ko”的驅動模塊文件,和mutexApp 這個應用程序。

將編譯出來的 mutex.ko 和 mutexApp 這兩個文件拷貝到 根文件 rootfs/lib/modules/4.1.15目錄中,重啟開發板。

進入到目錄 lib/modules/4.1.15 中,輸入如下命令加載 mutex.ko 驅動模塊:

depmod //第一次加載驅動的時候需要運行此命令
modprobe mutex.ko //加載驅動

驅動加載成功以后,就可以使用 mutexApp 軟件測試驅動是否工作正常:

./ mutexApp /dev/gpioled 1& //后臺方式,打開 LED 燈

在打開LED燈25s以內,關閉LED燈會失敗:

./ mutexApp /dev/gpioled 0& //關閉 LED 燈

這兩個命令都是運行在后臺,第一條命令先獲取到互斥體,因此可以操作 LED 燈,將LED 燈打開,并且占有 25S。

第二條命令因為互斥體獲取led資源失敗而進入休眠狀態,等待第一條命令運行完畢并釋放互斥體以后才擁有 LED 燈使用權,將 LED 燈關閉。

要卸載驅動的話輸入如下命令:

rmmod mutex.ko

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

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

相關文章

[4.2-2] NCCL新版本的register如何實現的?

文章目錄1->2->31. ncclRegisterP2pIpcBuffer2. ncclIpcLocalRegisterBuffer(..., 1, 0,...)3. ipcRegisterBuffer(..., regRecord,..., isLegacyIpc)4. p2pProxyRegister()1->2->3 1. ncclRegisterP2pIpcBuffer 在enqueue.cc內的調用是&#xff1a; NCCLCHECK(…

在idea中git切換分支,但是我的文件沒add,沒commit

這是一個很悲傷的故事&#xff0c;我朋友一個下午寫了4個小時的代碼&#xff0c;差不多10多個類&#xff0c;都在切換分支的時候。IDEA發現有沖突&#xff0c;然后就要resolve conflict&#xff0c;發現自己不知道怎么操作&#xff0c;就點了abort & rollback。然后所有代碼…

GPFS api

一、核心命令行 API&#xff08;mm 命令集&#xff09; GPFS 最基礎且常用的接口是命令行工具集&#xff08;以mm為前綴&#xff09;&#xff0c;用于文件系統的創建、配置、管理和監控。這些命令可直接在終端執行&#xff0c;也可通過腳本&#xff08;如 Shell、Python&#…

虛擬機一站式部署Claude Code 可視化UI界面

前言 最近&#xff0c;強大的 AI 編碼助手 Claude Code 在開發者社區中迅速走紅&#xff0c;憑借其出色的代碼生成和理解能力贏得了廣泛贊譽。然而&#xff0c;其純粹基于命令行的交互方式&#xff0c;對于許多習慣了圖形化界面的開發者&#xff0c;尤其是新手而言&#xff0c…

網站IP被劫持?三步自建防護盾

一、劫持檢測實戰&#xff08;Python腳本&#xff09; import requests import socket import ssldef check_hijacking(domain):try:# 獲取真實DNS解析real_ip socket.gethostbyname(domain)# 本地發起請求驗證response requests.get(f"https://{domain}", timeout…

SQL Server從入門到項目實踐(超值版)讀書筆記 23

第三篇 核心應用篇在本章中&#xff0c;將通過案例示范學習SQL Server數據庫的一些核心應用。例如&#xff0c;SQL Server視圖的使用、游標的應用、存儲過程的應用、索引的應用、觸發器的應用、SQL Server事務與鎖的應用等。學完本篇&#xff0c;讀者將對SQL Server數據庫的管理…

功能測試中常見的面試題-一

一、基礎概念與理論題什么是軟件測試&#xff1f;它的目的是什么&#xff1f;回答&#xff1a; 軟件測試是通過人工或自動化手段&#xff0c;運行或評估軟件系統&#xff0c;以驗證它是否滿足規定的需求、識別實際結果與預期結果之間的差異&#xff0c;并評估軟件產品質量的過程…

LINUX88 變量:命令定義;普通數組定義(復);declare -i /-x

問題 [codesamba ~]$ array3(ls axel-2.4) [codesamba ~]$ echo $array3 API [codesamba ~]$ ls axel-2.4 API CHANGES conn.o gui README tcp.o axel conf.c COPYING http.c ru.mo text.c axel.1 …

數字IC后端PPA優化| Timing一致性調整方法和Module Region規劃方法

Q1:直播課經常講到一致性&#xff0c;這個一致性的話一般是指place&#xff0c;CTS和PT的derating time&#xff0c;uncertainty和transition嗎&#xff0c;我大概知道innovus的uncertainty設置要比PT里面高一點&#xff0c;但具體設計時這幾部分的大小應該是一個什么樣的關系或…

電子電氣架構 --- 軟件定義汽車的驅動和挑戰

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 做到欲望極簡,了解自己的真實欲望,不受外在潮流的影響,不盲從,不跟風。把自己的精力全部用在自己。一是去掉多余,凡事找規律,基礎是誠信;二是…

機器學習——10 支持向量機SVM

1 支持向量機 1.1 故事引入看下圖左邊&#xff0c;藍色和紅色的點混在一起&#xff0c;這就像一堆數據&#xff0c;沒辦法用一條簡單的直線把它們分開。再看下圖右邊&#xff0c;有一條直線把藍色和紅色的點分開&#xff0c;這就是SVM在找的“決策邊界”&#xff0c;它能把不同…

若以微服務部署踩坑點

windows docker desktop 部署nacos mysql1、docker部署nacosdocker pull nacos/nacos-server:v2.4.3docker啟動命令 docker run --name nacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 --privilegedtrue --network bridge -e MODEstandalone -e SPRING_DATASOURCE_PLATFORMm…

Lua基礎+Lua數據類型

Lua基礎 Lua介紹 特點&#xff1a;輕量、小巧。C語言開發。開源。 設計的目的&#xff1a;嵌入到應用程序當中&#xff0c;提供靈活的擴展和定制化的功能。 luanginx&#xff0c;luaredis。 環境安裝 windows上安裝lua&#xff1a; 檢查機器上是否有lua C:\Users\cpf>lua lu…

基于VuePress2開發文檔自部署及嵌入VUE項目

最近在搞前端開發幫助文檔&#xff0c;轉了一圈發現Vue提供了一個高性能的、Vue驅動的靜態網站生成框架-VuePress。VuePress 是一個以 Markdown 為中心的靜態網站生成器。你可以使用 Markdown 來書寫內容&#xff08;如文檔、博客等&#xff09;&#xff0c;然后 VuePress 會生…

Flask初步學習

文章目錄一、初識Flask1.1 Pycharm修改環境配置1.2 運行第一個flask項目1.3 獲取數據請求1.3.1 動態路由參數一、初識Flask 1.1 Pycharm修改環境配置 file——settings——project——python Interpreter——add interpreter——add local interpreter 1.2 運行第一個fla…

word的正則替換

word查看選中了幾行 word替換掉空行 替換空行 按下 “Ctrl H” 組合鍵打開 “查找和替換” 對話框&#xff0c;在 “查找內容” 框中輸入 “pp”&#xff0c;“^p” 代表段落標記&#xff0c;兩個 “^p” 表示連續的兩個段落標記&#xff0c;即空行。在 “替換為” 框中輸入 “…

Spring Framework源碼解析——DisposableBean

版權聲明 本文原創作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl一、概述 DisposableBean 是 Spring 框架中用于定義 Bean 銷毀時回調行為的核心接口之一。它提供了一個標準化的鉤子方法 destroy()&#xff0c;允許 Bean 在容器關閉或作用域…

linux安裝和使用git

Linux 上安裝 Git 在 Linux 上安裝 Git&#xff0c;你可以按照以下步驟進行&#xff1a; 打開終端&#xff1a;打開你的 Linux 終端應用程序。通常可以通過在應用程序菜單中搜索 "Terminal" 或 "終端" 來找到它。 更新軟件包列表&#xff1a;運行以下命令…

數字圖像處理4

預處理——ROI——形態學處理形態學處理形態學變化只能在二值圖上處理1.腐蝕Erode對kernel映射的區域做與操作&#xff0c;包括自己在內如果有0則中間賦值成02.膨脹Dilate對kernel映射的區域做或操作&#xff0c;包括自己在內如果有1則中間賦值成13.其他操作開操作&#xff1a;…

Solon v3.4.3 發布(國產 Java 應用開發生態基座)

Solon 框架&#xff01; Solon 是新一代&#xff0c;Java 企業級應用開發框架。從零開始構建&#xff08;No Java-EE&#xff09;&#xff0c;有靈活的接口規范與開放生態。采用商用友好的 Apache 2.0 開源協議&#xff0c;是“杭州無耳科技有限公司”開源的根級項目&#xff…