Linux實現字元裝置驅動的基礎步驟
Linux應用層想要操作kernel層的API,比如想操作相關GPIO或暫存器,可以通過寫一個字元裝置驅動來實現。
1、先在rootfs中的 /dev/ 下生成一個字元裝置。注意主裝置號 和 從裝置號。可用如下shell指令碼生成:
if [ ! -e audioIN ];then
sudo mknod audioIN c 240 0
fi
生成的裝置為 /dev/audioIN ,主裝置號240,從裝置號0。
2、寫audioINdriver.ko ,audioINdriver.c 基本程式碼框架如下:程式碼中定義了裝置名audioIN,裝置號240, 0 ,與之前建立的裝置一致。
/**************************************************************************\
* audioINdriver.c
*
* kang_liu <[email protected]>
* 2014-07-15
\**************************************************************************/
#include <asm/uaccess.h>
#include <asm/errno.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <mach/gpio.h>
//#include <mach/at91_rstc.h> /* debug */
//#include <mach/at91_pmc.h>
//#include <mach/at91_rstc.h>
//#include <mach/at91_shdwc.h>
#include <mach/irqs.h>
//#include "generic.h"
//#include "clock.h"
#include <mach/w55fa92_reg.h>
#include <asm/io.h>
#define DEV_MAJOR 240
#define DEV_MINOR 0
#define NUM_MINORS 1
#define DEVICE_NAME "audioIN"
#define ERR(fmt, args...) printk(KERN_ALERT __FILE__ ": " fmt, ##args)
#define MSG(fmt, args...) printk(KERN_INFO __FILE__ ": " fmt, ##args)
#define DBG(fmt, args...) printk(KERN_DEBUG __FILE__ ": " fmt, ##args)
static ssize_t user_gpio_read(struct file *fp, char __user *buff,
size_t count, loff_t *offp)
{
char str[32] = {0};
char out[32] = {0};
int n, err;
// printk("lk~~~~~~~read buff = %s\n",buff);
err = copy_from_user(str, buff, count);
// printk("lk~~~~~~~read str = %s\n",str);
if (err)
return -EFAULT;
sprintf(out,"return values");
memset(buff, 0, count);
err = copy_to_user(buff, out, sizeof(out));
if (err)
return -EFAULT;
return n;
}
static ssize_t user_gpio_write(struct file *fp, const char __user *buff,
size_t count, loff_t *offp)
{
int err;
char tmp[32];
// printk("lk~~~~~~~write buff = %s\n",buff);
err = copy_from_user(tmp, buff, count);
// printk("lk~~~~~~~write tmp = %s\n",tmp);
if (err)
return -EFAULT;
if('1' == tmp[0])
{
//LINE IN
printk("line in\n");
}
else if('0' == tmp[0])
{
//MIC IN
printk("mic in\n");
}
return count;
}
static ssize_t user_gpio_open(struct inode *inode,struct file *fp)
{
// printk("open gpio devices\n");
return 0;
}
static struct file_operations user_gpio_file_ops =
{
.owner = THIS_MODULE,
.write = user_gpio_write,
.read = user_gpio_read,
.open = user_gpio_open,
};
static struct cdev *dev;
static void __exit user_audioIN_exit(void)
{
printk("exit audioIN\n");
dev_t devno = MKDEV(DEV_MAJOR, DEV_MINOR);
unregister_chrdev_region(devno, NUM_MINORS);
cdev_del(dev);
return;
}
static int __init user_audioIN_init(void)
{
printk("init audioIN\n");
int err = 0;
int i;
dev_t devno = MKDEV(DEV_MAJOR, DEV_MINOR);
err = register_chrdev_region(devno, NUM_MINORS, DEVICE_NAME);
if (err)
goto fail_devno;
dev = cdev_alloc();
dev->ops = &user_gpio_file_ops;
dev->owner = THIS_MODULE;
err = cdev_add(dev, devno, NUM_MINORS);
if (err)
goto fail_cdev;
return err;
fail_cdev:
fail_devno:
unregister_chrdev_region(devno, NUM_MINORS);
fail_gpio:
return err;
}
module_init(user_audioIN_init);
module_exit(user_audioIN_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kang_liu < [email protected]>");
MODULE_DESCRIPTION("Access GSEIO from userspace.");
這裡就可以呼叫kernel層的一些API進行底層的操作。
Makefile:生成audioINdriver.ko
# Comment/uncomment the following line to disable/enable debugging #DEBUG = y BUILD_TOOLS_PRE = arm-linux- CC=$(BUILD_TOOLS_PRE)gcc LD=$(BUILD_TOOLS_PRE)ld # Add your debugging flag (or not) to CFLAGS ifeq ($(DEBUG),y) DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines else DEBFLAGS = -O2 endif KERNEL_DIR = ../../../linux-2.6.35.4 EXTRA_CFLAGS += $(DEBFLAGS) EXTRA_CFLAGS += -I$(LDDINC) EXTRA_CFLAGS +=-I$(KERNEL_DIR)/arch/arm/mach-w55fa92/include EXTRA_CFLAGS +=-I$(KERNEL_DIR)/arch/arm EXTRA_CFLAGS +=-I$(KERNEL_DIR)/arch/arm/include EXTRA_CFLAGS +=-I$(KERNEL_DIR)/arch/arm/include/linux ifneq ($(KERNELRELEASE),) # call from kernel build system audioIN-objs := audioINdriver.o obj-m := audioINdriver.o else KERNELDIR ?= $(KERNEL_DIR) #KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) modules: $(MAKE) ARCH=arm CROSS_COMPILE=$(BUILD_TOOLS_PRE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules endif clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers depend .depend dep: $(CC) $(CFLAGS) -M *.c > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif
3. 生成好 .ko 以後,就可以在ARM板上,載入驅動。
insmod audioINdriver.ko
4、載入驅動成功後,就可以在應用層直接操作裝置 /dev/audioIN,來實現相關功能,將一些引數傳到驅動層,執行相關kernel層的程式碼。
應用層測試程式如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define BUF_LEN 32
int s_audioInFd = 0;
int InitAudioInDevice()
{
s_audioInFd = open("/dev/audioIN",O_RDWR);
if (s_audioInFd > 0)
{
return 1;
}
else
{
printf("Can't open the GSE IO device\n");
return 0;
}
}
void UninitAudioInDevice()
{
if (s_audioInFd > 0)
close(s_audioInFd);
}
int getAudioIn()
{
char buffer[BUF_LEN] = {0};
if (s_audioInFd > 0)
{
memcpy(&buffer[0], "lk_test", 7);
// printf("get buffer = %s\n", buffer);
int len = read(s_audioInFd, buffer, 7);
// printf("get buffer = %s, len = %d\n", buffer, len);
return len;
}
return -1;
}
int setAudioIn(int micLine)
{
char buffer[BUF_LEN] = {0};
if (s_audioInFd > 0)
{
sprintf(buffer, "%d", micLine);
int len = write(s_audioInFd, buffer, sizeof(buffer));
if (len > 0)
return 1;
}
return 0;
}
其中的read 和 write函式,可從驅動中獲取一些返回值,也可將字串傳到驅動中。
驅動的入口為:
module_init(user_audioIN_init);
module_exit(user_audioIN_exit);
相關推薦
Linux實現字元裝置驅動的基礎步驟
Linux應用層想要操作kernel層的API,比如想操作相關GPIO或暫存器,可以通過寫一個字元裝置驅動來實現。 1、先在rootfs中的 /dev/ 下生成一個字元裝置。注意主裝置號 和 從裝置號。可用如下shell指令碼生成: if [ ! -e audioIN
《5.linux驅動開發-第2部分-5.2.字元裝置驅動基礎》
《5.linux驅動開發-第2部分-5.2.字元裝置驅動基礎》 第一部分、章節目錄 5.2.1.開啟驅動開發之路 5.2.2.最簡單的模組原始碼分析1 5.2.3.最簡單的模組原始碼分析2 5.2.4.最簡單的模組原始碼分析3 5.2.5.用開發板來除錯模組 5.2.6.字元裝置驅動工作
19 字元裝置驅動基礎
字元裝置驅動基礎 裝置驅動通常是給使用者程序來呼叫的 最常用的是裝置驅動裡實現字元裝置驅動,實現後在”/dev/”目錄裡提供一個裝置檔案,然後使用者程序就可以通過操作該裝置檔案來呼叫驅動 如pc上的uart裝置檔案: crw-rw—- 1 root dial
linux driver ------ 字元裝置驅動之“ 建立裝置節點流程 ”
在字元裝置驅動開發的入門教程中,最常見的就是用device_create()函式來建立裝置節點了,但是在之後閱讀核心原始碼的過程中卻很少見device_create()的蹤影了,取而代之的是device_register()與device_add(),將device_create()函式展開不難發現:其實de
linux gpio字元裝置驅動
在linux下編寫led驅動,控制相應的gpio管腳。 在這裡有兩種方式 1) 直接操作相應的暫存器 2) 通過核心提供的gpio操作庫函式 第一種方式就省略了,只講第二種方式。 這裡板卡上有兩個led燈,在使用者空間採用兩種方式控制led 1. /dev/led0 /de
linux裝置驅動第三篇:如何實現簡單的字元裝置驅動
在linux裝置驅動第一篇:裝置驅動程式簡介中簡單介紹了字元驅動,本篇簡單介紹如何寫一個簡單的字元裝置驅動。本篇借鑑LDD中的原始碼,實現一個與硬體裝置無關的字元裝置驅動,僅僅操作從核心中分配的一些記憶體。 下面就開始學習如何寫一個簡單的字元裝置驅動。首先我們來分解一下
基礎 字元裝置驅動框架
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <lin
《5.linux驅動開發-第3部分-5.3.字元裝置驅動高階》
《5.linux驅動開發-第3部分-5.3.字元裝置驅動高階》 第一部分、章節目錄 5.3.1.註冊字元裝置驅動新介面1 5.3.2.註冊字元裝置驅動新介面2 5.3.3.註冊字元裝置驅動新介面3 5.3.4.註冊字元裝置驅動新介面4 5.3.5.字元裝置驅動註冊程式碼分析1 5.3.6
20 字元裝置驅動相關的函式和引數及實現(虛擬檔案)
字元裝置驅動相關的函式和引數及實現(虛擬檔案) 使用者程序呼叫函式順序: open ---> kernel ---> cdev.ops->open(..) read ---> kernel ---> cdev.ops->read(
14 Linux裝置驅動基礎程式設計
Linux裝置驅動基礎程式設計 核心功能模組:程序排程,記憶體管理(mmu,分配程序記憶體),檔案系統管理(如:支援的檔案系統格式),裝置驅動(硬體驅動由核心來統一管理),網路協議棧。 模組機制: 靜態載入:把驅動模組編進核心,在核心啟動時自動載入。 動態載入:把驅動模
13 Linux裝置驅動基礎知識
Linux裝置驅動基礎知識 驅動是硬體與使用者程序之間的通訊橋樑。 使用者程序是不可以直接訪問硬體的。 資料是驅動先接收到硬體反饋的資料處理後再移交給使用者程序的。 驅動不屬於任何一個使用者程序,可以給多個使用者程序呼叫。 驅動是常駐於記憶體裡,等待使用者程序呼叫。
Linux字元裝置驅動模型--字元裝置的註冊
當我們編寫字元裝置驅動程式的時候,在進行字元裝置物件cdev的分配、初始化,裝置號的註冊這些初始化階段之後,就可以將它加入到系統中,這樣才能使用這個字元裝置。將一個字元裝置加入到系統中呼叫的函式時cdev_add,核心原始碼如下: int cdev_add(struct cdev *
Linux 字元裝置驅動結構(二)—— 自動建立裝置節點
上一篇我們介紹到建立裝置檔案的方法,利用cat /proc/devices檢視申請到的裝置名,裝置號。 第一種是使用mknod手工建立:mknod filename type major minor 第二種是自動建立裝置節點:利用u
Linux 字元裝置驅動結構(一)—— cdev 結構體、裝置號相關知識解析
一、字元裝置基礎知識 1、裝置驅動分類 linux系統將裝置分為3類:字元裝置、塊裝置、網路裝置。使用驅動程式: 字元裝置:是指只能一個位元組一個位元組讀寫的裝置,不能隨機讀取裝置記憶體中的某一資料,讀取資料需要按照先後資料。
字元裝置驅動-------Linux異常處理體系結構
裸機中斷流程 外部觸發 CPU 發生中斷, 強制的跳到異常向量處 跳轉到具體函式 儲存被中斷處的現場(各種暫存器的值) 執行中斷處理函式,處理具體任務 恢復被中斷的現場 Linux處理異常流程 異常發生時,會去異常向量表找到入口
Linux 裝置驅動--- 阻塞型字元裝置驅動 --- O_NONBLOCK --- 非阻塞標誌
阻塞: 在設計簡單字元驅動程式時,要注意一個重要問題. 當一個裝置無法立刻滿足使用者的讀寫請求時應當如何處理?
Linux字元裝置驅動註冊三種方法以及核心分析
Linux驅動是使用者訪問底層硬體的橋樑,驅動有可以簡單分成三類:字元裝置、塊裝置、網路裝置。其中最多的是字元裝置,其中字元裝置的註冊方法主要有三種:雜項設備註冊、早期字元設備註冊、標準字元設備註冊。以及詳細介紹各類方法註冊。 開發環境: PC:WMwork
Linux裝置驅動之字元裝置驅動---轉
一、linux系統將裝置分為3類:字元裝置、塊裝置、網路裝置。 應用程式呼叫的流程框圖: 三種裝置的定義分別如下, 字元裝置:只能一個位元組一個位元組的讀寫的裝置,不能隨機讀取裝置記憶體中的某一資料,讀取資料需要按照先後順序進行。字元裝置是面向流的裝置,常見的字
linux字元裝置驅動模型
一.雜項裝置驅動模型 雜項的主裝置號固定為10,只有255個次裝置號。可以直接生成驅動核心。 1.需要確定每個模型都會用到的檔案操作方法集合指標 2.確定核心的結構體 static struct miscdevice abc 確定三個引數,第一個為次裝置號,第二個是次裝
Linux裝置驅動程式學習(基於2440的GPIO字元裝置驅動)
GPIO驅動程式如下: #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> #include <li