內核中與驅動相關的內存操作之九(重映射)

   ioremap()函數也是需要建立新的頁表,但是不會分配內存.它的功能是將一個物理地址轉換成內核需要的虛擬地址(邏輯地址),從而實際硬件的操作.其相反的動作爲iounmap().

 

   

   S3C2440RTC驅動爲例:

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()等類似.
   


 

發佈了131 篇原創文章 · 獲贊 17 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章