歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

IO管理一基礎

從CPU連出來一把線:數據總線、地址總線、控制總線,這把線上掛著N個接口,有相同的,有不同的,名字叫做存儲器接口、中斷控制接口、DMA接口、並行接口、串行接口、AD接口……一個設備要想接入,就用自己的接口和總線上的某個匹配接口對接……於是總線上出現了各種設備:內存、硬盤,鼠標、鍵盤,顯示器……

外設都是通過讀寫設備上的寄存器來進行的,外設寄存器也稱為“I/O端口”,而IO端口有兩種編址方式:獨立編址和統一編制。

統一編址:外設接口中的IO寄存器(即IO端口)與主存單元一樣看待,每個端口占用一個存儲單元的地址,將主存的一部分劃出來用作IO地址空間。

統一編址也稱為“I/O內存”方式,外設寄存器位於“內存空間”(很多外設有自己的內存、緩沖區,外設的寄存器和內存統稱“I/O空間”)。

獨立編址(單獨編址):IO地址與存儲地址分開獨立編址,I/O端口地址不占用存儲空間的地址范圍,這樣,在系統中就存在了另一種與存儲地址無關的IO地址,CPU也必須具有專用與輸入輸出操作的IO指令(IN、OUT等)和控制邏輯。

IO端口:當一個寄存器或者內存位於IO空間時;

IO內存:當一個內存或者寄存器位於內存空間時;

在linux使用platform_driver_register()注冊 platform_driver 時, 需要在 platform_driver 的probe() 裡面知道設備的中斷號, 內存地址等資源。

這些資源的描述信息存放在 resource數據結構中, 相同的資源存放在一個樹形樹形數據結構中, 通過父節點, 兄弟節點, 子節點相連。 比如中斷資源, IO端口資源, IO內存資源, DMA資源有不同資源樹。

Linux使用 struct resource來描述一個resouce

struct resource{

resource_size_t start; //資源范圍的開始

resource_size_t end; //資源范圍的結束

constchar *name;

//資源擁有者名

unsignedlong flags; //資源屬性標識

struct resource *parent, *sibling, *child; //資源樹的父節點, 兄弟節點, 字節點指針

};

resource_size_t 由系統決定為uint32_t 或uint64_t 。

在platform機制裡,使用platform_get_resource()來獲取指定的資源類型。

//比如獲取想獲取中斷號,

irq = platform_get_irq(pdev, 0);

intplatform_get_irq(struct platform_device

*dev, unsigned intnum)

{

struct resource *r =

platform_get_resource(dev,IORESOURCE_IRQ, num);

return r ? r->start: -ENXIO;

}

EXPORT_SYMBOL_GPL(platform_get_irq);

platform_get_irq() //會返回一個start, 即可用的中斷號。

//之後便可使用request_irq()來注冊中斷服務函數。

//再比如想要獲取IO內存資源:

struct resource *res_mem = platform_get_resource(pdev, IORESOURCE_MEM,

0);

即可得到一個IO內存資源節點指針, 包括了地址的開始,結束地址等, 該IO內存的長度可用resource_size() 來獲取, 但這段資源只是一個描述, 想真正使用這段IO內存, 還要經過先申請, 再映射的過程。

例如可使用devm_request_mem_region()申請出使用這段IO內存, 再使用ioremap() 將其映射出來, 供用戶空間使用。

devm_request_mem_region(&pdev->dev, res_mem->start, resource_size(res_mem), res_mem->name))

addr_start = ioremap(res_mem->start, resource_size(res_mem));

ioremap() 的返回值即為該資源的虛擬地址。

IO內存的資源是在設備樹源(DeviceTree Source)文件(以.dts結尾)裡給出的,.dts文件就是用來描述目標板硬件信息的,在uboot啟動後, 使用uboot提供的特定API將其獲取出來, 如fdt_getprop(), fdt_path_offset(),這些API包含在uboot 的頭文件

gpio:gpio-controller@1070000000800 {

#gpio-cells

=<2>;

compatible ="cavium,octeon-3860-gpio";

reg =<0x107000x000008000x00x100>;

gpio-controller;

根據其描述, 可知道gpio控制器的IO內存起始地址為:0x107900000800, 長度為0x100.

即從 0x107900000800 到0x1079000008ff.

在目標板裡使用 cat /proc/iomem可以看到:

1070000000800-10700000008ff: /soc@0/gpio-controller@1070000000800

關於i2c 的描述:

twsi0: i2c@1180000001000{

#address-cells

=<1>;

#size-cells

=<0>;

compatible ="cavium,octeon-3860-twsi";

reg =<0x118000x000010000x00x200>;

interrupts =<045>;

clock-rate =<100000>;

IO內存起始地址為: 0x118000001000, 長度為0x200.

從 0x118000001000 到0x1180000011ff.

在目標板裡使用 cat /proc/iomem可以看到:

1180000001000-11800000011ff: /soc@0/i2c@1180000001000

Copyright © Linux教程網 All Rights Reserved