文章目錄
常用接口
request_mem_region函數
release_mem_region函數
ioremap函數
iounmap函數
在驅動中的使用
點擊下方閱讀原文可訪問文中超鏈接
對于linux中的驅動來說,在操作硬件這個部分其實和在單片機中操作硬件幾乎是一樣的,不同的只是在linux中使用的是虛擬地址(如果開啟了MMU),而在單片機中都是直接操作物理地址;在linux中驅動有一套比較規范的流程而已。
MMU是一個硬件,主要功能是實現虛擬地址到物理地址之間的轉換和內存保護(比如權限管控、進程隔離)。
還是像學單片機一樣,前面鋪墊一大堆,但任然從點亮第一顆led燈開始。
常用接口
位于頭文件:include\linux\ioport.h
request_mem_region函數
此函數用以在映射物理地址之前向內核發出申請,這樣可以防止這個資源在其它地方再次被占用而造成訪問沖突。
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
release_mem_region函數
此函數用以釋放使用request_mem_region申請的資源。
#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n))
ioremap函數
位于頭文件:include\asm-generic\io.h
此函數用以映射一段物理地址到虛擬地址。
void __iomem *ioremap(phys_addr_t addr, size_t size)
iounmap函數
此函數用以取消ioremap所做的映射。
void iounmap(volatile void __iomem *addr)
在驅動中的使用
為了測試簡便,所以將硬件操作放在了open
和release
接口里面,在應用程序中open
和close
函數之間加一段延時就可以看到對應的led燈亮一段時間后熄滅。
typedef struct {
unsigned int con;
unsigned int dat;
unsigned int pud;
unsigned int drv;
unsigned int conpdn;
unsigned int pudpdn;
}gpio_regTypeDef;
#define GPJ0_BASE 0xe0200240
void __iomem *io_va;
struct resource *data_req;
static int test_open (struct inode *inode, struct file *file)
{
int ret = 0;
unsigned int tmp;
data_req = request_mem_region(GPJ0_BASE,sizeof(gpio_regTypeDef),"gpj0_reg");
if(!data_req)
{
ret = -EIO;
return ret;
}
io_va = ioremap(GPJ0_BASE,sizeof(gpio_regTypeDef));
if(!io_va)
{
ret = -EINVAL;
goto failed_ioremap;
}
/*配置引腳gpj0_3為輸出*/
tmp = readl(&((gpio_regTypeDef *)io_va)->con);
tmp |= (0x1 << 3);
writel(tmp,&((gpio_regTypeDef *)io_va)->con);
/*配置gpj0_3輸出低電平*/
tmp = readl(&((gpio_regTypeDef *)io_va)->dat);
tmp &= ~(0x1 << 3);
writel(tmp,&((gpio_regTypeDef *)io_va)->dat);
return ret;
failed_ioremap:
release_mem_region(GPJ0_BASE,sizeof(gpio_regTypeDef));
return ret;
}
static int test_close (struct inode *inode, struct file *file)
{
unsigned int tmp;
/*配置gpj0_3輸出低電平*/
tmp = readl(&((gpio_regTypeDef *)io_va)->dat);
tmp |= (0x1 << 3);
writel(tmp,&((gpio_regTypeDef *)io_va)->dat);
iounmap(io_va);
release_mem_region(GPJ0_BASE,sizeof(gpio_regTypeDef));
return 0;
}
測試源碼獲取:點我