字元裝置驅動

2022-07-08 04:54:13 字數 4819 閱讀 9754

一、早期的註冊方式

register_chrdev 函式族 + 建立裝置類、檔案的函式, 這種方式在 2.4版本的核心中使用,其優點是簡單,缺點是沒辦法指定次裝置號

registe_chrdev 函式族

int register_chrdev(unsigned int major, const

char *name,const

struct file_operations *fops)

/**函式作用: 為字元裝置註冊乙個主號碼

*引數1: 嘗試指定的主裝置號,傳入0則動態分配

*引數2: 裝置的標識名稱

*引數3: 與此裝置關聯的檔案操作

*/int unregister_chrdev(const

char* name, const

struct file_operations *fops)

/**函式作用: 登出裝置號

*引數1: 裝置標識名

*引數2: 與此裝置關聯的檔案操作

*/

二、cdev註冊方式2.6版本以後的核心中使用這種方式來註冊裝置驅動,優點是使用者可以自行設定主次裝置號,缺點是這種註冊方式相比於早期的更加複雜,函式更多

使用乙個結構體 cdev 來描述乙個裝置,結構體包含dev_t 型別的裝置號和 與裝置關聯的檔案操作集合 file_operations 結構體,file_operations和老版本相同

裝置號: 主裝置號表示乙個特定的驅動程式,次裝置號表示使用該驅動程式的不同裝置

32位無符號整型,12位用來表示主裝置號,20位用來表示次裝置號

例如:led驅動對應乙個主裝置號,兩個想要單獨控制的led裝置對應次裝置號1和2

struct

cdev ;

主從裝置號在核心中有乙個u32型別的變數儲存

---------------------------------typedef __u32 __kernel_dev_t;

typedef __kernel_dev_t dev_t;

cdev編寫字元驅動框架

使用到的系統函式

//

1. 註冊裝置號(靜態, 使用者指定)

int register_chrdev_region(dev_t from, unsigned int count, conster char*name)

/** from: 要分配的裝置編號範圍的初始值(主裝置號,次裝置號常設定為0)

* count: 連續編號範圍

*///

2. 註冊裝置號(動態)

int alloc_chrdev_region(dev_t* dev, unsigned int firstminor, unsigned int count, char *name)

/** dev:呼叫該函式申請下來的裝置號

* firstminor: 次裝置號的起始,請求使用的第乙個次裝置號

* count: 申請次裝置號的總數

* name: 裝置名

*分配失敗返回0

*/可以在驅動程式中通過major和minor 巨集,把主次裝置號列印出來,不然mknod的時候, 無法知道系統自動分配的裝置號

makdev(major, minor); //將主裝置號和此裝置號轉換成乙個主次裝置號

major(devid);      //獲取主裝置號

minor(devid);      //獲取次裝置號

//3. 初始化cdev

cdev_init(struct cdev* cdev, const

struct file_operations*fops)

/**cdev cdev結構體型別指標

*fops :與此裝置關聯的檔案操作

*///

4. 註冊cdev

cdev_add(struct cdev*p, dev_t dev, unsigned count)

/**p: cdev結構體

*dev: 裝置號

*count: 次裝置的個數

*///

5. 刪除cdev

cdev_del(struct cdev *p)

//6. 登出裝置號

void unregister_chrdev_region(dev_t from, unsigned int

count)

/**from: 第乙個裝置號

*count:申請的裝置數量

*/

這裡我們就靜態註冊以及動態註冊單獨兩個申請函式做分析

靜態註冊:

#define led_major 520

#define led_minor 0

static

dev_t devno;

struct

cdev cdev;

struct file_operations fops =;

int __init led_init(void

)

//初始化cdev結構體

cdev_init(devno, &fops);

cdev.owner =this_module;

cdev.ops = &fops

//註冊字元裝置

cdev_add(&cdev, devno, 1

);

return

0;

}

void __exit led_exit(void

)

動態註冊:

static

dev_t devno;

struct

cdev cdev;

struct file_operations fops =;

int __init led_init(void

)

//初始化cdev結構體

cdev_init(devno, &fops);

cdev.owner =this_module;

cdev.ops = &fops

//註冊字元裝置

cdev_add(&cdev, devno, 1

);

return

0;

}

void __exit led_exit(void

)

呼叫系統api,生成裝置節點

class_create   class_device_create

用動態申請裝置號的做示例

static

dev_t devno;

struct

cdev cdev;

struct file_operations fops =;

int __init led_init(void

)

//初始化cdev結構體

cdev_init(devno, &fops);

cdev.owner =this_module;

cdev.ops = &fops

//註冊字元裝置

cdev_add(&cdev, devno, 1

);

struct

class *led_class = class_create(this_module, "

led"

); class_device_create(led_class, null, devno, null,

"led0");

return

0;

}

void __exit led_exit(void

)

三、ioremap 對映實體地址

#define gpio_con_reg  0x12345

#define gpio_data_reg 0x23456unsigned

long *led_con;

unsigned

long *led_data;

static

dev_t devno;

struct

cdev cdev;

struct file_operations fops =;

int __init led_init(void

)

//初始化cdev結構體

cdev_init(devno, &fops);

cdev.owner =this_module;

cdev.ops = &fops

//註冊字元裝置

cdev_add(&cdev, devno, 1

);

struct

class *led_class = class_create(this_module, "

led"

); class_device_create(led_class, null, devno, null,

"led0");

led_con = ioremap(gpio_con_reg, 8

); led_data = ioremap(gpio_data_reg, 8

);

return

0;

}

void __exit led_exit(void

)

裝置驅動例項 字元裝置驅動

在整個linux裝置驅動學習中,字元裝置驅動較為基礎。通過對它的學習,對裝置驅動進一步加深了解 cdev 結構體struct cdev 講下比較重要的成員變數 dev t dev 定義了32位的裝置號,其中12位是主裝置號,20位是從裝置號。獲取主裝置號 major dev t dev 獲取從裝置號...

字元裝置驅動

字元裝置驅動 概述 塊裝置 字元裝置以及網路裝置中塊裝置和網路裝置一般都會硬體配置完備,對於程式設計師而言,能夠更多操作的就是字元裝置。設定字元裝置的一般步驟 1.初始化硬體 2.定義fops file operations 3.申請cdev,掛載fops 3.加入cdev 函式cdev add 主...

字元裝置驅動

標頭檔案包含 include 變數定義 define gpgconaddr 0x56000060 硬體中斷號定義 define key1 irq irq eint5 define key2 irq irq eint3 裝置名定義 define devname mykey 主裝置號 cdev定義 需全...