# Linux device driver -- Comunicating with Hardware, CH9
這個章節在討論driver怎麼access I/O ports and I/O memory
# I/O Ports and I/O memory
Every peripheral device is controlled by writing and reading its registers. Most of thetime a device has several registers, and they are accessed at consecutive addresses, either
* in the memory address space or
* in the I/O address space.
從hardware的角度來看,memory regions跟I/O regions是沒有分別的,他們都是透過送出電子訊號到address bus跟control bus(i.e. the read and write signals) 跟從data bus讀或寫東西
CPU設計上(X86)透過read/write I/O ports上的電子訊號跟CPU指令來存取ports,大多數的PCI devices會把register mapping到記憶體來讓使用者讀寫。(這樣就不需要其他特別的CPU指令來讀寫了)
# I/O Registers and Conventional Memory
I/O registers跟RAM有個主要區別是I/O operations有side effects, memory operations則無。(工三小)
driver必須確保讀register的時候,cpu必須不作caching且不能自己亂調read/write指令順序(volatile or memory barrier),linux有提供四個barrier機制來讓hardware自己作保護
* void rmb(void);
* void read_barrier_depends(void);
* void wmb(void);
* void mb(void);
kernel是SMP systems時
* void smp_rmb(void);
* void smp_read_barrier_depends(void);
* void smp_wmb(void);
* void smp_mb(void);
典型的用法在device driver

這個case代表你在開始control之前,要先確保資料全部都設定對了,所以中間插了一個barrier,但用這個會影響performance喔,所以不要亂用,有些architecture有提供進階版的memory barrier.
* #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
# Using I/O Ports
I/O ports就是drivers跟devices溝通的橋樑
# I/O Port Allocation
first, 你一定要有存取這個I/O ports的權限,你要先註冊

這個註冊告訴kernel你想用 n ports, 從first開始(怎麼有點像挑小姐),name就是你的device name. 成功回傳非0,失敗回傳NULL。
所有的port配置可以去/proc/ioports去看,你如果被拒絕就先來這看看

driver被拔掉時(module unload time),應該要把region放掉

你還可以先去check到底能不能用這組I/O ports

但這個不推薦使用,因為他不是atomic的XDDD哪招
也就是說他跟你說你能用但你也不一定能用(check跟之後allocate的動作是分開的),但你永遠就是要用request_region就對了
# Manipulating I/O ports
你要求存取 I/O ports之後,就可以進去read/write了
大部分的hardware會區分出
* 8-bits ports
* 16-bits ports
* 32-bits ports
你不能混和的去存取這些,你只能用不同的functions去存取不同size的ports
kernel用 memory-mapped I/O registers來假裝 port I/O,用remapping port addresses to memory addresses的方式來達成。(這邊是抽象化去作的,driver不會察覺這件事(portability issue)),Linux把這些抽象化的header(architecture-dependent)放在<asm/io.h>,定義了以下存取 I/O ports的方式
* 8bits
* 
* 16 bits
* 
* 32 bits
* 
沒有64bits的版本,就算在64-bits architectures上,最多就是32-bits
還是有例外

# I/O Port Access from User Space
不只是device drivers可以access I/O Ports, user space也可以唷~~~~~
The GNU C library defines them in <sys/io.h>
但必須遵守下面的規定

如果host上沒有這些system calls
* ioperm
* iopl
user space還能透過/dev/port device node去access I/O ports,有兩隻sample code可以參考
* misc-progs/inp.c
* misc-progs/outp.c
# String Operations
除了簡單的 in and out operations. 還有transfer a sequence of bytes, words, or longs to and from a single I/O port or the same size.
* Read or write count bytes starting at the memory address addr. Data is read from or written to the single port port

* Read or write 16-bit values to a single 16-bit port

* Read or write 32-bit values to a single 32-bit port

# Pausing I/O
當processor送資料給bus速度太快時,需要溫柔一點,解法是insert a small delay在每個I/O指令之後。如果你怕device掉資料,用用看這些

# Platform Dependencies
I/O instructions天生的就是高度processor dependent. 每個systems之間的實作是天差地遠的,所以,幾乎所有的 port I/O都是 platform-dependent.



# An I/O Port Example
A digital I/O port, in its most common incarnation,最常見的是 byte-wide I/O location, either memory-mapped or port-mapped.
# An Overview of the PC Parallel Port


# A Sample Driver
short(Simple Hardware Operations and Raw Tests).範例教學,簡單read/write 幾個8bits的 ports,By default, 他使用assigned給parallel interface(一種hardware)的port range.
* Each device node(with a unique minor number) accesses different port.
第一個要讓hardware把access權限給short driver. 如果有衝突的話就去查看 /proc/ioports看看是誰佔用了hardware.
# Using I/O Memory
盡管 I/O ports在X86的世界很受歡迎,但主要跟硬體溝通的機制還是透過 memory-mapped registers and device memory. 兩者都叫做 I/O memory.
I/O memory是什麼
* 因為是被抽象出來的東西所以理解邏輯上他是什麼就好
* 邏輯上就像是一塊RAM讓device跟cpu透過bus溝通
* can hoding video data or network packets
* or implementing device registers that behave just like I/O ports
* access I/O memory的方法是architecture dependent的, bus, deivce怎麼被使用等等
* 這章節主要討論ISA and PCI memory.
* 根據不同平台,I/O memory可能不能透過page tables access.
* 要讓page table能work要讓driver直接摸physical address.
* 代表做I/O之前要做ioremap
* 如果不需要page tables, I/O memory locations跟I/O ports基本一樣,直接讀寫I/O ports就好
* 不管需不需要用到ioremap來access I/O memory,都不鼓勵直接用Pointers去指向IO memory,就算 I/O memory在HW level被定址成就像RAM一樣,一定要用wrapper function來安全的存取(直接用指標可能還是可以work,但很危險(應該是driver在不同平台的portability的考量QQ))
# I/O Memory Allocation and Mapping
I/O memory regions一樣用之前要先配置

所有的I/O memory allocations在 /proc/iomem
不用要free掉


# ioremap在搞什麼?
配置完 I/O memory之後不代表就可以直接用了,你還要確定這塊 I/O memory在kernel裡面是合法使用的,在很多系統上,你不能直接dereferencing a pointer from剛拿到的這塊記憶體的Pointer. 你還需要建立mapping先。就是ioremap的工作。
回頭看

只要裝上了ioremap and iounmap, device driver就可以存取任何 I/O memory address,不管是不是直接mapped到virtual address space.
* 不過從ioremap return回來的addresses不能直接被dereferenced! 必須要用一個特別的kernel functions(雖然有些platform上你這樣做還是能work.但還是一定會遭遇portability的問題).等等會談,先來看看ioremap的interface

# Accessing I/O Memory
要正確的access ioremap後的pointer要用
這邊*addr就是ioremap後得到的address pointer
return value會是從I/O memory讀出來的data

write

read/write


These functions read or write *count* values from the given *buf* to the given *addr*
如果你需要存取block of I/O memory, 可以用這些

如果去看kernel舊一點的code,可以看到許多比較老的操作,還是能work,但不推薦使用。
read 8-bit, 16-bit, and 32-bit data values from I/O memory

write 8-bit, 16-bit, and 32-bit data items

64bits系統可能有
* readq (quad-word = 8bytes)
* writeq
# Ports as I/O memory
有些HW很智障,有些版本用I/O ports, 其他用I/O memory.
從CPU的角度來看沒差,都是吐registers給我,但access method會有差別。為了讓drivers可以好好過生活,不要一直加班,2.6 kernel提供了一個機制
* ioport_map

這個function把count I/O ports轉換成 I/O memory.
這樣driver以後就直接跟I/O memory打交道就好
這個東西沒用到要free掉喔

note: I/O ports還是要先allocated by request_region後才能使用喔
# ISA memory的例子

# sample module


