首页
/
每日頭條
/
科技
/
全面注冊制總結
全面注冊制總結
更新时间:2024-10-04 21:14:12

全面注冊制總結?内核中所有已分配的字符設備編号都記錄在一個名為 chrdevs 散列表裡該散列表中的每一個元素是一個 char_device_struct 結構,它的定義如下:,下面我們就來聊聊關于全面注冊制總結?接下來我們就一起去了解一下吧!

全面注冊制總結(淺淺講解字符設備編号的注冊分配)1

全面注冊制總結

内核中所有已分配的字符設備編号都記錄在一個名為 chrdevs 散列表裡。該散列表中的每一個元素是一個 char_device_struct 結構,它的定義如下:

static struct char_device_struct { struct char_device_struct *next; // 指向散列沖突鍊表中的下一個元素的指針 unsigned int major; // 主設備号 unsigned int baseminor; // 起始次設備号 int minorct; // 設備編号的範圍大小 char name[64]; // 處理該設備編号範圍内的設備驅動的名稱 struct file_operations *fops; // 沒有使用 struct cdev *cdev; // 指向字符設備驅動程序描述符的指針 } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

注 意,内核并不是為每一個字符設備編号定義一個 char_device_struct 結構,而是為一組對應同一個字符設備驅動的設備編号範圍定義一個 char_device_struct 結構。chrdevs 散列表的大小是 255,散列算法是把每組字符設備編号範圍的主設備号以 255 取模插入相應的散列桶中。同一個散列桶中的字符設備編号範圍是按起始次設備号遞增排序的。

注冊内核提供了三個函數 來注冊一組字符設備編号,這三個函數分别是 register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev()。這三個函數都會調用一個共用的 __register_chrdev_region() 函數來注冊一組設備編号範圍(即一個 char_device_struct 結構)。所以下面先來看一下 __register_chrdev_region() 函數的實現代碼。

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); 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; strncpy(cd->name,name, 64); 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); }

函數 __register_chrdev_region() 主要執行以下步驟:

  1. 分配一個新的 char_device_struct 結構,并用 0 填充。

  2. 如果申請的設備編号範圍的主設備号為 0,那麼表示設備驅動程序請求動态分配一個主設備号。動态分配主設備号的原則是從散列表的最後一個桶向前尋找,那個桶是空的,主設備号就是相應散列桶的序 号。所以動态分配的主設備号總是小于 256,如果每個桶都有字符設備編号了,那動态分配就會失敗。

  3. 根據參數設置 char_device_struct 結構中的初始設備号,範圍大小及設備驅動名稱。

  4. 計算出主設備号所對應的散列桶,為新的 char_device_struct 結構尋找正确的位置。同時,如果設備編号範圍有重複的話,則出錯返回。

  5. 将新的 char_device_struct 結構插入散列表中,并返回 char_device_struct 結構的地址。

更多linux内核視頻教程文檔資料免費領取後台私信【内核】自行獲取.

分析完 __register_chrdev_region() 後,我們來一個個看那三個注冊函數。首先是 register_chrdev_region()。

int register_chrdev_region(dev_t from, unsigned count, const char *name) { struct char_device_struct *cd; dev_t to = from count; dev_t n, next; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n) 1, 0); if (next > to) next = to; cd = __register_chrdev_region(MAJOR(n), MINOR(n), next - n, name); if (IS_ERR(cd)) goto fail; } return 0; fail: to = n; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n) 1, 0); kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); } return PTR_ERR(cd); }

register_chrdev_region() 函數用于分配指定的設備編号範圍。如果申請的設備編号範圍跨越了主設備号,它會把分配範圍内的編号按主設備号分割成較小的子範圍,并在每個子範圍上調用 __register_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; }

alloc_chrdev_region() 函數用于動态申請設備編号範圍,這個函數好像并沒有檢查範圍過大的情況,不過動态分配總是找個空的散列桶,所以問題也不大。通過指針參數返回實際獲得的起始設備編号。

int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops) { struct char_device_struct *cd; struct cdev *cdev; char *s; int err = -ENOMEM; cd = __register_chrdev_region(major, 0, 256, name); if (IS_ERR(cd)) return PTR_ERR(cd); cdev = cdev_alloc(); if (!cdev) goto out2; cdev->owner = fops->owner; cdev->ops = fops; kobject_set_name(&cdev->kobj, "%s", name); for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/')) *s = '!'; err = cdev_add(cdev, MKDEV(cd->major, 0), 256); if (err) goto out; cd->cdev = cdev; return major ? 0 : cd->major; out: kobject_put(&cdev->kobj); out2: kfree(__unregister_chrdev_region(cd->major, 0, 256)); return err; }

最 後一個 register_chrdev() 是一個老式分配設備編号範圍的函數。它分配一個單獨主設備号和 0 ~ 255 的次設備号範圍。如果申請的主設備号為 0 則動态分配一個。該函數還需傳入一個 file_operations 結構的指針,函數内部自動分配了一個新的 cdev 結構。關于這些,在後續講字符設備驅動的注冊時會說明。

注銷和 注冊分配字符設備編号範圍類似,内核提供了兩個注銷字符設備編号範圍的函數,分别是 unregister_chrdev_region() 和 unregister_chrdev() 。它們都調用了 __unregister_chrdev_region() 函數。由于比較簡單,就不加說明了,隻把代碼貼出來。

static struct char_device_struct * __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) { struct char_device_struct *cd = NULL, **cp; int i = major_to_index(major); mutex_lock(&chrdevs_lock); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major == major && (*cp)->baseminor == baseminor && (*cp)->minorct == minorct) break; if (*cp) { cd = *cp; *cp = cd->next; } mutex_unlock(&chrdevs_lock); return cd; } void unregister_chrdev_region(dev_t from, unsigned count) { dev_t to = from count; dev_t n, next; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n) 1, 0); if (next > to) next = to; kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); } } void unregister_chrdev(unsigned int major, const char *name) { struct char_device_struct *cd; cd = __unregister_chrdev_region(major, 0, 256); if (cd && cd->cdev) cdev_del(cd->cdev); kfree(cd); }

注意, unregister_chrdev() 會把 register_chrdev() 中自動分配的 cdev 給注銷掉。

導讀-最新發表 - 内核技術中文網 - 構建全國最權威的内核技術交流分享論壇

轉載地址:淺淺講解字符設備編号的注冊分配! - 圈點 - 内核技術中文網 - 構建全國最權威的内核技術交流分享論壇

Comments
Welcome to tft每日頭條 comments! Please keep conversations courteous and on-topic. To fosterproductive and respectful conversations, you may see comments from our Community Managers.
Sign up to post
Sort by
Show More Comments
推荐阅读
金山文檔怎麼保存文件
金山文檔怎麼保存文件
金山文檔怎麼保存文件?在微信的發現中打開小程序一欄,然後搜索金山小程序,點擊進入,下面我們就來說一說關于金山文檔怎麼保存文件?我們一起去了解并探讨一下這個問題吧!金山文檔怎麼保存文件在微信的發現中打開小程序一欄,然後搜索金山小程序,點擊進入...
2024-10-04
菜鳥驿站是所有快遞都可以接收嗎
菜鳥驿站是所有快遞都可以接收嗎
菜鳥驿站是所有快遞都可以接收嗎?進站不用帶手機,刷臉取碼,快遞在哪一目了然;取到快遞,掃描一下,無感帶走;回家晚了,智能櫃24小時刷臉取件;不想出門,手機預約,無人車準時送達……,我來為大家科普一下關于菜鳥驿站是所有快遞都可以接收嗎?下面希...
2024-10-04
最好的幾款百元全面屏手機
最好的幾款百元全面屏手機
#頭條群星8月榜#自從9月初蘋果秋季新品發布會以來,機圈又掀起了一波對「全面屏」讨論熱潮。原因無它,iPhone被吐槽萬年不變的劉海屏,終于在14Pro系列上換成挖孔屏。而蘋果則靈機一動,針對挖孔搞了個「靈動島」,愣是讓缺陷搖身一變成大賣點...
2024-10-04
服裝行業進銷存哪個軟件好
服裝行業進銷存哪個軟件好
如今的服裝進銷存管理軟件的應用越來越廣泛了,每一家的軟件也是各有自己的優勢,符合不同服裝商家來使用。那麼,比較常用的服裝進銷存管理軟件又有哪些呢?今天衣聯網的小編就來給大家總結一下。一、大牌通用類管理軟件這類軟件包括了我們熟知的Oracle...
2024-10-04
mac虛拟機裝完vmtools不能開機
mac虛拟機裝完vmtools不能開機
mac虛拟機裝完vmtools不能開機?PD虛拟機是一款可以在Mac電腦中設置Windows系統的應用軟件在ParallelsDesktop虛拟機中如何取消和Mac電腦的文件夾共享?下面我們分享一下具體的操作步驟,下面我們就來聊聊關于mac...
2024-10-04
Copyright 2023-2024 - www.tftnews.com All Rights Reserved