首页 > 技术文章 > linux使用i/o内存访问外设

defen 2016-05-06 15:56 原文

一。linux中访问外设的方法.
1.IO端口(IO port)
linux系统给外设分配不同的端口号,linux利用端口号来访问设备(驱动) (cpu x86)

cpu访问外设通过端号,访问通过地址

gec@ubuntu:/mnt/hgfs/tea/demo2$ cat /proc/ioports
0000-0cf7 : PCI Bus 0000:00
0000-001f : dma1
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-0060 : keyboard
0064-0064 : keyboard
0070-0071 : rtc0
0080-008f : dma page reg
00a0-00a1 : pic2
00c0-00df : dma2
00f0-00ff : fpu
0170-0177 : 0000:00:07.1
0170-0177 : ata_piix


2.IO内存 (IO mem) ---> ARM/MPIS
cpu访问外设的方法和访问内存方法都是一样,都是根据地址来方问。
外设(GPIO,ADC,WDT)都内存一样,是统一编址。

 


二。LINUX中IO内存的使用
思想:申请IO内存区-->动态是映射--->使用虚拟地址--> 解除动态映射击--->释放IO内存区。

1.IO内存的申请
struct resource *request_mem_region(resource_size_t start,resource_size_t n,const char *name)
参数值:
start-->资源的内存区的开始地址(物理地址)
n ----->物理内存区的大小
name --->自定义内存区的名字 cat /proc/iomem


返回值:
struct resource * -->申请到的资源
NULL--->申请失败



2.释放IO内存
void release_mem_region(resource_size_t start,resource_size_t n)


例:
struct resource *ledp=request_mem_region(OxE0200280,8,"gpj2_led");


----------------------------------------------------------------------------
3.IO内存的动态映射
void __iomem * ioremap (unsigned long phys_addr, unsigned long size)
参数:
unsigned long phys_addr--》需要映射的物理内存的地址(开始地址)
unsigned long size -->需要映射的物理内存大小
返值:
void __iomem * --->映射后虚拟地址(开始地址)
NULL --->失败

 

4。IO内存动态映射解除
void iounmap(void *addr)
void *addr--->映射后的虚拟地址


例:
#define OxE0200280 GPJ2CON_PA
unsigned int *GPJ2CON_VA =ioremap(GPJ2CON_PA,8);
unsigned int *GPJ2DAT_VA =GPJ2CON_VA+1;


iounmap(GPJ2CON_VA);


-------------------------------------------------
5.访问虚拟地址的函数(读写)
1.
unsigned int ioread32(void __iomem *addr)


void __iomem *addr--->虚拟地址
unsigned int ---》数据

 

void iowrite32(u32 b, void __iomem *addr);


例:

unsigned int a=ioread(GPJ2CON_VA);
a &= ;

iowrite32(a,GPJ2CON_VA)

2.
static inline u32 readl(const volatile void __iomem *addr)
static inline void writel(unsigned int b, volatile void __iomem *addr)

3.
static inline u32 __raw_readl(const volatile void __iomem *addr)
static inline void __raw_writel(u32 v, volatile void __iomem *addr)

 

实例:LED字符设备的驱动模块、

#include <linux/module.h>
#include <linux/kernel.h>
#include<linux/cdev.h>

struct cdev chrdev3;
unsigned int TestMajor=0;
unsigned int TestMinor=0;
#define *** GPJ*CON_PA
#define *** GPJ*DAT_PA
unsigned int *GPJ2CON_VA;
dev_t dev_no;

 

int testopen(struct inode *inode, struct file *file)
{
//LED输出
printk("led init \n");

}
int testclose (struct inode *inode, struct file *file);
{
printk("close");
return 0;

}
ssize_t testwrtie(struct file *, char __user *usr, size_t len, loff_t *off)
{
char buf[12];
copy_from_user(buf,usr,);
buf[12];
//if(buf[]=='1')
// led点明
printk(,buf);


}
ssize_t testread(struct file *, char __user *usr, size_t len, loff_t *);
{
char buf='r';
read_led;
copy_to_user(usr,buf,);
}

struct file_operations fops= --->结构体初始化 .---???????????????
{ .owner=THIS_MODULE,
.open=testopen,
.write=testwrite,
.release=testclose,
}


static int __init test_init(void) //入口函数
{
printk("hello world!\n"); //相当于printf()
int ret;
dev_no =MKDEV(TestMajor,TestMinor)


if(dev_no>0)
{
ret=register_chrdev_region(dev_no, 1,"chrdev_test");//静态注册设备号

}
else //动态申请设备号
{

alloc_chrdev_region(&dev_no,TestMinor, 1,"chrdev_test");

}


if(ret<0)
{
return ret;
}


cdev_init(&chrdev3,&fops);
cdev.owner=THIS_MODULE;
cdev_add(&chrdev3,dev_no,1);

request_mem_region();

GPJ2CON_VA =ioremap(GPJ2CON_PA,8);
GPJ2DAT_VA =GPJ2CON_VA+1;

return 0;
}

static void __exit test_exit(void) //出口函数
{
unregister_chrdev_region(dev_no, 1);
cdev_del(&chrdev3);
}


module_init(test_init); //驱动的入口 #insmod *.ko
module_exit(test_exit); //驱动的出口 #rmmod *.ko

//#modinfo *.ko 可以查看module的信息
MODULE_AUTHOR("fbx@GEC");
MODULE_DESCRIPTION("the first module of drivers");
MODULE_LICENSE("GPL");
MODULE_VERSION("V1.0");

 

  1 #include<linux/module.h>
  2 #include<linux/kernel.h>
  3 #include<linux/cdev.h>
  4 #include<linux/fs.h>
  5 #include<linux/kdev_t.h>
  6 #include<linux/types.h>
  7 #include<linux/uaccess.h>
  8 #include<linux/string.h>
  9 #include<linux/ioport.h>
 10 #include<asm/io.h>
 11 
 12 #define  GPJ2CON_PA 0xe0200280
 13 #define  GPJ2DAT_PA 0xe0200280
 14 unsigned int *GPJ2CON_VA;
 15 unsigned int *GPJ2DAT_VA;
 16 struct cdev chrdev;
 17 struct resource *res;
 18 unsigned int TestMajor=0;
 19 unsigned int TestMinor=0;
 20 dev_t dev_no;
 21 int ret;
 22 
 23 int testopen(struct inode *inode,struct file *file)
 24 {
 25     unsigned int a = ioread32(GPJ2CON_VA);
 26     a |= 0x1111;
 27     iowrite32(a,GPJ2CON_VA);
 28     printk("cdev init\n");
 29     return 0;
 30     
 31 }
 32 ssize_t testwrite(struct file *file, const char __user *usr, size_t len, loff_t *off)
 33 {
 34     unsigned int a;
 35     
 36     copy_from_user(&a,usr,len);
 37     iowrite32(a,GPJ2DAT_VA);
 38     
 39 
 40 }
 41 ssize_t testread(struct file *file, char __user *usr, size_t len, loff_t *off)
 42 {
 43     unsigned int a = ioread32(GPJ2DAT_VA);
 44     copy_to_user(usr,&a,len);
 45 
 46 
 47 }
 48 int testrelease(struct inode *inode, struct file *file)
 49 {
 50     printk("close\n");
 51     return 0;
 52 
 53 }
 54 
 55 struct file_operations fops=
 56 {
 57     .owner=THIS_MODULE,
 58     .open = testopen,
 59     .write = testwrite,
 60     .read = testread,
 61     .release = testrelease,
 62 };
 63 static int __init test_init(void)
 64 {
 65     dev_no = MKDEV(TestMajor,TestMinor);
 66     if(dev_no>0)
 67     {
 68         ret = register_chrdev_region(dev_no,1,"chrdev_test");    
 69     }
 70     else
 71     {
 72         alloc_chrdev_region(&dev_no,0,1,"chrdev_test");
 73     }
 74     if(ret<0)
 75     {
 76         return ret;
 77     }
 78     cdev_init(&chrdev,&fops);
 79     chrdev.owner=THIS_MODULE;
 80     cdev_add(&chrdev,dev_no,1);
 81     res = request_mem_region(GPJ2CON_PA,8,"gpj2_led");
 82     GPJ2CON_VA = ioremap(GPJ2CON_PA,8);
 83     GPJ2DAT_VA = GPJ2CON_VA + 1;
 84     return 0;
 85 }
 86 
 87 static int __exit test_exit(void)
 88 {
 89     unregister_chrdev_region(dev_no,1);
 90     cdev_del(&chrdev);
 91     iounmap(GPJ2CON_VA);
 92     release_mem_region(GPJ2CON_PA,8);
 93     return 0;
 94 }
 95 
 96 module_init(test_init);
 97 module_exit(test_exit);
 98 
 99 
100 MODULE_AUTHOR("FENG");
101 MODULE_DESCRIPTION("the first module of char drivers");
102 MODULE_LICENSE("GPL");
103 MODULE_VERSION("V1.0");

test.c 使一盏led循环点灭

 1 #include<stdio.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <errno.h>
 5 #include <unistd.h>
 6 #include <string.h>
 7 
 8 int main()
 9 {
10 unsigned int ledconfig;
11 char buf1[20];
12 int fd = open("/dev/chrdev_test",O_RDWR);
13 if(fd<0)
14 perror("open() error!\n");
15 bzero(buf1,20);
16 while(1)
17 {
18 read(fd,&ledconfig,4);
19 ledconfig ^=0x1;
20 write(fd,&ledconfig,4);
21 sleep(1);
22 }
23 }

 

推荐阅读