當(dāng)前位置:首頁(yè) > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 學(xué)習(xí)筆記 > linux字符設(shè)備驅(qū)動(dòng)框架及編寫流程
流程:
init
{
}
exit
{
}
申請(qǐng)?jiān)O(shè)備號(hào) (動(dòng)態(tài)注冊(cè)/靜態(tài)注冊(cè)) 創(chuàng)建一個(gè)字符設(shè)備 cdev_alloc
初始化字符設(shè)備 cdev_init
設(shè)備號(hào)和字符設(shè)備關(guān)聯(lián) cdev_add
銷毀字符設(shè)備 cdev_del
解注冊(cè)設(shè)備號(hào) unregister_chrdev_region
1 設(shè)備號(hào)
設(shè)備號(hào)分為主設(shè)備號(hào)和次設(shè)備號(hào)主設(shè)備號(hào)表示一類設(shè)備
次設(shè)備號(hào)表示一類設(shè)備中的一個(gè)設(shè)備
#include
#define MINORMASK ((1U << MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) typedef u_long dev_t;
2 申請(qǐng)?jiān)O(shè)備號(hào)
靜態(tài)注冊(cè)
#include
extern int register_chrdev_region(dev_t, unsigned, const char *);
函數(shù)實(shí)現(xiàn)在char_dev.c
int register_chrdev_region(dev_t from, unsigned count, const char *name)
from : 設(shè)備號(hào) 通過(guò) MKDEV 生成count : 子設(shè)備個(gè)數(shù)
name : 設(shè)備名
返回值: 成功返回0, 失敗返回負(fù)數(shù)錯(cuò)誤碼
動(dòng)態(tài)注冊(cè)
#include
extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name) dev : 設(shè)備號(hào)指針
baseminor : 子設(shè)備第一個(gè)編號(hào)count : 子設(shè)備個(gè)數(shù)
name : 設(shè)備名
返回值: 成功返回0, 失敗返回負(fù)數(shù)錯(cuò)誤碼
注銷設(shè)備號(hào)
#include
void unregister_chrdev_region(dev_t from, unsigned count) from : 設(shè)備號(hào)
count: 子設(shè)備個(gè)數(shù)
3 創(chuàng)建字符設(shè)備
struct cdev *cdev_alloc(void)
分配一個(gè)cdev結(jié)構(gòu)體,使用此結(jié)構(gòu)體描述一個(gè)字符設(shè)備成功返回一個(gè)指針,否則返回NULL
#include
void cdev_del(struct cdev *p) 刪除字符設(shè)備結(jié)構(gòu)體#include
void cdev_init(struct cdev *cdev, const struct file_operations
*fops)
初始化一個(gè)字符設(shè)備
cdev :被初始化的字符設(shè)備指針fops :字符設(shè)備操作函數(shù)指針集
int cdev_add(struct cdev *p, dev_t dev, unsigned count) 講字符設(shè)備添加到內(nèi)核
體指針
p :字符設(shè)備結(jié)構(gòu)體指針,cdev_alloc函數(shù)成功返回的結(jié)構(gòu)
dev : 設(shè)備號(hào) 通過(guò)動(dòng)態(tài)或靜態(tài)成功分配的設(shè)備號(hào)count :子設(shè)備個(gè)數(shù)
返回值:成功返回0, 出錯(cuò)返回負(fù)數(shù)的錯(cuò)誤碼
4 創(chuàng)建設(shè)備文件
sudo mknod /dev/haha0 c 250 0
/dev/haha0 創(chuàng)建的子設(shè)備文件名
c 字符設(shè)備
250 主設(shè)備號(hào)
0 次設(shè)備號(hào)
會(huì)在 /dev 下創(chuàng)建一個(gè)haha0的一個(gè)字符設(shè)備文件,主設(shè)備號(hào)
250,次設(shè)備號(hào)0
5 數(shù)據(jù)拷貝
char user *buf : user 指用戶空間的指針
從內(nèi)核空間向用戶空間拷貝數(shù)據(jù)
static inline long copy_to_user(void user *to, const void *from, unsigned long n)
to :用戶空間指針( user) from :數(shù)據(jù)源
n :拷貝的字節(jié)數(shù)返回值 0 成功
從用戶空間向內(nèi)核空間拷貝數(shù)據(jù)
static inline long copy_from_user(void *to, const void user * from, unsigned long n) to :內(nèi)核buf指針
form:用戶空間數(shù)據(jù)源指針n : 拷貝字節(jié)數(shù)
返回值 0 成功
注:字符設(shè)備驅(qū)動(dòng)測(cè)試步驟:
1 編譯出hello.ko(make)和test 2 sudo insmod hello.ko
3 cat /proc/devices 查看設(shè)備號(hào)
4 sudo mknod /dev/haha0 c 250 0
5 sudo ./test
如果打印open /dev/haha0 ok 則驅(qū)動(dòng)正常否則驅(qū)動(dòng)有錯(cuò),需改正
6 sudo rmmod hello
7 sudo rm -rf /dev/haha0