《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.字元裝置驅動註冊程式碼分析2
5.3.7.自動建立字元裝置驅動的裝置檔案
5.3.8.裝置類相關程式碼分析1
5.3.9.裝置類相關程式碼分析2
5.3.10.靜態對映表建立過程分析
5.3.11.動態對映結構體方式操作暫存器
5.3.12.核心提供的讀寫暫存器介面
第二部分、章節介紹
5.3.1.註冊字元裝置驅動新介面1
本節介紹核心中提供的字元裝置驅動註冊的新介面cdev,並且講了相關的介面函式,最後實踐編寫程式碼。
5.3.2.註冊字元裝置驅動新介面2
本節對上節講述的知識進行實踐程式設計測試。
5.3.3.註冊字元裝置驅動新介面3
本節講述新介面如何自動分配裝置號,以及其他一些程式設計細節如錯誤的逐級處理技巧。
5.3.4.註冊字元裝置驅動新介面4
本節講述cdev_alloc和cdev_init這兩個介面,同時引申講解了C語言如何以面向物件的程式設計方式來實現linux核心。
5.3.5.字元裝置驅動註冊程式碼分析1
本節帶大家瀏覽分析核心原始碼中與字元裝置驅動相關的介面,使用SourceInsight逐級追蹤的方式進入核心原始碼中。
5.3.6.字元裝置驅動註冊程式碼分析2
本節繼續上節分析字元裝置驅動註冊相關的介面函式,目的是教大家學習如何從原始碼中去學習。
5.3.7.自動建立字元裝置驅動的裝置檔案
本節實踐程式設計演示如何使用class_create和device_create這兩個介面來讓字元裝置驅動藉助裝置類自動建立及刪除裝置檔案。
5.3.8.裝置類相關程式碼分析1
本節開始分析class_create和device_create內部的實現原理。
5.3.9.裝置類相關程式碼分析2
本節接上節繼續分析,通過分析讓大家對sysfs有所瞭解,知曉核心如果通過sysfs和udev進行通訊以實現裝置檔案的自動建立和刪除。
5.3.10.靜態對映表建立過程分析
本節分析核心原始碼中與虛擬地址靜態對映建立有關的程式碼,通過分析大家可以進一步掌握靜態對映的實現細節。
5.3.11.動態對映結構體方式操作暫存器
本節對5.2.17中使用動態對映方式得到多個暫存器虛擬地址的程式碼進行改進,使用結構體封裝的方式讓我們能夠方便的對映多個暫存器。
5.3.12.核心提供的讀寫暫存器介面
本節介紹核心提供的writel/readl和iowrite32/ioread32等讀寫暫存器的介面,並且對之前的驅動進行改進,和核心中典型的驅動程式進行對比學習。
第三部分、隨堂記錄
5.3.1.註冊字元裝置驅動新介面1
5.3.1.1、新介面與老介面
(1)老介面:register_chrdev
(2)新介面:register_chrdev_region/alloc_chrdev_region + cdev
(3)為什麼需要新介面
5.3.1.2、cdev介紹
(1)結構體
(2)相關函式:cdev_alloc、cdev_init、cdev_add、cdev_del
5.3.1.3、裝置號
(1)主裝置號和次裝置號
(2)dev_t型別
(3)MKDEV、MAJOR、MINOR三個巨集
5.3.1.4、程式設計實踐
(1)使用register_chrdev_region + cdev_init + cdev_add進行字元裝置驅動註冊
#ubuntu的核心原始碼樹,如果要編譯在ubuntu中安裝的模組就開啟這2個
#KERN_VER = $(shell uname -r)
#KERN_DIR = /lib/modules/$(KERN_VER)/build
# 開發板的linux核心的原始碼樹目錄
KERN_DIR = /root/driver/kernel
obj-m += module_test.o
all:
make -C $(KERN_DIR) M=`pwd` modules
arm-linux-gcc app.c -o app
cp:
cp *.ko /root/porting_x210/rootfs/rootfs/ driver_test
cp app /root/porting_x210/rootfs/rootfs/driver_test
.PHONY: clean
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf app
#include <linux/module.h> // module_init module_exit
#include <linux/init.h> // __init __exit
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h> // arch/arm/mach-s5pv210/include/mach/gpio-bank.h
#include <linux/string.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/cdev.h>
#define MYMAJOR 200
#define MYCNT 1
#define MYNAME "testchar"
#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DAT
#define rGPJ0CON *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT)
#define GPJ0CON_PA 0xe0200240
#define GPJ0DAT_PA 0xe0200244
unsigned int *pGPJ0CON;
unsigned int *pGPJ0DAT;
//**********************************************/
int mymajor;
static dev_t mydev;
static struct cdev test_cdev;
//***********************************************/
char kbuf[100]; // 核心空間的buf
static int test_chrdev_open(struct inode *inode, struct file *file)
{
// 這個函式中真正應該放置的是開啟這個裝置的硬體操作程式碼部分
// 但是現在暫時我們寫不了這麼多,所以用一個printk列印個資訊來做代表。
printk(KERN_INFO "test_chrdev_open\n");
rGPJ0CON = 0x11111111;
rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5)); // 亮
return 0;
}
static int test_chrdev_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "test_chrdev_release\n");
rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
return 0;
}
ssize_t test_chrdev_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
{
int ret = -1;
printk(KERN_INFO "test_chrdev_read\n");
ret = copy_to_user(ubuf, kbuf, count);
if (ret)
{
printk(KERN_ERR "copy_to_user fail\n");
return -EINVAL;
}
printk(KERN_INFO "copy_to_user success..\n");
return 0;
}
// 寫函式的本質就是將應用層傳遞過來的資料先複製到核心中,然後將之以正確的方式寫入硬體完成操作。
static ssize_t test_chrdev_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
int ret = -1;
printk(KERN_INFO "test_chrdev_write\n");
// 使用該函式將應用層傳過來的ubuf中的內容拷貝到驅動空間中的一個buf中
//memcpy(kbuf, ubuf); // 不行,因為2個不在一個地址空間中
memset(kbuf, 0, sizeof(kbuf));
ret = copy_from_user(kbuf, ubuf, count);
if (ret)
{
printk(KERN_ERR "copy_from_user fail\n");
return -EINVAL;
}
printk(KERN_INFO "copy_from_user success..\n");
if (kbuf[0] == '1')
{
rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
}
else if (kbuf[0] == '0')
{
rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
}
return 0;
}
//*****************************************************************************/
// 自定義一個file_operations結構體變數,並且去填充
static const struct file_operations test_fops = {
.owner = THIS_MODULE, // 慣例,直接寫即可
.open = test_chrdev_open, // 將來應用open開啟這個裝置時實際呼叫的
.release = test_chrdev_release, // 就是這個.open對應的函式
.write = test_chrdev_write,
.read = test_chrdev_read,
};
//*****************************************************************************/
static int __init chrdev_init(void)
{
int retval;
printk(KERN_INFO "chrdev_init helloworld init\n");
// 使用新的cdev介面來註冊字元裝置驅動
// 新的介面註冊字元裝置驅動需要2步
//*****************************************************************************/
* // 第1步:註冊/分配主次裝置號
* mydev = MKDEV(MYMAJOR, 0);
* retval = register_chrdev_region(mydev, MYCNT, MYNAME);
* if (retval) {
* printk(KERN_ERR "Unable to register minors for %s\n", MYNAME);
* return -EINVAL;
* }
* printk(KERN_INFO "register_chrdev_region success\n");
* // 第2步:註冊字元裝置驅動
* cdev_init(&test_cdev, &test_fops);
* retval = cdev_add(&test_cdev, mydev, MYCNT);
* if (retval) {
* printk(KERN_ERR "Unable to cdev_add\n");
* return -EINVAL;
* }
* printk(KERN_INFO "cdev_add success\n");
//*****************************************************************************/
// 使用動態對映的方式來操作暫存器
if (!request_mem_region(GPJ0CON_PA, 4, "GPJ0CON"))
return -EINVAL;
if (!request_mem_region(GPJ0DAT_PA, 4, "GPJ0CON"))
return -EINVAL;
pGPJ0CON = ioremap(GPJ0CON_PA, 4);
pGPJ0DAT = ioremap(GPJ0DAT_PA, 4);
*pGPJ0CON = 0x11111111;
*pGPJ0DAT = ((0<<3) | (0<<4) | (0<<5)); // 亮
return 0;
}
// 模組下載函式
static void __exit chrdev_exit(void)
{
printk(KERN_INFO "chrdev_exit helloworld exit\n");
*pGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
// 解除對映
iounmap(pGPJ0CON);
iounmap(pGPJ0DAT);
release_mem_region(GPJ0CON_PA, 4);
release_mem_region(GPJ0DAT_PA, 4);
/*
// 在module_exit巨集呼叫的函式中去登出字元裝置驅動
unregister_chrdev(mymajor, MYNAME);
*/
//*****************************************************************************/
// 使用新的介面來登出字元裝置驅動
// 登出分2步:
// 第一步真正登出字元裝置驅動用cdev_del
cdev_del(&test_cdev);
// 第二步去登出申請的主次裝置號
unregister_chrdev_region(mydev, MYCNT);
//*****************************************************************************/
}
module_init(chrdev_init);
module_exit(chrdev_exit);
// MODULE_xxx這種巨集作用是用來新增模組描述資訊
MODULE_LICENSE("GPL"); // 描述模組的許可證
MODULE_AUTHOR("aston"); // 描述模組的作者
MODULE_DESCRIPTION("module test"); // 描述模組的介紹資訊
MODULE_ALIAS("alias xxx"); // 描述模組的別名資訊
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define FILE "/dev/test" // 剛才mknod建立的裝置檔名
char buf[100];
int main(void)
{
int fd = -1;
int i = 0;
fd = open(FILE, O_RDWR);
if (fd < 0)
{
printf("open %s error.\n", FILE);
return -1;
}
printf("open %s success..\n", FILE);
/*
// 讀寫檔案
write(fd, "on", 2);
sleep(2);
write(fd, "off", 3);
sleep(2);
write(fd, "on", 2);
sleep(2);
*/
/*
write(fd, "1", 1);
sleep(2);
write(fd, "0", 1);
sleep(2);
write(fd, "1", 1);
sleep(2);
*/
while (1)
{
memset(buf, 0 , sizeof(buf));
printf("請輸入 on | off \n");
scanf("%s", buf);
if (!strcmp(buf, "on"))
{
write(fd, "1", 1);
}
else if (!strcmp(buf, "off"))
{
write(fd, "0", 1);
}
else if (!strcmp(buf, "flash"))
{
for (i=0; i<3; i++)
{
write(fd, "1", 1);
sleep(1);
write(fd, "0", 1);
sleep(1);
}
}
else if (!strcmp(buf, "quit"))
{
break;
}
}
// 關閉檔案
close(fd);
return 0;
}
5.3.2.註冊字元裝置驅動新介面2
5.3.2.1、實踐程式設計
5.3.2.2、測試
5.3.3.註冊字元裝置驅動新介面3
5.3.2.1、使用alloc_chrdev_region自動分配裝置號
(1)register_chrdev_region是在事先知道要使用的主、次裝置號時使用的;要先檢視cat /proc/devices去檢視沒有使用的。
(2)更簡便、更智慧的方法是讓核心給我們自動分配一個主裝置號,使用alloc_chrdev_region就可以自動分配了。
(3)自動分配的裝置號,我們必須去知道他的主次裝置號,否則後面沒法去mknod建立他對應的裝置檔案。
5.3.2.2、得到分配的主裝置號和次裝置號
(1)使用MAJOR巨集和MINOR巨集從dev_t得到major和minor
(2)反過來使用MKDEV巨集從major和minor得到dev_t。
(3)使用這些巨集的程式碼具有可移植性
5.3.2.3、中途出錯的倒影式錯誤處理方法
(1)核心中很多函式中包含了很多個操作,這些操作每一步都有可能出錯,而且出錯後後面的步驟就沒有進行下去的必要性了。
#ubuntu的核心原始碼樹,如果要編譯在ubuntu中安裝的模組就開啟這2個
#KERN_VER = $(shell uname -r)
#KERN_DIR = /lib/modules/$(KERN_VER)/build
# 開發板的linux核心的原始碼樹目錄
KERN_DIR = /root/driver/kernel
obj-m += module_test.o
all:
make -C $(KERN_DIR) M=`pwd` modules
arm-linux-gcc app.c -o app
cp:
cp *.ko /root/porting_x210/rootfs/rootfs/driver_test
cp app /root/porting_x210/rootfs/rootfs/driver_test
.PHONY: clean
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf app
#include <linux/module.h> // module_init module_exit
#include <linux/init.h> // __init __exit
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h> // arch/arm/mach-s5pv210/include/mach/gpio-bank.h
#include <linux/string.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/cdev.h>
//#define MYMAJOR 200
#define MYCNT 1
#define MYNAME "testchar"
#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DAT
#define rGPJ0CON *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT)
#define GPJ0CON_PA 0xe0200240
#define GPJ0DAT_PA 0xe0200244
unsigned int *pGPJ0CON;
unsigned int *pGPJ0DAT;
//int mymajor;
static dev_t mydev;
static struct cdev test_cdev;
char kbuf[100]; // 核心空間的buf
static int test_chrdev_open(struct inode *inode, struct file *file)
{
// 這個函式中真正應該放置的是開啟這個裝置的硬體操作程式碼部分
// 但是現在暫時我們寫不了這麼多,所以用一個printk列印個資訊來做代表。
printk(KERN_INFO "test_chrdev_open\n");
rGPJ0CON = 0x11111111;
rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5)); // 亮
return 0;
}
static int test_chrdev_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "test_chrdev_release\n");
rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
return 0;
}
ssize_t test_chrdev_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
{
int ret = -1;
printk(KERN_INFO "test_chrdev_read\n");
ret = copy_to_user(ubuf, kbuf, count);
if (ret)
{
printk(KERN_ERR "copy_to_user fail\n");
return -EINVAL;
}
printk(KERN_INFO "copy_to_user success..\n");
return 0;
}
// 寫函式的本質就是將應用層傳遞過來的資料先複製到核心中,然後將之以正確的方式寫入硬體完成操作。
static ssize_t test_chrdev_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
int ret = -1;
printk(KERN_INFO "test_chrdev_write\n");
// 使用該函式將應用層傳過來的ubuf中的內容拷貝到驅動空間中的一個buf中
//memcpy(kbuf, ubuf); // 不行,因為2個不在一個地址空間中
memset(kbuf, 0, sizeof(kbuf));
ret = copy_from_user(kbuf, ubuf, count);
if (ret)
{
printk(KERN_ERR "copy_from_user fail\n");
return -EINVAL;
}
printk(KERN_INFO "copy_from_user success..\n");
if (kbuf[0] == '1')
{
rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
}
else if (kbuf[0] == '0')
{
rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
}
/*
// 真正的驅動中,資料從應用層複製到驅動中後,我們就要根據這個資料
// 去寫硬體完成硬體的操作。所以這下面就應該是操作硬體的程式碼
if (!strcmp(kbuf, "on"))
{
rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
}
else if (!strcmp(kbuf, "off"))
{
rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
}
*/
return 0;
}
// 自定義一個file_operations結構體變數,並且去填充
static const struct file_operations test_fops = {
.owner = THIS_MODULE, // 慣例,直接寫即可
.open = test_chrdev_open, // 將來應用open開啟這個裝置時實際呼叫的
.release = test_chrdev_release, // 就是這個.open對應的函式
.write = test_chrdev_write,
.read = test_chrdev_read,
};
相關推薦
《linux驅動開發-第11部分-5.11.網路裝置驅動介紹》
《linux驅動開發-第11部分-5.11.網路裝置驅動介紹》
第一部分、章節目錄 5.11.1.網路裝置驅動概述 5.11.2.虛擬網絡卡驅動分析1 5.11.3.虛擬網絡卡驅動分析2 5.11.4.DM9000驅動原始碼分析1 5.11.5.DM9000驅動原始碼分析2
第二部分
《5.linux驅動開發-第10部分-5.10.塊裝置驅動介紹》
《5.linux驅動開發-第10部分-5.10.塊裝置驅動介紹》
第一部分、章節目錄 5.10.1.正確理解塊裝置驅動的概念 5.10.2.塊裝置驅動框架簡介 5.10.3.塊裝置驅動案例分析1 5.10.4.塊裝置驅動案例分析2 5.10.5.塊裝置驅動案例分析3
第二部分、章節介
《5.linux驅動開發-第7部分-5.7.framebuffer驅動詳解》
《5.linux驅動開發-第7部分-5.7.framebuffer驅動詳解》
第一部分、章節目錄 5.7.1.framebuffer介紹 5.7.2.framebuffer應用程式設計實踐1 5.7.3.framebuffer應用程式設計實踐2 5.7.4.framebuffer應用程式
《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》
《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》
第一部分、章節目錄 5.6.1.板載蜂鳴器驅動測試 5.6.2.misc類裝置介紹 5.6.3.misc驅動框架原始碼分析1 5.6.4.misc驅動框架原始碼分析2 5.6.5.蜂鳴器驅動原始碼分析1 5.6.6
《5.linux驅動開發-第4部分-5.4.驅動框架入門之LED》
《5.linux驅動開發-第4部分-5.4.驅動框架入門之LED》
第一部分、章節目錄 5.4.1.何謂驅動框架 5.4.2.核心驅動框架中LED的基本情況 5.4.3.初步分析led驅動框架原始碼1 5.4.4.初步分析led驅動框架原始碼2 5.4.5.在核心中新增或去除某個驅動 5
《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.字元裝置驅動工作
《5.linux驅動開發-第1部分-5.1.驅動應該怎麼學》
《5.linux驅動開發-第1部分-5.1.驅動應該怎麼學》
第一部分、章節目錄 5.1.1.什麼是驅動1 5.1.2.什麼是驅動2 5.1.3.模組化設計 5.1.4.linux裝置驅動分類 5.1.5.驅動程式的安全性要求 5.1.6.驅動應該這麼學
第二部分、章節介紹 5.1.
Linux裝置驅動程式學習(基於2440的GPIO字元裝置驅動)
GPIO驅動程式如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <li
《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
《5.linux驅動開發-第5部分-5.8.input子系統基礎之按鍵》
《5.linux驅動開發-第5部分-5.8.input子系統基礎之按鍵》
第一部分、章節目錄 5.8.1.什麼是input子系統 5.8.2.input裝置應用層程式設計實踐1 5.8.3.input裝置應用層程式設計實踐2 5.8.4.input子系統架構總覽1 5.8.5.input
《5.linux驅動開發-第5部分-5.5.linux裝置驅動模型》
《5.linux驅動開發-第5部分-5.5.linux裝置驅動模型》
第一部分、章節目錄 5.5.1.linux裝置驅動模型簡介 5.5.2.裝置驅動模型的底層架構 5.5.3.匯流排式裝置驅動組織方式 5.5.4.platform平臺匯流排簡介1 5.5.5.platform平臺匯流排
求(3+開根5) N次方的整數部分最後3位
\n using include none scan alt tdi typedef fine 求(3+開根5) N次方的整數部分最後3位,請補足前導零 。
分析:首先(1)=(3+開根5) N次方的展開為 an + bn * 根號5 的形式 。 同時也有 (2)=
linux操作指令 第三部分
groupdel 手動 左右 del cat pass useradd user 用戶操作 文件簡單操作
1.文件內容查看 > cat filename //一次性把全部內容都輸出到終端 > more filename
linux驅動開發(三) 字符設備驅動框架(自動創建設備節點)
The module __line__ mage fail goto div on() sys 代碼如下
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ke
《2.uboot和系統移植-第3部分-2.3.零距離初體驗uboot》
《2.uboot和系統移植-第3部分-2.3.零距離初體驗uboot》
第一部分、章節目錄 2.3.1_2.X210官方uboot配置編譯實踐 2.3.3.uboot的原始碼目錄分析1 2.3.4.uboot的原始碼目錄分析2 2.3.5.uboot的原始碼目錄分析3 2.3.6.Sou
遷移 Linux 系統,第 1 部分 如何遷移備份和裸機恢復 Linux 系統
當硬體升級,更換儲存裝置或是遇到硬體故障時,需要遷移原來的作業系統及應用軟體到新的硬體裝置上。這個過程包含系統的遷移備份和裸機恢復,本文詳細描述了整個過程的細節。
災
難恢復 ,
指自然或人為災害後,重新啟用資訊系統的資料、硬體及軟體裝置,恢復正常商業運作的過程。災難恢復是
ZYNQ Linux驅動開發——第一個字元裝置驅動
硬體平臺:XCZ7020 CLG484-1 完全適配Zedboard
開發環境:Widows下Vivado 2016.2 、 SDK2016.2 、 Linux機器:debin
目的:操作板載的LED燈LD9,受PS部分的MIO7控制
linux裝置驅
linux裝置驅動第三篇:寫一個簡單的字元裝置驅動
在linux裝置驅動第一篇:裝置驅動程式簡介中簡單介紹了字元驅動,本篇簡單介紹如何寫一個簡單的字元裝置驅動。本篇借鑑LDD中的原始碼,實現一個與硬體裝置無關的字元裝置驅動,僅僅操作從核心中分配的一些記憶體。
下面就開始學習如何寫一個簡單的字元裝置驅動。首先我們來分解一下字元
linux驅動開發10之misc及蜂鳴器驅動
1.板載蜂鳴器驅動測試
1.1驅動部分
1)九鼎移植核心已經提供了蜂鳴器驅動原始碼
2)make menuconfig
3)bug排查。修改Makefile中的巨集名,最終可以在系統中看到 /dev/buzzer
由於makefile檔案與Kconfig檔案中的
從零開始寫linux字元裝置驅動程式(一)(基於友善之臂tiny4412開發板)
從這篇博文開始,我將開始手把手教會大家寫linux裝置驅動程式這是開篇,如何來寫第一個字元裝置驅動程式。首先,寫一個最簡單的字元裝置驅動程式需要什麼?或者說我們需要了解什麼?1、每一個字元裝置至少需要有一個裝置號2、裝置號 = 主裝置號 + 次裝置號3、同一類裝置的主裝置號一