天天看點

Linux裝置驅動(2)字元裝置

裝置号

裝置号由主裝置号和次裝置号組成。linux下,一切裝置皆檔案,所有的裝置都能在/dev目錄下找到相應的檔案。這些檔案除了名字不一樣以外,還每個裝置檔案都有不一樣的裝置号;

一般地,主裝置号對應一個類型的驅動裝置,之是以有次裝置号,它是用來驅動同類型的裝置。如序列槽,所有的序列槽共用一個主裝置号,每個序列槽有不同的次裝置号。

dev_t類型用來儲存裝置編号(包含主裝置号和次裝置号),實際上是一個32位整數,12位用來表示主裝置号,後20位表示次裝置号。

#define MINORBITS   20
#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))
           

裝置号的配置設定和釋放

靜态配置設定

/**
 * register_chrdev_region() - register a range of device numbers
 * @from: the first in the desired range of device numbers; must include
 *        the major number.
 * @count: the number of consecutive device numbers required
 * @name: the name of the device or driver.
 *
 * Return value is zero on success, a negative error code on failure.
 */
int register_chrdev_region(dev_t from, unsigned count, const char *name)
           

指定從裝置号from開始,申請count個裝置号,在/proc/devices中的名字為name

動态配置設定

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

動态申請從次裝置号baseminor開始的count個裝置号,在/proc/devices中的名字為name,并通過dev指針把配置設定到的裝置号傳回給調用函數者。

釋放

void unregister_chrdev_region(dev_t from, unsigned count)
           

裝置注冊

字元裝置struct cdev

struct cdev {
    struct kobject kobj;
    struct module *owner;//一般初始化為THIS_MODULE
    const struct file_operations *ops;//檔案操作結構體
    struct list_head list;
    dev_t dev;//裝置号
    unsigned int count;//添加的裝置個數
};
           

注冊的三個步驟:

1)配置設定cdev;

2)初始化cdev;

3)添加cdev;

配置設定

直接定義struct cdev test_cdev;

或者動态配置設定

truct cdev* test_cdev;

test_cdev = cdev_alloc();

初始化

/**
 * cdev_init() - initialize a cdev structure
 * @cdev: the structure to initialize
 * @fops: the file_operations for this device
 *
 * Initializes @cdev, remembering @fops, making it ready to add to the
 * system with cdev_add().
 */
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
           

這個函數幹了兩件事情:

1)核心自己填充了結構體中list和kobj的内容

2)把傳入的檔案操作結構體也填充進去

一般的,還要手工定義結構體成員owner。

添加

将cdev結構體與裝置号關聯起來:

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

參數:

cdev:指定要被添加的cdev結構體;

dev:對應的裝置号

count:從裝置号dev開始添加count個裝置.

函數幹了也兩件事:

1)把cdev結構體中還沒填充的兩個成員dev和count按照傳入參數指派。

2)把cdev結構體中傳入核心,這樣核心就知道對應裝置号和具體的檔案操作結構體了。

删除

void cdev_del(struct cdev *p)
           

繼續閱讀