Linux Device Driver Ch 9 Communicating with Hardware

  • Slides: 29
Download presentation
Linux Device Driver Ch 9 Communicating with Hardware Nickle @ CCU CSIE

Linux Device Driver Ch 9 Communicating with Hardware Nickle @ CCU CSIE

I/O 埠 與 I/O 記憶體 void smp_rmb(void); void smp_read_barrier_depends(void); void smp_wmb(void); void smp_mb(void); –

I/O 埠 與 I/O 記憶體 void smp_rmb(void); void smp_read_barrier_depends(void); void smp_wmb(void); void smp_mb(void); – 同前述函式,但只在支援SMP的system有作用 – 使用barrier的例子: writel(dev->registers. addr, io_destination_address); writel(dev->registers. size, io_size); writel(dev->registers. operation, DEV_READ); wmb( ); writel(dev->registers. control, DEV_GO); – 前面三個writel都完成後,才會進行writel(dev-> ……. )的 動作。

I/O 埠 與 I/O 記憶體 – 某些平台容許「一次設值(atomic_t)」和「一 個記憶體屏障」組成比較有效率的執行單位, 提供以下巨集: #define set_mb(var, value) do {var

I/O 埠 與 I/O 記憶體 – 某些平台容許「一次設值(atomic_t)」和「一 個記憶體屏障」組成比較有效率的執行單位, 提供以下巨集: #define set_mb(var, value) do {var = value; mb( ); } while 0 #define set_wmb(var, value) do {var = value; wmb( ); } while 0 #define set_rmb(var, value) do {var = value; rmb( ); } while 0

使用 I/O 埠 • 在驅動程式真正使用I/O埠之前,必須先 配置: #include <linux/ioport. h> int check_region(unsigned long first, unsigned

使用 I/O 埠 • 在驅動程式真正使用I/O埠之前,必須先 配置: #include <linux/ioport. h> int check_region(unsigned long first, unsigned long n); struct resource *request_region(unsigned long first, unsigned long n, const char *name); void release_region(unsigned long start, unsigned long n); – 大部分的硬體會區分 8 -bit 16 -bit 32 -bit埠, 因此不能像平常存許系統記憶體那樣混用。

使用 I/O 埠 • Linux核心中的<asm/io. h>定義以下用來存取I/O埠的內插函式: unsigned inb(unsigned port); void outb(unsigned char byte, unsigned

使用 I/O 埠 • Linux核心中的<asm/io. h>定義以下用來存取I/O埠的內插函式: unsigned inb(unsigned port); void outb(unsigned char byte, unsigned port); • 讀寫 1 -byte埠,某些平台上port定義成unsigned long,回傳值也因 平台而易。 unsigned inw(unsigned port); void outw(unsigned short word, unsigned port); • 存取 16 -bits埠,在只支援byte I/O的平台不存在。 unsigned inl(unsigned port); void outl(unsigned longword, unsigned port); • 存取 32 -bits埠,longword有可能被宣告成unsigned long或是 unsigned int • 64 -bits port I/O 並不存在。

使用 I/O 埠 • 字串操作(string intructions):某些處理器提供特殊指令能夠 將依連串同等大小的bytes、word、longs讀入、寫出到一個I/O 埠。 • 字串操作的巨集原型: void insb(unsigned port, void

使用 I/O 埠 • 字串操作(string intructions):某些處理器提供特殊指令能夠 將依連串同等大小的bytes、word、longs讀入、寫出到一個I/O 埠。 • 字串操作的巨集原型: void insb(unsigned port, void *addr, unsigned long count); void outsb(unsigned port, void *addr, unsigned long count); • 前者從port讀取count個位元組存入addr位址上的記憶體,後者 將addr位址上的count個位元組寫入port void insw(unsigned port, void *addr, unsigned long count); void outsw(unsigned port, void *addr, unsigned long count); • 同上面的函式,以 16 -bits word為單位。 void insl(unsigned port, void *addr, unsigned long count); void outsl(unsigned port, void *addr, unsigned long count); • 同上面的函式,以 32 -bits long word為單位。

使用 I/O 記憶體 • 直接映射記憶體 – 保留部位記憶位址空間給I/O專用,這些I/O專區不受記憶體管理系 統的管制,也沒有任何虛擬位址會落在I/O專區的範圍內。 • 存取直接映射的I/O記憶區:用指標存取 unsigned int ioread 8(void

使用 I/O 記憶體 • 直接映射記憶體 – 保留部位記憶位址空間給I/O專用,這些I/O專區不受記憶體管理系 統的管制,也沒有任何虛擬位址會落在I/O專區的範圍內。 • 存取直接映射的I/O記憶區:用指標存取 unsigned int ioread 8(void *addr); unsigned int ioread 16(void *addr); unsigned int ioread 32(void *addr); void iowrite 8(u 8 value, void *addr); void iowrite 16(u 16 value, void *addr); void iowrite 32(u 32 value, void *addr); • 如果要存取一序列的資料(repeat): void ioread 8_rep(void *addr, void *buf, unsigned long count); void ioread 16_rep(void *addr, void *buf, unsigned long count); • void ioread 32_rep(void *addr, void *buf, unsigned long count); • void iowrite 8_rep(void *addr, const void *buf, unsigned long count); • void iowrite 16_rep(void *addr, const void *buf, unsigned long count); • void iowrite 32_rep(void *addr, const void *buf, unsigned long count);

使用 I/O 記憶體 – 讀寫一個block,用: unsigned readb(address); unsigned readw(address); unsigned readl(address); – 這些巨集分別從I/O記憶體擷取 8

使用 I/O 記憶體 – 讀寫一個block,用: unsigned readb(address); unsigned readw(address); unsigned readl(address); – 這些巨集分別從I/O記憶體擷取 8 -bits、16 -bits、32 -bits資料值。 void writeb(unsigned value, address); void writew(unsigned value, address); void writel(unsigned value, address); – 用於寫出 8 -bits、16 -bits、32 -bits資料值。 void memset_io(void *addr, u 8 value, unsigned int count); void memcpy_fromio(void *dest, void *source, unsigned int count); void memcpy_toio(void *dest, void *source, unsigned int count); – 這些函式將資料塊搬出、搬入I/O記憶體,類似C函式庫中的 memcpy()一樣。

使用 I/O 記憶體 • 軟體映射的 I/O 記憶體 – 對於要存取I/O記憶體的軟體,必須要有一種辦法 將虛擬位址指向裝置:ioremap() #include <asm/io. h> void

使用 I/O 記憶體 • 軟體映射的 I/O 記憶體 – 對於要存取I/O記憶體的軟體,必須要有一種辦法 將虛擬位址指向裝置:ioremap() #include <asm/io. h> void *ioremap(unsigned long phys_addr, unsigned long size); void *ioremap_nocache(unsigned long phys_addr, unsigned long size); – 大多數平台上,其實做和ioremap()完全一樣。 void iounmap(void * addr); • 如果使用的是完全映射的I/O位址,則ioremap()沒有作 用。

使用 I/O 記憶體 • 位於 1 MB以下的 ISA記憶體 – – 指位於 640 KB ~

使用 I/O 記憶體 • 位於 1 MB以下的 ISA記憶體 – – 指位於 640 KB ~ 1024 KB範圍的的記憶體位址。 ISA記憶體位址範圍屬於非直接映射式。 Silly模組(Simple Tool for Unloading and Printing ISA Data)。 Silly的任務是存取ISA記憶體,他必須把ISA的實體位址 映射到核心的虛擬位址(使用ioremap() )。 #define ISA_BASE 0 x. A 0000 #define ISA_MAX 0 x 100000 /* for general memory access */ /* this line appears in silly_init */ io_base = ioremap(ISA_BASE, ISA_MAX - ISA_BASE);

使用 I/O 記憶體 • Silly的作業方法: – 存取/dev/sillyb (8 -bits存取模式) case M_8: while (count) {

使用 I/O 記憶體 • Silly的作業方法: – 存取/dev/sillyb (8 -bits存取模式) case M_8: while (count) { *ptr = ioread 8(add); add++; count--; ptr++; } break;

使用 I/O 記憶體 – 存取/dev/sillyw和/dev/sillyl case M_32: while (count >= 4) { iowrite 8(*(u

使用 I/O 記憶體 – 存取/dev/sillyw和/dev/sillyl case M_32: while (count >= 4) { iowrite 8(*(u 32 *)ptr, add); add += 4; count -= 4; ptr += 4; } break; – 存取/dev/sillycp,使用memcpy_*io() case M_memcpy: memcpy_fromio(ptr, add, count); break; • 最後使用iounmap(io_base)恢復原狀。

THE END~ Any question?

THE END~ Any question?