国嵌驱动——硬件访问——第一天

mmap设备操作:
void *mmap(void *addr, size_t len, int port, int flags, int fd, off_t offset);
内存映射函数,负责把文件内容映射到进程的虚拟内存空间,通过对这段内存的修改来实现对文件的修改。
addr:指定映射的起始地址,通常为NULL,由系统指定
len :文件中映射到内存的长度
port:
            PORT_EXEC:映射区可被执行;
            PORT_READ:映射区可被读取;
            PORT_WRITE:映射区可被写入;
flags:
            MAP_SHARED:写入映射区的数据会复制回文件,且允许其他映射该文件的进程共享
            MAP_PRIVATE:对映射区的写入操作会产生一个映射区的复制(copy-on-write),
                                    对此区域的修改不会写回原文件。
offset:
                映射文件中的偏移量。
解除映射:
    int munmap(void *start, size_t length);
注意:内存映射不会增加文件的原来大小。

虚拟内存区域:
一个进程的内存区域可以通过查看/proc/pid/maps文件
例如:cat /proc/1/maps
start   - end     perm     offset     major:minor  inode
00008000-000f1000 r-xp    00000000     1f:03       730        /bin/busybox
000f8000-000fb000 rwxp    000e8000     1f:03       730        /bin/busybox
000fb000-000fd000 rwxp    00000000     00:00       0
0048d000-004ae000 rwxp    00000000     00:00       0          [heap]
4001a000-40037000 r-xp    00000000     1f:03       263        /lib/ld-2.8.so
4003e000-4003f000 r-xp    0001c000     1f:03       263        /lib/ld-2.8.so
4003f000-40040000 rwxp    0001d000     1f:03       263        /lib/ld-2.8.so
40063000-40064000 rwxp    00000000     00:00       0
400c6000-400c7000 rwxp    00000000     00:00       0
40157000-401fc000 r-xp    00000000     1f:03       301        /lib/libm-2.8.so
401fc000-40203000 ---p    000a5000     1f:03       301        /lib/libm-2.8.so
40203000-40204000 r-xp    000a4000     1f:03       301        /lib/libm-2.8.so
40204000-40205000 rwxp    000a5000     1f:03       301        /lib/libm-2.8.so
40205000-40323000 r-xp    00000000     1f:03       295        /lib/libc-2.8.so
40323000-4032b000 ---p    0011e000     1f:03       295        /lib/libc-2.8.so
4032b000-4032d000 r-xp    0011e000     1f:03       295        /lib/libc-2.8.so
4032d000-4032e000 rwxp    00120000     1f:03       295        /lib/libc-2.8.so
4032e000-40331000 rwxp    00000000     00:00       0
bec95000-becb6000 rw-p    00000000     00:00       0          [stack]
ffff0000-ffff1000 r-xp    00000000     00:00       0          [vectors]

Linux内核使用结构vm_area_struct(<linux/mm_types.h>)来描述虚拟内存区域

unsigned long vm_start; //虚拟内存区域起始地址
unsigned long vm_end;   //虚拟内存区域结束地址
unsigned long vm_flags;
/*
  该区域的标记。
  VM_IO:内存映射的IO区域,该标记阻止系统将该区域包含在进程的存放转存(core dump)中。
  VM_RESERVED:内存区域不能被换出。
*/

mmap设备操作:
映射一个设备是指把用户空间的一段地址关联到设备内存上。
当程序读写这段用户空间地址时,它实际上是在访问设备。
mmap设备方法需要完成什么功能?
mmap方法是file_operations结构的成员,在mmap系统调用发出时被调用。
在此之前,内核已经完成了很多工作。mmap设备方法所需要做的就是建立
虚拟地址到物理地址的页表。

int (*mmap)(struct file* ,struct vm_area_struct *);
如何建立页表:
1.使用remap_pfn_range一次建立所以页表;
2.使用nopage VMA方法每次建立一个页表。
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, unsigned long size, pgprot_t prot)
vma:虚拟内存区域指针
addr:虚拟地址的起始值
pfn :要映射的物理地址所在的物理页帧号,可将物理地址>>PAGE_SHIFT得到
size:要映射的区域的大小
prot:VMA的保护属性
例子:mmap设备操作:
int memdev_mmap(struct file *filp, struct vm_area_struct *vma)
{
    vma->vm_flags |= VM_IO;
    vma->vm_flags |= VM_RESERVED;
    
    if(remap_pfn_range(vma, vma->vm_start, virt_to_phys(dev->data)>>PAGE_SHIFT, size, vma->vm_page_prot))
        return -EAGAIN;
    return 0;
}
    

寄存器与内存的区别:
寄存器和RAM的主要不同在于寄存器操作有副作用(side effect 或 边际效果)
读取某个地址时可能导致该地址内容发生变化,比如很多设备的中断状态寄存器
只要一读取,便自动清零。

内存与I/O
在X86处理器中存在I/O空间的概念,I/O空间是相对内存空间而言的,他们是彼此独立
的地址空间,在32位的X86系统中,I/O空间大小为64K, 内存空间大小为4G。

 ————————
|        |
|  CPU   | ——————————————————————————————————>
|        |      |                 |
 ————————       |                 |
                |                 |
          内存地V址空间      I/O地V址空间
         |——————————————|     ___________
         |    网卡       |    |           |
         |——————————————|    |           |
         |    内存       |    |———————————|
         |——————————————|    |           |
         |    Nand      |    |  ......   |
         |——————————————|    |           |
         |    Nor       |    |———————————|
         |——————————————|
         |   ......     |
         |——————————————|
X86: 支持内存空间、IO空间
ARM: 只支持内存空间
MIPS:只支持内存空间
PPC: 只支持内存空间

IO端口与IO内存
IO端口:当一个寄存器或内存位于IO空间时,称为IO端口。
IO内存:当一个寄存器或内存位于内存空间时,称IO内存。

操作IO端口:
1.申请
#include <linux/ioport.h>
struct resource * request_region(resource_size_t start, resource_size_t n, const char *name);
系统端口分配记录于/proc/ioports中。
2.访问
#include <asm/io.h>
unsigned in[bwl](unsigned port);
void out[bwl](unsigned char byte, unsigned port)
3.释放
void release_region(resource_size_t start, resource_size_t n);

操作I/O内存
1.申请
request_mem_region(start,n,name)
系统IO内存分配记录于/proc/iomem
2.映射
void *ioremap(phys_addr_t offset, unsigned long size);
3.访问
unsigned ioread[8 16 32](void *addr);
void iowrite[8 16 32](u8 value, void *addr);
旧版:
unsigned read[bwl](address);
unsigned write[bwl](unsigned value, address);
4.释放
void iounmap(void *addr);
void release_mem_region(unsigned long start, unsigned long len);

Linux内核使用struct miscdevice来描述混杂设备
    混杂设备是字符设备,相同的主设备号(10),所有的混杂设备形成一个链表
对设备访问时内核根据次设备号查找到相应的混杂设备。
struct miscdevice
{
    int minor;/*次设备号*/
    const char *name;/*设备名*/
    const struct file_operations *fops;/*文件操作*/
    struct list_head list;
    struct device *parent;
    struct device *this_device;
}

注册混杂设备:
int    misc_register(struct miscdevice *misc);
注销混杂设备:
int    misc_deregister(struct miscdevice *misc);

上拉电阻/下拉电阻:
上拉电阻:将不确定的信号通过一个电阻与电源相连,固定在高电平。
下拉电阻:将不确定的信号通过一个电阻于地相连,固定在低电平。
上拉是对器件注入电流。
下拉式输出电流。
当一个接有上拉电阻的I/O端口设为输入状态时,它常态为高电平,
可用于检测低电平的输入。
S3C2440有GPA~GPJ九组I/O端口。
GPxCON:00-输入
        01-输出
        10-表示特殊功能
        11-reserved
GPxDAT:用于读写
GPxUP:用于决定是否使用内部上拉电阻
        0-此引脚无内部上拉电阻
        1-此引脚使用内部上拉电阻

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值