linux字元裝置解析,linux字元解析

來源:互聯網
上載者:User

linux字元裝置解析,linux字元解析

字元裝置的表示當然是指這個struct cdev結構。let us see。

struct cdev {    struct kobject kobj;    struct module *owner;    const struct file_operations *ops;    struct list_head list;    dev_t dev;    unsigned int count;};

kobj用來表示sys下的目錄,owner模組使用者指標,一般賦值為THIS_MODULE,第三個參數很關鍵file_operations,是使用者層調用open、release、write、read函數時。傳到核心層處理,第四個結構list表示的是一個鏈表節點。第五個是裝置號,沒什麼講的。第六個是count

怎麼分配結構體cdev呢,有兩種方式,一種是靜態定義一個 struct cdev my_cdev,然後在使用cdev_init函數去初始化該結構,第二種方式是利用cdev_alloc函數去動態申請。

有的人會先使用cdev_alloc函數去動態分配,在使用函數cdev_init去釋放,其實這種用法是不太正確的,為什麼呢?且看下面分析。

void cdev_init(struct cdev *cdev, const struct file_operations *fops){    memset(cdev, 0, sizeof *cdev);    INIT_LIST_HEAD(&cdev->list);    kobject_init(&cdev->kobj, &ktype_cdev_default);    cdev->ops = fops;}struct cdev *cdev_alloc(void){    struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);    if (p) {        INIT_LIST_HEAD(&p->list);        kobject_init(&p->kobj, &ktype_cdev_dynamic);    }    return p;}

看出相同之處和不同之處了嗎,yes kobject_init這個函數是關鍵,關鍵在於ktype類型不同、

static struct kobj_type ktype_cdev_default = {    .release    = cdev_default_release,};static struct kobj_type ktype_cdev_dynamic = {    .release    = cdev_dynamic_release,};

很明顯,再看

static void cdev_default_release(struct kobject *kobj){    struct cdev *p = container_of(kobj, struct cdev, kobj);    cdev_purge(p);}static void cdev_dynamic_release(struct kobject *kobj){    struct cdev *p = container_of(kobj, struct cdev, kobj);    cdev_purge(p);    kfree(p);}

對,多了一個kfree,也就是說alloc申請出來的cdev佔用的記憶體空間可以在裝置被卸載時自動釋放。

下面來看linux 核心怎麼管理字元裝置號。
核心提供了兩種方式,一種是alloc_chrdev_region另一個是register_chrdev_region,兩個的底層實現如出一轍。下面來分析alloc_chrdev_region。

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,            const char *name){    struct char_device_struct *cd;    cd = __register_chrdev_region(0, baseminor, count, name);    if (IS_ERR(cd))        return PTR_ERR(cd);    *dev = MKDEV(cd->major, cd->baseminor);    return 0;}

主要的函數是__register_chrdev_region(0, baseminor, count, name);

static struct char_device_struct *__register_chrdev_region(unsigned int major, unsigned int baseminor,               int minorct, const char *name){    struct char_device_struct *cd, **cp;    int ret = 0;    int i;    cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);//分配裝置號相關的資訊。    if (cd == NULL)        return ERR_PTR(-ENOMEM);    mutex_lock(&chrdevs_lock);    /* temporary */    if (major == 0) {//動態申請        for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {            if (chrdevs[i] == NULL)                break;        }        if (i == 0) {            ret = -EBUSY;            goto out;        }        major = i;        ret = major;    }    cd->major = major;    cd->baseminor = baseminor;    cd->minorct = minorct;    strlcpy(cd->name, name, sizeof(cd->name));    i = major_to_index(major);    for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)        if ((*cp)->major > major ||            ((*cp)->major == major &&             (((*cp)->baseminor >= baseminor) ||              ((*cp)->baseminor + (*cp)->minorct > baseminor))))            break;//次裝置號的掛接是從小到大,    /* Check for overlapping minor ranges.  */    if (*cp && (*cp)->major == major) {//檢測是否有裝置號重合衝突        int old_min = (*cp)->baseminor;        int old_max = (*cp)->baseminor + (*cp)->minorct - 1;        int new_min = baseminor;        int new_max = baseminor + minorct - 1;        /* New driver overlaps from the left.  */        if (new_max >= old_min && new_max <= old_max) {            ret = -EBUSY;            goto out;        }        /* New driver overlaps from the right.  */        if (new_min <= old_max && new_min >= old_min) {            ret = -EBUSY;            goto out;        }    }    cd->next = *cp;//掛接到雜湊表裡面    *cp = cd;    mutex_unlock(&chrdevs_lock);    return cd;out:    mutex_unlock(&chrdevs_lock);    kfree(cd);    return ERR_PTR(ret);}

分析到這裡,就該看一個有意思的資料結構了,也就是所謂的雜湊表。

static struct char_device_struct {    struct char_device_struct *next;    unsigned int major;    unsigned int baseminor;    int minorct;    char name[64];    struct cdev *cdev;      /* will die */} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

這就是雜湊表結構,chrdevs是一個指標數組,每一個元素都儲存著一個字元裝置,一看是static類型的,就知道這個chrdevs的每一項初始化後都為NULL,當一個新的裝置來了之後通過主裝置號來掛接到相應的chrdevs裡面,主裝置號就是雜湊表的表頭,而衝突域就用next指標來掛接。比如我註冊了一個major = 254 baseminor= 3 的一個裝置和major = 254 baseminor= 6的一個裝置,這時候chrdevs[254]就應該指向major= 254 baseminor= 3的char_device_struct結構然後該結構的next指標又指向 major= 254 baseminor= 6的char_device_struct結構。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.