|
AUTHOR: Joseph Yang (楊紅剛) <ganggexiongqi@gmail.com>
CONTENT: uio.c source code notes NOTE: linux-3.0 LAST MODIFIED:09-04-2011 -------------------------------------- Distributed and Embedded System Lab (分布式嵌入式系統(tǒng)實驗室,蘭州大學) ===============================================================================
uio.c 導出的可以在您的uio驅動中使用的函數(shù): EXPORT_SYMBOL_GPL(uio_event_notify); EXPORT_SYMBOL_GPL(__uio_register_device); EXPORT_SYMBOL_GPL(uio_unregister_device); ------------------------------------------------------------------------------------------------- uio.c 函數(shù)列表 |- function || map_name_show || map_addr_show || map_size_show || map_offset_show || map_release || map_type_show || portio_name_show || portio_start_show || portio_size_show || portio_porttype_show || portio_release || portio_type_show || show_name || show_version || show_event || uio_dev_add_attributes || uio_dev_del_attributes || uio_get_minor || uio_free_minor || uio_event_notify || uio_interrupt || uio_open || uio_fasync || uio_release || uio_poll || uio_read || uio_write || uio_find_mem_index || uio_vma_open || uio_vma_close || uio_vma_fault || uio_mmap_physical || uio_mmap_logical || uio_mmap || uio_major_init || uio_major_cleanup || init_uio_class || release_uio_class || __uio_register_device || uio_unregister_device || uio_init || uio_exit ---------------------------一些重要的數(shù)據(jù)結構----------------------------------------------
------------------------------------ 函數(shù)的詳細解釋 --------------------------------------------- 1. 函數(shù): static int __init uio_init(void) 功能:申請字符設備號,設備,并注冊到系統(tǒng)中,注冊uio_class到系統(tǒng)中 調用模塊:init_uio_class() 執(zhí)行流程: 申請字符設備號,設備,并注冊到系統(tǒng)中,注冊uio_class到系統(tǒng)中 //init_uio_class //創(chuàng)建"/sys/class/uio" 2. 函數(shù):uio_exit 參數(shù): 返回值: 功能:注銷uio_class,注銷字符設備編號,刪除設備 調用模塊:release_uio_class 執(zhí)行流程: 注銷uio_class,注銷字符設備編號,刪除設備 //release_uio_class 3. 函數(shù):static void release_uio_class(void) 參數(shù): 返回值: 功能:注銷uio_class,注銷字符設備編號,刪除設備 調用模塊: 執(zhí)行流程: 注銷uio_class//class_unregister 注銷字符設備編號,刪除設備 //uio_major_cleanup ------------------------------------------------- 4. 函數(shù):static int init_uio_class(void) 參數(shù): 返回值: 功能:申請字符設備號,設備,并注冊到系統(tǒng)中,注冊uio_class到系統(tǒng)中 調用模塊: uio_major_init() class_register() 執(zhí)行流程: 申請字符設備編號,設備,并初始化//uio_major_init 注冊class 類型全局變量uio_class到系統(tǒng)//class_register //ls -l /sys/class 查看 5. 函數(shù): static int uio_major_init(void) 參數(shù): 返回值: 功能:申請字符設備編號,設備,并初始化 調用模塊: alloc_chrdev_region() cdev_alloc() kobject_set_name() cdev_add() 執(zhí)行流程: 申請字符設備編號(多個)//alloc_chrdev_region //2^UIO_MAX_DEVICES個從設備 //設備的名字為"uio" 分配一個表示字符設備的cdev結構//cdev_alloc 初始化cdev結構的file_operations類型字段//控制cdev設備的各種操作, // 如 open, close, read, write... 設置cdev結構的kobj字段的name為uio //kobject_set_name 添加字符設備到系統(tǒng)中 //cdev_add,調用成功后,我們的設備就“活了” // cat /proc/devices ,可以查看到分配到主設備號 保存主設備號到全局變量uio_major 保存設備指針到全局變量uio_cdev 返回 6. 函數(shù):static void uio_major_cleanup(void) 參數(shù): 返回值: 功能:注銷字符設備編號,刪除設備 調用模塊:unregister_chrdev_region 執(zhí)行流程: 注銷字符設備編號//unregister_chrdev_region 刪除設備uio_cdev //cdev_del ===== file_operations 7. 函數(shù):static int uio_open(struct inode *inode, struct file *filep) 參數(shù):inode: filep: 返回值: 功能:獲得和次設備號關聯(lián)的uio_device指針,創(chuàng)建一個輔助變量listener, 并調用 info指向的uio_info結構中的open方法 調用模塊: 執(zhí)行流程: 獲得保護uio_idr的鎖 //mutex_lock 從inode 結構中獲取次編號 //iminor 獲得和次編號關聯(lián)的uio_device指針 //idr_find <----------<<<< 在那里進行地設置呢??? // 在 uio_get_minor 中分配的次設備編號并設置的關聯(lián) 放棄鎖 //mutex_unlock 增加uio_device類型指針指向的模塊的引用計數(shù) //try_module_get 分配一個uio_listener類型的listener //kmalloc 關聯(lián)listener和 uio_device 指針 獲得uio_device 指向設備的事件計數(shù)值,并存入listener //atomic_read 把listener指針保存到filep->private_data字段 調用uio_device的info字段指向的uio_info中的open方法//***** 8. 函數(shù):static int uio_release(struct inode *inode, struct file *filep) 參數(shù):inode filep 返回值: 功能:從而調用uio_device的字段info指向的uio_info中的release方法 釋放輔助結構體listener 調用模塊: 執(zhí)行流程: 從filep->private_data中獲得uio_open中保存的listener指針。 利用listener指針找到指向uio_device類型結構指針 從而調用uio_device的字段info指向的uio_info中的release方法。 減少uio_device類型指針指向的模塊的引用計數(shù)//module_put 釋放listener結構體 //kfree 9. 函數(shù):static int uio_fasync(int fd, struct file *filep, int on) 參數(shù): fd filep on : 0, 刪除;非零,添加 返回值: 功能: 管理uio_device的async_queue 調用模塊:fasync_helper() 執(zhí)行流程: 從filep->private_data中獲得uio_open中保存的listener指針。 利用listener指針找到指向uio_device類型結構指針 設置uio_device的async_queue//fasync_helper 10. 函數(shù):static unsigned int uio_poll(struct file *filep, poll_table *wait) 參數(shù): filep wait 返回值: 功能: 使進程在傳遞到該系統(tǒng)調用的所有文件描述符對應的等待隊列上等待, 并返回一個是否可以立即無阻塞執(zhí)行的位掩碼 調用模塊: 執(zhí)行流程: 從filep->private_data中獲得uio_open中保存的listener指針。 利用listener指針找到指向uio_device類型結構指針 判斷用uio_device類型指針的info字段(uio_info類型)的irq成員不為0,則繼續(xù), 否則,返回IO錯誤 向poll_table類型的wait表中添加uio_device類型指針指向結構的wait等待隊列//poll_wait //!!!! 注意poll_wait并不阻塞 如果listener中的事件計數(shù)值event_count和uio_device的 事件計數(shù)值count不一致時// uio_interrupt調用了uio_event_notify對 //中斷事件計數(shù)器增一 返回“通?!钡臄?shù)據(jù)可讀的位掩碼 11. 函數(shù):static ssize_t uio_read(struct file *filep, char __user *buf, size_t count, loff_t *ppos) 參數(shù): filep buf count ppos 返回值: 功能:復制uio設備中斷事件計數(shù)器的值到用戶空間 調用模塊: 執(zhí)行流程: 從filep->private_data中獲得uio_open中保存的listener指針 利用listener指針找到指向uio_device類型結構指針 創(chuàng)建一個等待隊列的項 //DECLARE_WAITQUEUE 檢查確認uio設備的設備info的中斷號(0)不為零 添加本進程到uio設備的等待隊列wait上 // add_wait_queue //由uio_interrupt調用uio_event_notify喚醒 REP: 設置當前進程的 "可中斷標志" 檢查是否有中斷事件發(fā)生, 如果有(listener中的中斷事件計數(shù)值event_count)和uio設備中的中斷事件 計數(shù)器值不一致),則將設備中斷計數(shù)器的值復制到用戶空間 并將listener中的中斷事件計數(shù)值更新為設備的中斷事件計數(shù)值 把當前進程設置為TASK_RUNNING狀態(tài), 并將當前進程從uio設備的等待隊列wait上刪除 如果文件讀時設置了O_NONBLOCK標志, 那么,把當前進程設置為TASK_RUNNING狀態(tài), 并將當前進程從uio設備的等待隊列wait上刪除 返回 -EAGAIN 檢查當前進程是否有信號處理 //signal_pending //http://blog./space.php?uid=20746501&do=blog&cuid=1820175 如有,把當前進程設置為TASK_RUNNING狀態(tài), 并將當前進程從uio設備的等待隊列wait上刪除 并返回 -ERESTARTSYS 執(zhí)行調度 //schedule JMP REP 12. 函數(shù):static irqreturn_t uio_interrupt(int irq, void *dev_id) // <---------------<<<<<<<<<<被誰調用呢??? __uio_register_device中設定 參數(shù): irq dev_id 返回值: 功能: 調用uio_info中注冊的handler中斷處理函數(shù),對設備的中斷事件計數(shù)器增一 并通知各讀進程,有數(shù)據(jù)可讀 調用模塊: 執(zhí)行流程: 從filep->private_data中獲得uio_open中保存的listener指針 調用 uio_device類型指針的info字段(uio_info類型)的handler 如果屬于本設備的中斷,并且在handler中已經(jīng)處理過 那么對設備的中斷事件計數(shù)器增一, 并通知各讀進程,有數(shù)據(jù)可讀 //uio_event_notify 13. 函數(shù):void uio_event_notify(struct uio_info *info) 參數(shù): 返回值: 功能:“觸發(fā)“ 一個中斷事件,對設備的中斷事件計數(shù)器增一,并通知各讀進程,有數(shù)據(jù) 可讀 調用模塊: 執(zhí)行流程: 從filep->private_data中獲得uio_open中保存的listener指針 對中斷事件計數(shù)器增一 喚醒阻塞在設備等待隊列wait上的讀進程 //wake_up_interruptible // 該隊列上的進程在uio_read中添加 向異步等待隊列async_queue發(fā)出可讀信號 //kill_fasync 14. 函數(shù):static ssize_t uio_write(struct file *filep, const char __user *buf, size_t count, loff_t *ppos) 參數(shù): 返回值: 功能: 讀取用戶空間的值,并調用uio_device注冊的irqcontrol函數(shù) 調用模塊: 執(zhí)行流程: 從filep->private_data中獲得uio_open中保存的listener指針 調用 uio_device類型指針的info字段(uio_info類型)的handler 檢驗info字段(uio_info類型)的中斷號irq 讀取從用戶空間傳過來的32位的值//copy_from_user 調用info字段(uio_info類型)的irqcontrol函數(shù),將用戶空間傳遞過來的32位值 作為參數(shù)傳入。 15. 函數(shù):static int uio_mmap(struct file *filep, struct vm_area_struct *vma) 參數(shù): 返回值: 功能: 調用模塊: 執(zhí)行流程: 從filep->private_data中獲得uio_open中保存的listener指針 調用 uio_device類型指針的info字段(uio_info類型)的handler 保存uio_device類型指針到 vma 的vm_private_data 返回映射區(qū)域的索引(比如 mapX,的X)//uio_find_mem_index 計算實際的頁數(shù)和請求的頁數(shù) 如果實際的頁數(shù)小于請求的頁數(shù)那么,返回-EINVAL 如果uio設備注冊有mmap函數(shù),那么就調用它 當內存區(qū)域的類型為UIO_MEM_PHYS時, //uio_mmap_physical 當內存區(qū)域的類型為UIO_MEM_LOGICAL/UIO_MEM_VIRTUAL時, 為虛擬內存區(qū)域設置操作,和告訴內存不要將 該區(qū)域交換出去,訪問計數(shù)器增一//uio_mmap_logical 備注:
16. 函數(shù):static int uio_find_mem_index(struct vm_area_struct *vma) 參數(shù): 返回值: 功能: 返回映射區(qū)域的索引(比如 mapX,的X) 調用模塊: 執(zhí)行流程: 返回虛擬內存區(qū)域在文件中以頁為單位的偏移 //即vma->vm_pgoff // 其實 vma->vm_pgoff 被內核自動填充為了用戶空間調用mmap時的最后一個參數(shù)offset>>page_size // 而uio用戶空間編程要求mmap最后一個參數(shù)為N*getsizeofpage(),從而 vma->vm_pgoff為映射區(qū)域的索引 17. 函數(shù):static int uio_mmap_logical(struct vm_area_struct *vma) 參數(shù): 返回值: 功能: 為虛擬內存區(qū)域設置操作,和告訴內存不要將該區(qū)域交換出去,訪問計數(shù)器增一 調用模塊: 執(zhí)行流程: 設置vma 標志VM_RESERVED告訴內存管理系統(tǒng)不要將VMA交換出去 設置vma的vm_ops // 對虛擬內存區(qū)的操作集合的設置 uio設備的虛擬內存區(qū)域訪問計數(shù)器(vma_count)增一 // uio_vma_open 18. 函數(shù):static void uio_vma_open(struct vm_area_struct *vma) 參數(shù): 返回值: 功能:uio設備的虛擬內存區(qū)域訪問計數(shù)器(vma_count)增一 調用模塊: 執(zhí)行流程: uio設備的虛擬內存區(qū)域訪問計數(shù)器(vma_count)增一 19. 函數(shù):static void uio_vma_close(struct vm_area_struct *vma) 參數(shù): 返回值: 功能: 調用模塊: 執(zhí)行流程: uio設備的虛擬內存區(qū)域訪問計數(shù)器(vma_count)減一 20. 函數(shù):static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 參數(shù): 返回值: 功能: 為失效的虛擬地址查找正確的page結構,并增加它的引用計數(shù) 調用模塊: 執(zhí)行流程: 從虛擬內存區(qū)域結構的私有數(shù)據(jù)字段獲得uio設備描述結構的指針 返回映射區(qū)域的索引(比如 mapX,的X)//uio_find_mem_index 如果是UIO_MEM_LOGICAL類型的虛地址 由內核邏輯地址得到該頁的描述結構的指針 //virt_to_page 如果是UIO_MEM_VIRTUAL類型的虛地址 有vmalloc得到的虛擬地址得到該頁的描述結構//vmalloc_to_page 增加內存頁的使用計數(shù) //get_page 保存頁結構的指針 備注: /* * We need to subtract mi because userspace uses offset = N*PAGE_SIZE * to use mem[N]. */ offset = (vmf->pgoff - mi) << PAGE_SHIFT; / 設備可以有多個內存映射塊,offset為塊內偏移。 21. 函數(shù):static int uio_mmap_physical(struct vm_area_struct *vma) 參數(shù): 返回值: 功能: 把內核空間的物理內存區(qū)域映射到用戶空間 調用模塊: 執(zhí)行流程: 從虛擬內存區(qū)域結構的私有數(shù)據(jù)字段獲得uio設備描述結構的指針 返回映射區(qū)域的索引(比如 mapX,的X) //uio_find_mem_index 設置虛擬內存區(qū)域的標志VM_IO ,VM_RESERVED //VM_IO將該VMA標記為內存映射的IO區(qū)域,VM_IO會阻止系 // 統(tǒng)將該區(qū)域包含在進程的存放轉存(core dump)中, // VM_RESERVED標志內存區(qū)域不能被換出。 設置頁的存取權限 //pgprot_nocached禁止了相關頁的CACHE 和寫緩沖( //位于處理器和主存之間,將處理器和cache從及 //較慢的主存寫操作解脫出來的FIFO存儲器) 把內核空間的內存區(qū)域映射到用戶空間 //remap_pfn_range 22. 函數(shù):static int uio_get_minor(struct uio_device *idev) 參數(shù): 返回值: 功能:分配id號,并將id號和指針關聯(lián) 調用模塊: 執(zhí)行流程: 獲得保護uio_idr的鎖 //mutex_lock 為idr分配內存 //idr_pre_get 分配id號,并將id號和指針關聯(lián) //idr_get_new // 在uio_open中用到了 將分配到的id保存到uio設備結構變量的minor字段 釋放鎖 //mutex_unlock 23. 函數(shù):static void uio_free_minor(struct uio_device *idev) 參數(shù): 返回值: 功能:從idr表中刪除id與指針的關聯(lián) 調用模塊: 執(zhí)行流程: 獲得保護uio_idr的鎖 //mutex_lock 從idr表中刪除id與指針的關聯(lián) //idr_remove 釋放uio_idr的鎖 //mutex_unlock 24. 函數(shù):static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) 參數(shù): 返回值: 功能:顯示uio設備的名字 調用模塊: 執(zhí)行流程: 獲得保存在driver_data中的uio_device指針 //driver_data <-------------<<<<在那里設定??? 把uio設備的名字字符串寫到buf中,將在用戶空間看到它的值 25. 函數(shù):static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) 參數(shù): 返回值: 功能:顯示 uio設備的版本 調用模塊: 執(zhí)行流程: 26. 函數(shù):static ssize_t show_event(struct device *dev, struct device_attribute *attr, char *buf) 參數(shù): 返回值: 功能:顯示uio設備中斷計數(shù)器的值 調用模塊: 執(zhí)行流程: 27,28,29,30 //map <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 功能: 顯示kobject對象的屬性 map_name_show map_addr_show map_size_show map_offset_show 31. 函數(shù):static void map_release(struct kobject *kobj) 參數(shù): 返回值: 功能:釋放uio_map結構 調用模塊: 執(zhí)行流程: 得到包含kobj的 uio_map 結構的指針 // to_map 釋放uio_map結構 32. 函數(shù): static ssize_t map_type_show(struct kobject *kobj, struct attribute *attr, char *buf) 參數(shù): 返回值: 功能:調用 map_name_show, map_addr_show, map_size_show,map_offset_show方法 顯示mem map的各種屬性 調用模塊: 執(zhí)行流程: 得到包含kobj的 uio_map 結構的指針 // to_map 得到uio_map的uio_mem類型成員的指針 得到包含attribute 的map_sysfs_entry結構的指針// 調用map_sysfs_entry的show函數(shù) 33, 34, 35, 36 功能: 顯示 io 區(qū)域的屬性 portio_name_show, portio_start_show, portio_size_show, portio_porttype_show 37. 函數(shù):static void portio_release(struct kobject *kobj) 參數(shù): 返回值: 功能: 釋放uio_portio結構 調用模塊: 執(zhí)行流程: 得到包含kobj的 uio_portio 結構的指針 // to_map 釋放uio_portio結構 38. 函數(shù):static ssize_t portio_type_show(struct kobject *kobj, struct attribute *attr, char *buf) 參數(shù): 返回值: 功能: 調用 portio_name_show, 顯示 io region 的屬性 調用模塊:執(zhí)行流程: 得到包含kobj的 uio_portio 結構的指針 // to_map 得到uio_portio內嵌的uio_port結構體的指針 得到包含attr 的portio_sysfs_entry類型的指針 調用show方法 39. 函數(shù):static int uio_dev_add_attributes(struct uio_device *idev) 參數(shù): 返回值: 功能:在sysfs中注冊 內存映射和端口io區(qū)域 相關的文件和文件夾,以及相關屬性。 調用模塊: 執(zhí)行流程: 內存映射 在sysfs中的注冊: create a struct kobject “maps”dynamically and register it with sysfs//kobject_create_and_add // "uio/maps" directory created 分配uio_map 類型變量map 初始化map的obj成員,并為之添加屬性// kobject_init 關聯(lián) uio_map類型變量map和uio_mem類型變量mem //把mem地址保存在uio_map類型變量的成員中 //把map地址保存在mem類型變量的成員中 在uio/uioX/maps下再創(chuàng)建mapX 對象//kobject_create_and_add,"uio/uioX/maps/mapX" 通知用戶空間"uio/uioX/maps/mapX"可用 //kobject_uevent 端口io區(qū)域在 sysfs中的注冊: create a struct kobject “portio”dynamically and register it with sysfs//kobject_create_and_add // "uio/uioX/portio" directory created 分配uio_portio 類型變量portio 初始化map的portio成員,并為之添加屬性// kobject_init 關聯(lián) uio_portio類型變量portio和uio_port類型變量port //把port地址保存在uio_portio類型變量的成員中 //把portio地址保存在port類型變量的成員中 在uio/uioX/portio下再創(chuàng)建portX對象//kobject_create_and_add,"uio/uioX/portio/portX" 通知用戶空間"uio/uioX/portio/portX"可用 //kobject_uevent 40. 函數(shù):static void uio_dev_del_attributes(struct uio_device *idev) 參數(shù): 返回值: 功能: 刪除在uio_dev_add_attributes中,添加的kobject對象, 從而刪除在uio目錄下的各個文件和文件夾 調用模塊: 執(zhí)行流程:... 41. 函數(shù):int __uio_register_device(struct module *owner, struct device *parent, struct uio_info *info) 參數(shù):owner: module that creates the new device parent: parent device info: UIO device capabilities 返回值: 功能:register a new userspace IO device 調用模塊: 執(zhí)行流程: 檢查 parent,和info的name,和version,確保不為空 分配uio_device型變量的空間 初始化uio設備的等待隊列 初始化uio設備的中斷事件計數(shù)器event為0//atomic_set 分配id號,并將id號和指針關聯(lián) //uio_get_minor creates a device and registers it with sysfs//device_create //在uio class目錄下創(chuàng)建 uioX,即'uio/uioX' 在sysfs中注冊 內存映射和端口io區(qū)域 相關的文件和文件夾, 以及相關屬性。 //uio_dev_add_attributes 將完成初始化的uio_device的指針保存在uio_info類型變量的uio_dev中 為uio_device注冊中斷函數(shù)uio_interrupt //request_irq 42. 函數(shù):void uio_unregister_device(struct uio_info *info) 參數(shù): 返回值: 功能:卸載uio設備 調用模塊: 執(zhí)行流程: 從idr表中刪除uio_device 的id 與指針的關聯(lián)//uio_free_minor 刪除在uio_dev_add_attributes中,添加的kobject對象,// uio_dev_del_attributes 從而刪除在uio目錄下的各個文件和文件夾 刪除設備//device_destroy 釋放uio_device 類型結構的空間//kfree =================================================================== 參考: 1. Documentation/DocBook/uio-howto.tmpl 2. drivers/uio/uio.c 3. vm_area_struct http://blog.csdn.net/ganggexiongqi/article/details/6746248 4. 淺析linux內核中的idr機制 http://blog.csdn.net/ganggexiongqi/article/details/6737389 |
|
|
來自: lifei_szdz > 《UIO子系統(tǒng)》