Linux的uio机制架构详解(三)

一个设备驱动的主要任务有两个: 
1. 存取设备的内存 
2. 处理设备产生的中断

对于第一个任务,UIO 核心实现了mmap()可以处理物理内存(physical memory),逻辑内存(logical memory), 
虚拟内存(virtual memory)。UIO驱动的编写是就不需要再考虑这些繁琐的细节。

第二个任务,对于设备中断的应答必须在内核空间进行。所以在内核空间有一小部分代码 
用来应答中断和禁止中断,但是其余的工作全部留给用户空间处理。

如果用户空间要等待一个设备中断,它只需要简单的阻塞在对 /dev/uioX的read()操作上。 
当设备产生中断时,read()操作立即返回。UIO 也实现了poll()系统调用,你可以使用 
select()来等待中断的发生。select()有一个超时参数可以用来实现有限时间内等待中断。

对设备的控制还可以通过/sys/class/uio下的各个文件的读写来完成。你注册的uio设备将会出现在该目录下。 
假如你的uio设备是uio0那么映射的设备内存文件出现在 /sys/class/uio/uio0/maps/mapX,对该文件的读写就是 
对设备内存的读写。 
如下的图描述了uio驱动的内核部分,用户空间部分,和uio 框架以及内核内部函数的关系。 
这里写图片描述

这里写图片描述

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_portio {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> kobject kobj;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_port *port;
};

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
 * struct uio_port - description of a UIO port region
 * @name:       name of the port region for identification
 * @start:      start of port region
 * @size:       size of port region
 * @porttype:       type of port (see UIO_PORT_* below)
 * @portio:     for use by the UIO core only.
 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_port {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>      *name;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>       start;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>       size;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>         porttype;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_portio   *portio;
};

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* defines for uio_port->porttype */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define UIO_PORT_NONE   0</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define UIO_PORT_X86    1</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define UIO_PORT_GPIO   2</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define UIO_PORT_OTHER  3</span>


  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*
  * struct uio_mem - description of a UIO memory region
 * @name:       name of the memory region for identification
 * @addr:       address of the device's memory
 * @size:       size of IO
 * @memtype:        type of memory addr points to
 * @internal_addr:  ioremap-ped version of addr, for driver internal use
 * @map:        for use by the UIO core only.
 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_mem {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>      *name;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 内存映射的名字</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>       addr; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 内存块的地址</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>       size; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//addr所指向的内存块的大小</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>         memtype; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//UIO_MEM_PHYS,UIO_MEM_LOGICAL(kmalloc()),UIO_MEM_VIRTUAL( virtual memory)</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> __iomem        *internal_addr; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// If you have to access this memory region from within your kernel module,</span>
                                                               <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// you will want to map it internally by using something like ioremap().</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_map      *map;
};

 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_map {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> kobject kobj;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_mem *mem;
};


 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> vm_operations_struct uio_vm_ops = {
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.open</span> = uio_vma_open,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.close</span> = uio_vma_close,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.fault</span> = uio_vma_fault,
};
 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> device_attribute uio_class_attributes[] = {
    __ATTR(name, S_IRUGO, show_name, <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>),
    __ATTR(version, S_IRUGO, show_version, <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>),
    __ATTR(event, S_IRUGO, show_event, <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>),
    {}
};
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* UIO class infrastructure */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> class uio_class = {
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.name</span> = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"uio"</span>,<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// /sys/class/uio</span>
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.dev_attrs</span> = uio_class_attributes,
};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> file_operations uio_fops = {
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.owner</span>      = THIS_MODULE,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.open</span>       = uio_open,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.release</span>    = uio_release,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.read</span>       = uio_read,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.write</span>      = uio_write,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.mmap</span>       = uio_mmap,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.poll</span>       = uio_poll,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.fasync</span>     = uio_fasync,
    <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.llseek</span>     = noop_llseek,
};

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Protect idr accesses */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> DEFINE_MUTEX(minor_lock);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> DEFINE_IDR(uio_idr);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//关于idr机制,参见 http://blog.csdn.net/ganggexiongqi/article/details/6737389</span>

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_device {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> module       *owner;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> device       *dev; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//在__uio_register_device中初始化</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>         minor; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 次设备id号,uio_get_minor</span>
    atomic_t        event; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//中断事件计数</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> fasync_struct    *async_queue;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//该设备上的异步等待队列//</span>
                                                               <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关于 “异步通知“ //参见LDD3第六章</span>
    wait_queue_head_t   wait; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//该设备上的等待队列,在注册设备时(__uio_register_device)初始化</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>         vma_count;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_info     *info;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 指向用户注册的uio_info,在__uio_register_device中被赋值的</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> kobject      *map_dir;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> kobject      *portio_dir;
};  
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*
 * 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
 */</span>     
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_info {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_device   *uio_dev; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 在__uio_register_device中初始化</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>      *name; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 调用__uio_register_device之前必须初始化</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>      *version; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//调用__uio_register_device之前必须初始化</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_mem      mem[MAX_UIO_MAPS];
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_port     port[MAX_UIO_PORT_REGIONS];
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>            irq; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//分配给uio设备的中断号,调用__uio_register_device之前必须初始化</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>       irq_flags;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 调用__uio_register_device之前必须初始化</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>            *priv; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span>
    irqreturn_t (*handler)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> irq, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_info *dev_info); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//uio_interrupt中调用,用于中断处理</span>
                                                                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 调用__uio_register_device之前必须初始化</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> (*mmap)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_info *info, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> vm_area_struct *vma); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//在uio_mmap中被调用,</span>
                                                                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 执行设备打开特定操作</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> (*open)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_info *info, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> inode *inode);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//在uio_open中被调用,执行设备打开特定操作</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> (*release)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_info *info, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> inode *inode);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//在uio_device中被调用,执行设备打开特定操作</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> (*irqcontrol)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> uio_info *info, s32 irq_on);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//在uio_write方法中被调用,执行用户驱动的</span>
                                                                                       <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//特定操作。</span>
};</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li><li style="box-sizing: border-box; padding: 0px 5px;">100</li><li style="box-sizing: border-box; padding: 0px 5px;">101</li><li style="box-sizing: border-box; padding: 0px 5px;">102</li><li style="box-sizing: border-box; padding: 0px 5px;">103</li><li style="box-sizing: border-box; padding: 0px 5px;">104</li><li style="box-sizing: border-box; padding: 0px 5px;">105</li><li style="box-sizing: border-box; padding: 0px 5px;">106</li><li style="box-sizing: border-box; padding: 0px 5px;">107</li><li style="box-sizing: border-box; padding: 0px 5px;">108</li><li style="box-sizing: border-box; padding: 0px 5px;">109</li><li style="box-sizing: border-box; padding: 0px 5px;">110</li><li style="box-sizing: border-box; padding: 0px 5px;">111</li><li style="box-sizing: border-box; padding: 0px 5px;">112</li><li style="box-sizing: border-box; padding: 0px 5px;">113</li><li style="box-sizing: border-box; padding: 0px 5px;">114</li><li style="box-sizing: border-box; padding: 0px 5px;">115</li><li style="box-sizing: border-box; padding: 0px 5px;">116</li><li style="box-sizing: border-box; padding: 0px 5px;">117</li><li style="box-sizing: border-box; padding: 0px 5px;">118</li><li style="box-sizing: border-box; padding: 0px 5px;">119</li><li style="box-sizing: border-box; padding: 0px 5px;">120</li><li style="box-sizing: border-box; padding: 0px 5px;">121</li><li style="box-sizing: border-box; padding: 0px 5px;">122</li><li style="box-sizing: border-box; padding: 0px 5px;">123</li><li style="box-sizing: border-box; padding: 0px 5px;">124</li><li style="box-sizing: border-box; padding: 0px 5px;">125</li><li style="box-sizing: border-box; padding: 0px 5px;">126</li><li style="box-sizing: border-box; padding: 0px 5px;">127</li><li style="box-sizing: border-box; padding: 0px 5px;">128</li><li style="box-sizing: border-box; padding: 0px 5px;">129</li><li style="box-sizing: border-box; padding: 0px 5px;">130</li><li style="box-sizing: border-box; padding: 0px 5px;">131</li><li style="box-sizing: border-box; padding: 0px 5px;">132</li><li style="box-sizing: border-box; padding: 0px 5px;">133</li><li style="box-sizing: border-box; padding: 0px 5px;">134</li><li style="box-sizing: border-box; padding: 0px 5px;">135</li></ul>
  1. 函数: static int __init uio_init(void) 
    功能:申请字符设备号,设备,并注册到系统中,注册uio_class到系统中 
    调用模块:init_uio_class() 
    执行流程: 
    申请字符设备号,设备,并注册到系统中,注册uio_class到系统中 //init_uio_class 
    //创建”/sys/class/uio”


    1. 函数:uio_exit 
      参数: 
      返回值: 
      功能:注销uio_class,注销字符设备编号,删除设备 
      调用模块:release_uio_class 
      执行流程: 
      注销uio_class,注销字符设备编号,删除设备 //release_uio_class

    2. 函数:static void release_uio_class(void) 
      参数: 
      返回值: 
      功能:注销uio_class,注销字符设备编号,删除设备 
      调用模块: 
      执行流程: 
      注销uio_class//class_unregister 
      注销字符设备编号,删除设备 //uio_major_cleanup
  2. 函数:static int init_uio_class(void) 
    参数: 
    返回值: 
    功能:申请字符设备号,设备,并注册到系统中,注册uio_class到系统中 
    调用模块: uio_major_init() 
    class_register() 
    执行流程: 
    申请字符设备编号,设备,并初始化//uio_major_init 
    注册class 类型全局变量uio_class到系统//class_register 
    //ls -l /sys/class 查看

  3. 函数: static int uio_major_init(void) 
    参数: 
    返回值: 
    功能:申请字符设备编号,设备,并初始化 
    调用模块: alloc_chrdev_region() 
    cdev_alloc() 
    kobject_set_name() 
    cdev_add() 
    执行流程: 
    申请字符设备编号(多个)//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 
    添加字符设备到系统中 //cdev_add,调用成功后,我们的设备就“活了” 
    // cat /proc/devices ,可以查看到分配到主设备号 
    保存主设备号到全局变量uio_major 
    保存设备指针到全局变量uio_cdev

    返回

  4. 函数:static void uio_major_cleanup(void) 
    参数: 
    返回值: 
    功能:注销字符设备编号,删除设备 
    调用模块:unregister_chrdev_region 
    执行流程: 
    注销字符设备编号//unregister_chrdev_region 
    删除设备uio_cdev //cdev_del

file_operations 
7. 
函数:static int uio_open(struct inode *inode, struct file *filep) 
参数:inode: 
filep: 
返回值: 
功能:获得和次设备号关联的uio_device指针,创建一个辅助变量listener, 并调用 
info指向的uio_info结构中的open方法 
调用模块: 
执行流程: 
获得保护uio_idr的锁 //mutex_lock 
从inode 结构中获取次编号 //iminor 
获得和次编号关联的uio_device指针 //idr_find 在那里进行地设置呢??? 
// 在 uio_get_minor 中分配的次设备编号并设置的关联 
放弃锁 //mutex_unlock 
增加uio_device类型指针指向的模块的引用计数 //try_module_get 
分配一个uio_listener类型的listener //kmalloc 
关联listener和 uio_device 指针 
获得uio_device 指向设备的事件计数值,并存入listener //atomic_read 
把listener指针保存到filep->private_data字段 
调用uio_device的info字段指向的uio_info中的open方法//*

  1. 函数:static int uio_release(struct inode *inode, struct file *filep) 
    参数:inode 
    filep 
    返回值: 
    功能:从而调用uio_device的字段info指向的uio_info中的release方法 
    释放辅助结构体listener 
    调用模块: 
    执行流程: 
    从filep->private_data中获得uio_open中保存的listener指针。 
    利用listener指针找到指向uio_device类型结构指针 
    从而调用uio_device的字段info指向的uio_info中的release方法。 
    减少uio_device类型指针指向的模块的引用计数//module_put 
    释放listener结构体 //kfree

  2. 函数:static int uio_fasync(int fd, struct file *filep, int on) 
    参数: 
    fd 
    filep 
    on : 0, 删除;非零,添加 
    返回值: 
    功能: 管理uio_device的async_queue 
    调用模块:fasync_helper() 
    执行流程: 
    从filep->private_data中获得uio_open中保存的listener指针。 
    利用listener指针找到指向uio_device类型结构指针 
    设置uio_device的async_queue//fasync_helper

    1. 函数:static unsigned int uio_poll(struct file *filep, poll_table *wait) 
      参数: filep 
      wait 
      返回值: 
      功能: 使进程在传递到该系统调用的所有文件描述符对应的等待队列上等待, 
      并返回一个是否可以立即无阻塞执行的位掩码 
      调用模块: 
      执行流程: 
      从filep->private_data中获得uio_open中保存的listener指针。 
      利用listener指针找到指向uio_device类型结构指针 
      判断用uio_device类型指针的info字段(uio_info类型)的irq成员不为0,则继续, 
      否则,返回IO错误 
      向poll_table类型的wait表中添加uio_device类型指针指向结构的wait等待队列//poll_wait 
      //!!!! 注意poll_wait并不阻塞 
      如果listener中的事件计数值event_count和uio_device的 
      事件计数值count不一致时// uio_interrupt调用了uio_event_notify对 
      //中断事件计数器增一 
      返回“通常”的数据可读的位掩码

    2. 函数:static ssize_t uio_read(struct file *filep, char __user *buf, 
      size_t count, loff_t *ppos) 
      参数: 
      filep 
      buf 
      count 
      ppos 
      返回值: 
      功能:复制uio设备中断事件计数器的值到用户空间 
      调用模块: 
      执行流程: 
      从filep->private_data中获得uio_open中保存的listener指针 
      利用listener指针找到指向uio_device类型结构指针 
      创建一个等待队列的项 //DECLARE_WAITQUEUE 
      检查确认uio设备的设备info的中断号(0)不为零 
      添加本进程到uio设备的等待队列wait上 // add_wait_queue 
      //由uio_interrupt调用uio_event_notify唤醒 
      REP: 设置当前进程的 “可中断标志” 
      检查是否有中断事件发生, 
      如果有(listener中的中断事件计数值event_count)和uio设备中的中断事件 
      计数器值不一致),则将设备中断计数器的值复制到用户空间 
      并将listener中的中断事件计数值更新为设备的中断事件计数值 
      把当前进程设置为TASK_RUNNING状态, 
      并将当前进程从uio设备的等待队列wait上删除 
      如果文件读时设置了O_NONBLOCK标志, 
      那么,把当前进程设置为TASK_RUNNING状态, 
      并将当前进程从uio设备的等待队列wait上删除 
      返回 -EAGAIN 
      检查当前进程是否有信号处理 //signal_pending 
      //http://blog.chinaunix.net/space.php?uid=20746501&do=blog&cuid=1820175 
      如有,把当前进程设置为TASK_RUNNING状态, 
      并将当前进程从uio设备的等待队列wait上删除 
      并返回 -ERESTARTSYS 
      执行调度 //schedule 
      JMP REP

12. 
函数:static irqreturn_t uio_interrupt(int irq, void *dev_id) 被谁调用呢??? __uio_register_device中设定 
参数: irq 
dev_id 
返回值: 
功能: 调用uio_info中注册的handler中断处理函数,对设备的中断事件计数器增一 
并通知各读进程,有数据可读 
调用模块: 
执行流程: 
从filep->private_data中获得uio_open中保存的listener指针 
调用 uio_device类型指针的info字段(uio_info类型)的handler 
如果属于本设备的中断,并且在handler中已经处理过 
那么对设备的中断事件计数器增一, 
并通知各读进程,有数据可读 //uio_event_notify

13. 
函数:void uio_event_notify(struct uio_info *info) 
参数: 
返回值: 
功能:“触发“ 一个中断事件,对设备的中断事件计数器增一,并通知各读进程,有数据 
可读 
调用模块: 
执行流程: 
从filep->private_data中获得uio_open中保存的listener指针 
对中断事件计数器增一 
唤醒阻塞在设备等待队列wait上的读进程 //wake_up_interruptible 
// 该队列上的进程在uio_read中添加 
向异步等待队列async_queue发出可读信号 //kill_fasync 
14. 
函数:static ssize_t uio_write(struct file *filep, const char __user *buf, 
size_t count, loff_t *ppos) 
参数: 
返回值: 
功能: 读取用户空间的值,并调用uio_device注册的irqcontrol函数 
调用模块: 
执行流程: 
从filep->private_data中获得uio_open中保存的listener指针 
调用 uio_device类型指针的info字段(uio_info类型)的handler 
检验info字段(uio_info类型)的中断号irq 
读取从用户空间传过来的32位的值//copy_from_user 
调用info字段(uio_info类型)的irqcontrol函数,将用户空间传递过来的32位值 
作为参数传入。


  1. 函数:static int uio_mmap(struct file *filep, struct vm_area_struct *vma) 
    参数: 
    返回值: 
    功能: 
    调用模块: 
    执行流程: 
    从filep->private_data中获得uio_open中保存的listener指针 
    调用 uio_device类型指针的info字段(uio_info类型)的handler 
    保存uio_device类型指针到 vma 的vm_private_data 
    返回映射区域的索引(比如 mapX,的X)//uio_find_mem_index 
    计算实际的页数和请求的页数 
    如果实际的页数小于请求的页数那么,返回-EINVAL 
    如果uio设备注册有mmap函数,那么就调用它 
    当内存区域的类型为UIO_MEM_PHYS时, 
    //uio_mmap_physical 
    当内存区域的类型为UIO_MEM_LOGICAL/UIO_MEM_VIRTUAL时, 
    为虚拟内存区域设置操作,和告诉内存不要将 
    该区域交换出去,访问计数器增一//uio_mmap_logical


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值