免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
UIO 子系統(tǒng)結(jié)構(gòu)介紹

UIO 子系統(tǒng)結(jié)構(gòu)介紹

分類(lèi): Linux 內(nèi)核 Linux 基礎(chǔ)學(xué)習(xí) Linux 驅(qū)動(dòng) 移植 實(shí)時(shí)操作系統(tǒng) 雜項(xiàng) 259人閱讀 評(píng)論(0) 收藏 舉報(bào)
AUTHOR: Joseph Yang (楊紅剛) <ganggexiongqi@gmail.com>
CONTENT: Introduction of UIO subsystem ( UIO子系統(tǒng)介紹 )
NOTE: linux-3.0
LAST MODIFIED:09-15-2011
-----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (分布式嵌入式系統(tǒng)實(shí)驗(yàn)室,蘭州大學(xué))
===============================================================


------1------為什么出現(xiàn)了UIO?


硬件設(shè)備可以根據(jù)功能分為網(wǎng)絡(luò)設(shè)備,塊設(shè)備,字符設(shè)備,或者根據(jù)與CPU相連的方式
分為PCI設(shè)備,USB設(shè)備等。它們被不同的內(nèi)核子系統(tǒng)支持。這些標(biāo)準(zhǔn)的設(shè)備的驅(qū)動(dòng)編寫(xiě)
較為容易而且容易維護(hù)。很容易加入主內(nèi)核源碼樹(shù)。
但是,又有很多設(shè)備難以劃分到這些子系統(tǒng)中,比如I/O卡,現(xiàn)場(chǎng)總線接口或者定制的FPGA。

通常這些非標(biāo)準(zhǔn)設(shè)備的驅(qū)動(dòng)被實(shí)現(xiàn)為字符驅(qū)動(dòng)。這些驅(qū)動(dòng)使用了很多內(nèi)核內(nèi)部函數(shù)和宏。
而這些內(nèi)部函數(shù)和宏是變化的。這樣驅(qū)動(dòng)的編寫(xiě)者必須編寫(xiě)一個(gè)完全的內(nèi)核驅(qū)動(dòng),而且一直維護(hù)
這些代碼。而且這些驅(qū)動(dòng)進(jìn)不了主內(nèi)核源碼。于是就出現(xiàn)了用戶空間I/O框架(Userspace I/O framework)。

---------2----------UIO 是怎么工作的?


一個(gè)設(shè)備驅(qū)動(dòng)的主要任務(wù)有兩個(gè):
 1. 存取設(shè)備的內(nèi)存
 2. 處理設(shè)備產(chǎn)生的中斷
 
 對(duì)于第一個(gè)任務(wù),UIO 核心實(shí)現(xiàn)了mmap()可以處理物理內(nèi)存(physical memory),邏輯內(nèi)存(logical memory),
 虛擬內(nèi)存(virtual memory)。UIO驅(qū)動(dòng)的編寫(xiě)是就不需要再考慮這些繁瑣的細(xì)節(jié)。
 
 第二個(gè)任務(wù),對(duì)于設(shè)備中斷的應(yīng)答必須在內(nèi)核空間進(jìn)行。所以在內(nèi)核空間有一小部分代碼
 用來(lái)應(yīng)答中斷和禁止中斷,但是其余的工作全部留給用戶空間處理。
 
 如果用戶空間要等待一個(gè)設(shè)備中斷,它只需要簡(jiǎn)單的阻塞在對(duì) /dev/uioX的read()操作上。
 當(dāng)設(shè)備產(chǎn)生中斷時(shí),read()操作立即返回。UIO 也實(shí)現(xiàn)了poll()系統(tǒng)調(diào)用,你可以使用
 select()來(lái)等待中斷的發(fā)生。select()有一個(gè)超時(shí)參數(shù)可以用來(lái)實(shí)現(xiàn)有限時(shí)間內(nèi)等待中斷。
 
 對(duì)設(shè)備的控制還可以通過(guò)/sys/class/uio下的各個(gè)文件的讀寫(xiě)來(lái)完成。你注冊(cè)的uio設(shè)備將會(huì)出現(xiàn)在該目錄下。
 假如你的uio設(shè)備是uio0那么映射的設(shè)備內(nèi)存文件出現(xiàn)在 /sys/class/uio/uio0/maps/mapX,對(duì)該文件的讀寫(xiě)就是
 對(duì)設(shè)備內(nèi)存的讀寫(xiě)。

 如下的圖描述了uio驅(qū)動(dòng)的內(nèi)核部分,用戶空間部分,和uio 框架以及內(nèi)核內(nèi)部函數(shù)的關(guān)系。


 Figure 1: uio_architecture
 
 詳細(xì)的UIO驅(qū)動(dòng)的編寫(xiě)可以參考 drivers/uio/下的例子,以及Documentation/DocBook/uio-howto.tmpl
 //tmpl格式的文件可以借助 docbook-utils (debian下)工具轉(zhuǎn)化為pdf或者h(yuǎn)tml合格等。
 
 ---------3----------- “uio 核心的實(shí)現(xiàn) 和 uio驅(qū)動(dòng)的內(nèi)核部分的關(guān)系“詳談
 重要的結(jié)構(gòu):
       struct uio_device {
    struct module       *owner;
    struct device       *dev; //在__uio_register_device中初始化
    int         minor; // 次設(shè)備id號(hào),uio_get_minor
    atomic_t        event; //中斷事件計(jì)數(shù)
    struct fasync_struct    *async_queue;//該設(shè)備上的異步等待隊(duì)列//
                                                               // 關(guān)于 “異步通知“ //參見(jiàn)LDD3第六章
    wait_queue_head_t   wait; //該設(shè)備上的等待隊(duì)列,在注冊(cè)設(shè)備時(shí)(__uio_register_device)初始化
    int         vma_count;
    struct uio_info     *info;// 指向用戶注冊(cè)的uio_info,在__uio_register_device中被賦值的
    struct kobject      *map_dir;
    struct kobject      *portio_dir;
};  

      /*
 * struct uio_info - UIO device capabilities
 * @uio_dev:        the UIO device this info belongs to
 * @name:       device name
 * @version:        device driver version
 * @mem:        list of mappable memory regions, size==0 for end of list
 * @port:       list of port regions, size==0 for end of list
 * @irq:        interrupt number or UIO_IRQ_CUSTOM
 * @irq_flags:      flags for request_irq()
 * @priv:       optional private data
 * @handler:        the device's irq handler
 * @mmap:       mmap operation for this uio device
 * @open:       open operation for this uio device
 * @release:        release operation for this uio device
 * @irqcontrol:     disable/enable irqs when 0/1 is written to /dev/uioX
 */     
struct uio_info {
    struct uio_device   *uio_dev; // 在__uio_register_device中初始化
    const char      *name; // 調(diào)用__uio_register_device之前必須初始化
    const char      *version; //調(diào)用__uio_register_device之前必須初始化
    struct uio_mem      mem[MAX_UIO_MAPS];
    struct uio_port     port[MAX_UIO_PORT_REGIONS];
    long            irq; //分配給uio設(shè)備的中斷號(hào),調(diào)用__uio_register_device之前必須初始化
    unsigned long       irq_flags;// 調(diào)用__uio_register_device之前必須初始化
    void            *priv; //
    irqreturn_t (*handler)(int irq, struct uio_info *dev_info); //uio_interrupt中調(diào)用,用于中斷處理
                                                                                                   // 調(diào)用__uio_register_device之前必須初始化
    int (*mmap)(struct uio_info *info, struct vm_area_struct *vma); //在uio_mmap中被調(diào)用,
                                                                                                                // 執(zhí)行設(shè)備打開(kāi)特定操作
    int (*open)(struct uio_info *info, struct inode *inode);//在uio_open中被調(diào)用,執(zhí)行設(shè)備打開(kāi)特定操作
    int (*release)(struct uio_info *info, struct inode *inode);//在uio_device中被調(diào)用,執(zhí)行設(shè)備打開(kāi)特定操作
    int (*irqcontrol)(struct uio_info *info, s32 irq_on);//在uio_write方法中被調(diào)用,執(zhí)行用戶驅(qū)動(dòng)的
                                                                                       //特定操作。
};

 先看一個(gè)uio 核心和 uio 設(shè)備之間關(guān)系的圖,有個(gè)整體印象:


                  Figure 2: uio_core_device


 
 uio核心部分是一個(gè)名為"uio"的字符設(shè)備(下文稱(chēng)為“uio核心字符設(shè)備“)。用戶驅(qū)動(dòng)的內(nèi)核部分
 使用uio_register_device向uio核心部分 注冊(cè)u(píng)io設(shè)備。uio 核心的任務(wù)就是管理好這些注冊(cè)的uio
 設(shè)備。這些uio設(shè)備使用的數(shù)據(jù)結(jié)構(gòu)是  uio_device。而這些設(shè)備屬性,比如name, open(),
 release()等操作都放在了uio_info結(jié)構(gòu)中,用戶使用 uio_register_device注冊(cè)這些驅(qū)動(dòng)之前
 要設(shè)置好uio_info。
 uio核心字符設(shè)備注冊(cè)的
 uio_open
 uio_fasync
 uio_release
 uio_poll
 uio_read
 uio_write
 中除了完成相關(guān)的維護(hù)工作外,還調(diào)用了注冊(cè)在uio_info中的相關(guān)方法。比如,在
 uio_open中調(diào)用了uio_info中注冊(cè)的open方法。
 那么這里有一個(gè)問(wèn)題,uio核心字符設(shè)備怎么找到相關(guān)設(shè)備的uio_device結(jié)構(gòu)的呢?
 這就涉及到了內(nèi)核的idr機(jī)制,關(guān)于該機(jī)制可以參考:
 http://blog.csdn.net/ganggexiongqi/article/details/6737389
 在uio.c中,有如下的定義:
 static DEFINE_IDR(uio_idr);
 /* Protect idr accesses */
static DEFINE_MUTEX(minor_lock);
在你調(diào)用uio_register_device(內(nèi)部調(diào)用了__uio_register_device)注冊(cè)你的uio 設(shè)備時(shí),
在__uio_register_device中調(diào)用了uio_get_minor函數(shù),在uio_get_minor函數(shù)中,利用
idr機(jī)制(idr_get_new)建立了次設(shè)備號(hào)和uio_device類(lèi)型指針之間的聯(lián)系。而uio_device指針
指向了代表你注冊(cè)的uio設(shè)備的內(nèi)核結(jié)構(gòu)。在uio核心字符設(shè)備的打開(kāi)方法,uio_open中
先取得了設(shè)備的次設(shè)備號(hào)(iminor(inode)),再次利用idr機(jī)制提供的方法(idr_find)取得了
對(duì)應(yīng)的uio_device類(lèi)型的指針。并且把該指針保存在了uio_listener結(jié)構(gòu)中,以方便以后
使用。

----4---關(guān)于設(shè)備中斷的處理

在__uio_register_device中,為uio設(shè)備注冊(cè)了統(tǒng)一的中斷處理函數(shù)uio_interrupt,
在該函數(shù)中,調(diào)用了uio設(shè)備自己提供的中斷處理函數(shù)handler(uio_info結(jié)構(gòu)中)。
并調(diào)用了uio_event_notify函數(shù)對(duì)uio設(shè)備的中斷事件計(jì)數(shù)器增一, 通知各個(gè)讀進(jìn)程
“有數(shù)據(jù)可讀”。每個(gè)uio設(shè)備的中斷處理函數(shù)都是單獨(dú)注冊(cè)的。

  關(guān)于中斷計(jì)數(shù): uio_listener
            struct uio_listener {
                struct uio_device *dev; //  保存uio設(shè)備的指針,便于訪問(wèn)
                s32 event_count; //跟蹤uio設(shè)備的中斷事件計(jì)數(shù)器
            };
         對(duì)于每一個(gè)注冊(cè)的uio 設(shè)備(uio_device), 都關(guān)聯(lián)一個(gè)這樣的結(jié)構(gòu)。
         它的作用就是跟蹤每個(gè)uio設(shè)備(uio_device)的中斷事件計(jì)數(shù)器值。
         
         在用戶空間進(jìn)行文件打開(kāi)操作(open)時(shí),與uio設(shè)備關(guān)聯(lián)的uio_listener結(jié)構(gòu)就被分配,
         指向它的指針被保存在filep指針的private_data字段以供其他操作使用。
         在用戶空間執(zhí)行文件關(guān)閉操作時(shí),和uio設(shè)備關(guān)聯(lián)的uio_listener結(jié)構(gòu)就被銷(xiāo)毀。
         
         在uio設(shè)備注冊(cè)時(shí),uio core會(huì)為設(shè)備注冊(cè)一個(gè)通用的中斷處理函數(shù)(uio_interrupt),
         在該函數(shù)中,會(huì)調(diào)用uio設(shè)備自身的中斷處理函數(shù)(handler). 中斷發(fā)生時(shí),
         uio_event_notify將被調(diào)用,用來(lái)對(duì)設(shè)備的中斷事件計(jì)數(shù)器()增一,并通知各讀進(jìn)程,
         有數(shù)據(jù)可讀。
         
         uio_poll 操作判斷是否有數(shù)據(jù)可讀的依據(jù)就是 listener中的中斷事件計(jì)數(shù)值
         (event_count)和uio設(shè)備中的中斷事件計(jì)數(shù)器值不一致(前者小于后者)。因?yàn)?br>         listener的值除了在執(zhí)行文件打開(kāi)操作時(shí)被置為被賦值外,只在uio_read操作中
         被更新為uio設(shè)備的中斷事件計(jì)數(shù)器值。    
         
 疑問(wèn)1:
 對(duì)于中斷事件計(jì)數(shù)器,uio_device中定義為 atomic_t 類(lèi)型,又有
             typedef struct {
                int counter;
            } atomic_t;
   需不需要考慮溢出問(wèn)題?
   同樣的問(wèn)題存在在uio_listener的event_count字段。
   
   關(guān)于uio_device的event字段 uio_howto中:
   event: The total number of interrupts handled by the driver since the last time the device node
               was read.
   【如果中斷事件產(chǎn)生的頻率是100MHZ的話,(2^32)/(10^8) = 42 秒 】counter計(jì)數(shù)器就會(huì)
   溢出。所以,依賴(lài)于counter的操作可能會(huì)出現(xiàn)問(wèn)題。//補(bǔ)充:中斷發(fā)生的頻率最多為kHz不會(huì)是 Mhz,所以[]中的假設(shè)是不合理的,但是溢出會(huì)發(fā)生,而且,依賴(lài)counter值的應(yīng)用可能會(huì)出現(xiàn)問(wèn)題??!
   
   我們可以添加一個(gè)timer,在timer 處理函數(shù)中,調(diào)用uio_event_notify增加counter的值,
   很快會(huì)觀察到溢出。<<<<<<< 例子,還沒(méi)有寫(xiě) (^_^)
   //其實(shí),可以在我們注冊(cè)的函數(shù)中,得到uio_device的指針,可以直接修改event的值。
   

   ===========關(guān)于 sysfs文件創(chuàng)建
   sysfs下uio相關(guān)的文件結(jié)構(gòu)如下
  1.  sys  
  2.  ├───uio  
  3.        ├───uio0  
  4.        │     ├───maps  
  5.        │          ├───mapX  
  6.        ├───uio1  
  7.              ├───maps                           
  8.              │    ├───mapX        
  9.              ├───portio  
  10.                    ├───portX  


     其中的uio是uio模塊加載時(shí),uio_init調(diào)用init_uio_class調(diào)用class_register注冊(cè)到內(nèi)核空間的。
     關(guān)于這個(gè)類(lèi)的方法有個(gè)疑問(wèn),就是比如在show_event方法中,
     struct uio_device *idev = dev_get_drvdata(dev);//具體的uio設(shè)備相關(guān)的信息
    這個(gè)uio_device相關(guān)的信息是怎么跟 uio class聯(lián)系上的?
    在調(diào)用__uio_register_device注冊(cè)u(píng)io設(shè)備時(shí),通過(guò)
    
    idev->dev = device_create(&uio_class, parent,
                  MKDEV(uio_major, idev->minor), idev,
                  "uio%d", idev->minor);
     其中,idev就是 uio_device類(lèi)型的指針,它作為drvdata被傳入,
     device_create調(diào)用了device_create調(diào)用了device_create_vargs調(diào)用了dev_set_drvdata。
     這樣在uio class的 show_event方法中,就可以使用
     struct uio_device *idev = dev_get_drvdata(dev);
     得到了uio設(shè)備的結(jié)構(gòu)體的指針。
     
     device_create調(diào)用完畢后在 /sys/class/uio/下就會(huì)出現(xiàn) 代表uio設(shè)備的uioX文件夾,
     其中X為uio設(shè)備的次設(shè)備號(hào)。
     
     往下,就不再啰嗦了。希望有所幫助。
=======================================
參考:  
  1,2 參考了Userspace I/O drivers in a realtime context  Hans J. Koch, Linutronix GmbH
  3,4 參考了 uio.c 分析 http://blog.csdn.net/ganggexiongqi/article/details/6737647                       
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Linux 2.6內(nèi)核的設(shè)備模型
c風(fēng)格的面向?qū)ο?-linux內(nèi)核學(xué)習(xí)
Linux設(shè)備模型(6)_Bus
<2012 11 14> Linux V4L2驅(qū)動(dòng)架構(gòu)解析與開(kāi)發(fā)導(dǎo)引
Linux2.6內(nèi)核platform機(jī)制分析A
Linux I2C驅(qū)動(dòng)完全分析(一)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服