您的位置:首页 > 其它

内核中与驱动相关的内存操作之九(重映射)

2014-03-18 16:04 302 查看
ioremap()函数也是需要建立新的页表,但是不会分配内存.它的功能是将一个物理地址转换成内核需要的虚拟地址(逻辑地址),从而实际硬件的操作.其相反的动作为iounmap().

以S3C2440的RTC驱动为例:
struct platform_device s3c_device_rtc = {
.name		  = "s3c2410-rtc",
.id		  = -1,
.num_resources	  = ARRAY_SIZE(s3c_rtc_resource),
.resource	  = s3c_rtc_resource,
};

-->

/* RTC */

static struct resource s3c_rtc_resource[] = {
[0] = {
.start = S3C24XX_PA_RTC,
.end   = S3C24XX_PA_RTC + 0xff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_RTC,
.end   = IRQ_RTC,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_TICK,
.end   = IRQ_TICK,
.flags = IORESOURCE_IRQ
}
};

-->

#define S3C24XX_PA_RTC      S3C2410_PA_RTC

-->

#define S3C2410_PA_RTC	   (0x57000000)

其中,0x5700 0000便是S3C2440的RTC基地址,这里是物理地址,可参见其数据手册.接下来的程序操作中,便是涉及到此寄存器地址的操作.但是这里是物理地址,是不能直接被内核所操作的,必须将其转换为虚拟地址(逻辑地址).如下:

static struct platform_driver s3c2410_rtc_driver = {
.probe		= s3c_rtc_probe,
.remove		= __devexit_p(s3c_rtc_remove),
.suspend	= s3c_rtc_suspend,
.resume		= s3c_rtc_resume,
.driver		= {
.name	= "s3c2410-rtc",
.owner	= THIS_MODULE,
},
};

-->

static int __devinit s3c_rtc_probe(struct platform_device *pdev)
{
... ...;
s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);

... ...;
}

为了保持可移植性,不应把ioremap返回的地址当作指向内存的指针而直接访问,可以借助内核提供的两个API进行读写:readb()和writeb().以S3C2440-RTC为例:

static int __devinit s3c_rtc_probe(struct platform_device *pdev)
{
... ...;
s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);
... ...;
}

-->

1.	static void s3c_rtc_enable(struct platform_device *pdev, int en)
2.	{
3.	    void __iomem *base = s3c_rtc_base;
4.	    unsigned int tmp;
5.
6.	    if (s3c_rtc_base == NULL)
7.	        return;
8.
9.	    if (!en) {
10.	        tmp = readb(base + S3C2410_RTCCON);
11.	        writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);
12.
13.	        tmp = readb(base + S3C2410_TICNT);
14.	        writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);
15.	    } else {
16.	        /* re-enable the device, and check it is ok */
17.
18.	        if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
19.	            dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
20.
21.	            tmp = readb(base + S3C2410_RTCCON);
22.	            writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON);
23.	        }
24.
25.	        if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
26.	            dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n");
27.
28.	            tmp = readb(base + S3C2410_RTCCON);
29.	            writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON);
30.	        }
31.
32.	        if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
33.	            dev_info(&pdev->dev, "removing RTCCON_CLKRST\n");
34.
35.	            tmp = readb(base + S3C2410_RTCCON);
36.	            writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON);
37.	        }
38.	    }
39.	}


小结:

当我们在内核驱动中拿到一个物理地址时,需要将其转换为内核所需要的虚拟地址(逻辑地址),这个动作通过ioremap()来完成,相反动作为iounremap();把物理地址转换为虚拟地址后,为了其可移植性,也通过内核提供的统一的API来实现,分别是writeb()和readb(),当然,这只是针对字节的操作,还有一系列的扩展操作如writel()、readl()等类似.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: