linux一切裝置皆檔案的實現(二)
- 通過register_chrdev()函式註冊字元裝置struct cdev, struct cdev中保護kobject機構體,註冊的過程就是讓major 裝置號與struct cdev中的kobject建立對映關係(kobj_map(cdev_map, dev,...))。
- 在開啟裝置檔案時,通過儲存在磁碟中的inode中的i_rdev取得裝置檔案對應的裝置號,裝置號包括major(12bit)和minor(20bit),通過major取得kobject(register_chrdev已經建立好的kobject和major對映關係),container_of()可以取得struct cdev。
- 填充開啟的struct file的操作方法(const struct file_operations *ops)指向struct cdev中定義好的方法,這樣通struct file就可以直接操作到對應的裝置了。
status = register_chrdev(SPIDEV_MAJOR
}struct gendisk { int major; /* major number of driver */ int first_minor; int minors; /* maximum number of minors, =1 for * disks that can't be partitioned. */ char disk_name[DISK_NAME_LEN]; /* name of major driver */ char *(*devnode)(struct gendisk *gd, umode_t *mode); struct disk_part_tbl __rcu *part_tbl; struct hd_struct part0; //描述整個磁碟 const struct block_device_operations *fops; //操作方法 struct request_queue *queue; void *private_data; ...
}struct hd_struct { sector_t start_sect; sector_t nr_sects; sector_t alignment_offset; unsigned int discard_alignment; struct device __dev; struct kobject *holder_dir; int policy, partno; struct partition_meta_info *info; ...
}
首先來看看塊裝置的註冊過程:
- 驅動呼叫add_disk()來註冊整個磁碟
blk_register_region(disk_devt(disk), disk->minors, NULL, exact_match, exact_lock, disk); //通過struct hd_struct中的struct device中的kobject與裝置號建立對映,這也就是說struct gendisk和裝置號之間建立了對映關係 register_disk(disk); blk_register_queue(disk); ...
}void blk_register_region(dev_t devt, unsigned long range, struct module *module, struct kobject *(*probe)(dev_t, int *, void *), int (*lock)(dev_t, void *), void *data){ kobj_map(bdev_map, devt, range, module, probe, lock, data);}static void register_disk(struct gendisk *disk){ struct device *ddev = disk_to_dev(disk); struct block_device *bdev; struct disk_part_iter piter; struct hd_struct *part; int err; ddev->parent = disk->driverfs_dev; dev_set_name(ddev, disk->disk_name); if (device_add(ddev)) return; ... /* No minors to use for partitions */ if (!disk_part_scan_enabled(disk)) //判斷是否要掃描磁碟上的分割槽 goto exit; /* No such device (e.g., media were just removed) */ if (!get_capacity(disk)) goto exit; bdev = bdget_disk(disk, 0); //建立整個磁碟對應的struct block_device if (!bdev) goto exit; bdev->bd_invalidated = 1; err = blkdev_get(bdev, FMODE_READ, NULL); if (err < 0) goto exit; blkdev_put(bdev, FMODE_READ);exit: /* announce disk after possible partitions are created */ dev_set_uevent_suppress(ddev, 0); kobject_uevent(&ddev->kobj, KOBJ_ADD); /* announce possible partitions */ disk_part_iter_init(&piter, disk, 0); while ((part = disk_part_iter_next(&piter))) kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD); disk_part_iter_exit(&piter);}struct block_device *bdget_disk(struct gendisk *disk, int partno){ struct hd_struct *part; struct block_device *bdev = NULL; part = disk_get_part(disk, partno); if (part) bdev = bdget(part_devt(part)); //首次呼叫時,建立裝置號與bdev檔案系統中的indoe建立對映關係,首次呼叫分配bdev_inode結構體,也就是說同時分配了 struct block_device, 通過inode可以得到struct block_device,這也就是說裝置號和struct block_device之間也建立了對映關係 disk_put_part(part); return bdev;}int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder){ ...
res = __blkdev_get(bdev, mode, 0); ...
}static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part){ ...
disk = get_gendisk(bdev->bd_dev, &partno); //通過之前建立好的對映關係,由裝置號得到struct gendisk bdev->bd_disk = disk; if (!partno) { ...
rescan_partitions(disk, bdev); //掃描分割槽 }
...
}struct block_device *bdget(dev_t dev){ struct block_device *bdev; struct inode *inode; inode = iget5_locked(blockdev_superblock, hash(dev), bdev_test, bdev_set, &dev); if (!inode) return NULL; bdev = &BDEV_I(inode)->bdev; if (inode->i_state & I_NEW) { ...
inode->i_mode = S_IFBLK; inode->i_rdev = dev; //裝置號與inode之間建立對映 inode->i_bdev = bdev; ...
} return bdev;}struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data){ struct hlist_head *head = inode_hashtable + hash(sb, hashval); struct inode *inode; spin_lock(&inode_hash_lock); inode = find_inode(sb, head, test, data); spin_unlock(&inode_hash_lock); if (inode) { wait_on_inode(inode); return inode; } inode = alloc_inode(sb); //首次呼叫時分配bdev_inode結構體 if (inode) { ...
if (set(inode, data)) ...
} return inode;set_failed: spin_unlock(&inode_hash_lock); destroy_inode(inode); return NULL;}static int bdev_set(struct inode *inode, void *data){ BDEV_I(inode)->bdev.bd_dev = *(dev_t *)data; //儲存裝置號 return 0;}struct bdev_inode { struct block_device bdev; struct inode vfs_inode;};struct gendisk *get_gendisk(dev_t devt, int *partno){ struct gendisk *disk = NULL; kobj = kobj_lookup(bdev_map, devt, partno); if (kobj)
disk = dev_to_disk(kobj_to_dev(kobj));}
- open開啟裝置檔案, 通過儲存在inode中的i_rdev在bdev檔案系統中進行查詢,找到inode,然後通過inode找到block_device,得到gendisk,gendisk存放著操作方法,覆蓋struct file的操作方法,這樣就可以操作裝置了。
通過上面的分析可以看出,在設備註冊過程中首先建立起裝置號和裝置操作方法間的對映,然後通過裝置檔案中的裝置號得到操作方法覆蓋掉普通檔案操作方法,這樣就可以實現裝置的訪問了。
相關推薦
linux一切裝置皆檔案的實現(二)
首先struct device是裝置模型中的概念,這個結構體中儲存的是具體板子上裝置的資訊,比如基暫存器地址,暫存器範圍,終端號等等,目的就是使驅動與具體的板子硬體連線剝離,使驅動更具有通用性和移植性,這樣不同板子上驅動都不需要改變,struct device註冊裝置放在架構
Linux 核心程式設計之檔案系統(二)
1.為了方便查詢,VFS引入了 目錄 項,每個dentry代表路徑中的一個特定部分。目錄項也可包括安裝點。 2.目錄項物件由dentry結構體表示 ,定義在檔案linux/dcache.h 標頭檔案中。 89struct dentry { 90 atomic_t d_count;
Linux 檔案系統與裝置檔案系統 (二)—— sysfs 檔案系統與Linux裝置模型
提到 sysfs 檔案系統 ,必須先需要了解的是Linux裝置模型,什麼是Linux裝置模型呢? 一、Linux 裝置模型 1、裝置模型概述 從2.6版本開始,Linux開發團隊便為核心建立起一個統一的裝置模型。在以前的核心中沒有獨立的資料結構用來讓核
linux系統 使用者身份與檔案許可權(二)
0.檔案的許可權與歸屬 儘管在Linux系統中一切都是檔案,但是每個檔案的型別不盡相同,因此Linux系統使用了不同的字元來加以區分,常見的字元如下所示。 -:普通檔案 d:目錄檔案 l:連結檔案 b:塊裝置檔案 c:字元
基於IE核心的多媒體檔案視覺化程式實現(二)
文章目錄 使用命令列引數 命令列引數獲取和解析程式碼 幫助系統 執行測試 WSEE的功能還不只如此 現在的結果 上回說道,我們需要使用命令列引數方法將要瀏覽的檔名傳入wsee.exe 程式,然後由
一個簡單的BitTorrent客戶端實現(二):種子檔案解析及資訊儲存
關於種子檔案 BT的種子檔案一般是以.torrent作為字尾的。關於種子檔案的編碼,這裡不再做任何介紹。本程式採用的測試種子檔案為ubuntu-14.04.3-desktop-i386.torrent,各位可以到http://mirrors.163.com/u
基於Huffman樹的檔案壓縮原理及C語言實現(二)
在上文基於Huffman樹的檔案壓縮原理及C語言實現(一)中已經介紹並實現瞭如何建立Huffman樹,得到Huffman編碼,這篇我們將會接著說。如何通過Huffman樹,實現檔案壓縮。 實現思路 任何檔案都可以看作是由位元組組成的位元組塊,將位元組看作
例說linux核心與應用資料通訊(二):proc虛擬檔案系統
下面是一個簡單使用proc的示例,應用上面傳入資料,核心經過處理之後,應用再獲取經過處理的資料:#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <
Linux下庫檔案學習(二)如何設定庫的路徑
最近在Linux下使用第三方庫Protobuf時,遇到一個問題:編譯出的可執行程式在執行時總報錯:“error while loading shared libraries: libprotobuf.so.7: cannot open shared object file
OpenCV3計算機視覺Python語言實現(二):處理檔案、攝像頭和圖形使用者介面
2.1 基本I/O指令碼 2.1.1 讀/寫影象檔案 2.1.2 影象和原始位元組之間的轉換 2.1.3使用numpy.array()訪問影象資料 2.1.4 視訊檔案的讀寫 2.1.5 捕獲攝像頭的幀 2.1.6 在視窗顯示影象 2.1.7 在視窗顯示攝像
Dji Mobile SDK 基礎實現(二)
stat one 透傳 pub != exceptio rom tick ann Dji Mobile SDK 基礎實現(二) 本文簡要介紹如何通過調用DJI Mobile SDK,實現獲取和釋放無人機的控制權限、模擬遙控器按鈕控制無人機的飛行、獲取無人機的回傳視頻、獲取
Linux下MySQL主從復制(二)
mysql 鄰居 MySQL的一主多從模式原理結構圖配置步驟1.主服務器: 1. 改變server id 2. 啟用二進制日誌文件 3. 創建具有復制的用戶123123具體操作請看:http://www.crazyrui.pw:8088/index.php/2017/07/23/linux_m
實現自定義查詢的數據庫設計及實現(二)
表名 table abr bigint sts 處理 update 關聯表 creat 上部分大概講了一下表設計,這部分講一下處理。 處理的結構 處理結構的內容比較多,分為幾個部分分別講解一下。首先講解一下尋找關系表。 尋找關系表 尋找關系表根據“表間關系登記表”進行處
linux學習之進程篇(二)
通過 passwd 查看 現在 替換 cnblogs exe -1 stdio.h 進程原語 1.fork #include<unistd.h> pid_t fork(void); fork 子進程復制父進程,子進程和父進程的PID是不一樣的,在
Linux系統管理----存儲管理(二)
運維 系統 創建文件系統----分區格式化 格式化 低級格式化:磁盤初始化,磁道劃分; 高級格式化:創建或重建文件系統;按照某種特定的標準,將整個分區劃分為大小相同的若幹小的邏輯編址單元,每個這樣的單元,稱為塊(Block);window中稱為:簇 劃分
KVM虛擬化的四種簡單網絡模型介紹及實現(二)
str drive 51cto -c water -a return dfa 模型 接上篇,介紹NAT網絡模型和橋接模型。 三、NAT模型 NAT模型其實就是SNAT的實現,路由中虛擬機能將報文發送給外部主機,但是外部主機因找不到通往虛擬機的路由因而無法回應請求。但是外部
SpringBoot在Kotlin中的實現(二)
文件中 open 代碼 rabl delete ons list any data 根據現在的開發模式和網上的一些資料,SpringBoot需要對業務和操作進行分層,通常分為controller、entity、service、respository等結構。下面以Kotlin
Linux文本處理三劍客awk (二)
退出 action ram out scrip 設計 default dup 性能 前一篇文章分享了awk的一些基本概念和用法,這篇分享的是awk的一些高級用法。在學習awk的過程中,對比我之前學過的C語言,我發現awk裏的while,for,cas
【原始碼剖析】tornado-memcached-sessions —— Tornado session 支援的實現(二)
客官您終於回頭了!讓我們本著探(zuo)索(si)精神把 session.py 看完吧... 首先看看需要的庫: pickle 一個用於序列化反序列化的庫(聽
Linux學習之shell 程式設計基礎(二)
一、bash環境變數 HOME、MAIL、SHELL、PATH 等,環境變數大都用大寫字母組成 [[email protected] dalianmao]# echo $SHELL /bin/bash [[email protected] dalianmao]# echo