2026年1月20日 星期二
修復 v4l2loopback 0.15.0 的 V4L2 緩衝區佇列問題
2017年6月19日 星期一
手動快速編譯 Ubuntu 16.04 當中 Linux kernel 4.4 裡面的 kernel module
以前寫過一篇「手動快速編譯 Ubuntu 14.04 當中 Linux kernel 裡面的 i915 module」這次是要針對 Ubuntu 16.04 LTS 上面的 Linux kernel 4.4 編譯,步驟都差不多只是有些不一樣的地方。
首先是 Linux kernel git tree 的來源改從 Launchpad 而來,是的! Ubuntu 使用的 Linux kernel 現在也放到 Launchpad 上面了。
$ git clone https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/xenial
然後是編譯的設定檔的位置不一樣了,不過大致上只要找出 config.common.ubuntu config.common.amd64 config.flavour.generic 這三個檔案的位置出來就可以了。
cat ./debian.master/config/config.common.ubuntu ./debian.master/config/amd64/config.common.amd64 ./debian.master/config/amd64/config.flavour.generic > .config
然後這次我的目標是 ubuntu/i915 底下的 kernel module 其它的部份就直接參考前一份文章就可以了。
2016年7月25日 星期一
Disable Secure Boot in shim-signed
The latest Ubuntu kernel updates bring some Secure Boot enhancement for the kernel modules when the Secure Boot is enabled in BIOS settings. However there is no easy way to sign those kernel modules in DKMS packages automatically so far. If we want to use those DKMS packages, we need to disable Secure Boot in BIOS settings temporarily or we can also disable Secure Boot in shim-signed temporarily. The following steps introduced how to disable Secure Boot in shim-signed.
- Open a terminal by Ctrl + Alt + T, execute `sudo update-secureboot-policy` and then select ‘Yes’.

- Enter a temporary password between 8 to 16 digits. (For example, 12345678, we will use this password later.)

- Enter the same password again to confirm.

- Reboot the system and press any key when you see the blue screen (MOK management).

- Select “Change Secure Boot state”.

- Press the corresponding password character and press Enter. Repeat this step several times to confirm previous temporary password like ‘12345678’ in step 2&3. For exmaple, '2' for this screen.

- Select ‘Yes’ to disable Secure Boot in shim-signed.

- Press Enter key to finish the whole procedure.

We can still enable Secure Boot in shim-signed again. Just execute `sudo update-secureboot-policy --enable` and then follow the similar steps above.
2016年5月30日 星期一
編譯 Ubuntu 的 Linux kernel 來使用 USB to RS-232 輸出訊息
如果曾經有參加過台北的 Ubuntu Hardware Summit,應該都會拿到一本橘色小手冊 Ubuntu Debugging,當中有提到可以設定幾個 Linux kernel 編譯選項中
CONFIG_USB_SERIAL_CONSOLE=y CONFIG_USB_SERIAL=y CONFIG_USB_SERIAL_PL2303=y
然後就可以在 Linux kernel 開機參數加上
console=tty console=ttyUSB0,115200n8
這樣就可以透過 USB to RS-232 傳輸線將 Linux kernel 訊息輸出到另外一台電腦上面,為什麼要這樣做有時候是因為 Linux kernel 開機時是什麼畫面也沒有,也不曉得中間到底發生了什麼事情,又或者是 Linux kernel 訊息出現的太快了,來不及看清楚完整的訊息一下子就過去了,也沒有來得及儲存到檔案系統上面就當機了,有著許許多多不同的情況可能會需要。
但是實際上要怎麼做才能夠編譯出 Ubuntu 上面所使用的 Linux kernel 呢?
首先是將 Ubuntu 所使用的 Linux kernel 的原始碼下載回來。
$ git clone git://kernel.ubuntu.com/ubuntu/ubuntu-xenial.git
然後我自己 commit 了一些修改 (主要是針對 amd64)。
$ git diff HEAD^..HEAD
diff --git a/debian.master/abi/4.4.0-22.39/amd64/generic.modules b/debian.master/abi/4.4.0-22.39/amd64/generic.modules
index e1b9392..53d7914 100644
--- a/debian.master/abi/4.4.0-22.39/amd64/generic.modules
+++ b/debian.master/abi/4.4.0-22.39/amd64/generic.modules
@@ -2873,7 +2873,6 @@ pixcir_i2c_ts
pkcs7_test_key
pktcdvd
pktgen
-pl2303
platform_lcd
plat_nand
plat-ram
@@ -4236,7 +4235,6 @@ usblp
usbmon
usbmouse
usbnet
-usbserial
usb-serial-simple
usbsevseg
usb-storage
diff --git a/debian.master/config/annotations b/debian.master/config/annotations
index 825012f..167ab6e 100644
--- a/debian.master/config/annotations
+++ b/debian.master/config/annotations
@@ -6609,7 +6609,7 @@ CONFIG_USB_STORAGE_ENE_UB6250 policy<{'amd64': 'm', 'arm64': '
CONFIG_USB_UAS policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
# Menu: Device Drivers >> USB support >> Support for Host-side USB >> USB Serial Converter support
-CONFIG_USB_SERIAL policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
CONFIG_USB_SERIAL_GENERIC policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'powerpc': 'y', 'ppc64el': 'y'}>
CONFIG_USB_SERIAL_SIMPLE policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
CONFIG_USB_SERIAL_AIRCABLE policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
@@ -6641,7 +6641,7 @@ CONFIG_USB_SERIAL_MOS7715_PARPORT policy<{'amd64': 'y', 'arm64': '
CONFIG_USB_SERIAL_MOS7840 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
CONFIG_USB_SERIAL_MXUPORT policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
CONFIG_USB_SERIAL_NAVMAN policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
-CONFIG_USB_SERIAL_PL2303 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_PL2303 policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
CONFIG_USB_SERIAL_OTI6858 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
CONFIG_USB_SERIAL_QCAUX policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
CONFIG_USB_SERIAL_QUALCOMM policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'powerpc': 'm', 'ppc64el': 'm'}>
diff --git a/debian.master/config/config.common.ubuntu b/debian.master/config/config.common.ubuntu
index 505a3c7..7cb1284 100644
--- a/debian.master/config/config.common.ubuntu
+++ b/debian.master/config/config.common.ubuntu
@@ -8391,7 +8391,8 @@ CONFIG_USB_RIO500=m
CONFIG_USB_RTL8150=m
CONFIG_USB_RTL8152=m
CONFIG_USB_S2255=m
-CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
CONFIG_USB_SERIAL_AIRCABLE=m
CONFIG_USB_SERIAL_ARK3116=m
CONFIG_USB_SERIAL_BELKIN=m
@@ -8439,7 +8440,7 @@ CONFIG_USB_SERIAL_OMNINET=m
CONFIG_USB_SERIAL_OPTICON=m
CONFIG_USB_SERIAL_OPTION=m
CONFIG_USB_SERIAL_OTI6858=m
-CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_PL2303=y
CONFIG_USB_SERIAL_QCAUX=m
CONFIG_USB_SERIAL_QT2=m
CONFIG_USB_SERIAL_QUALCOMM=m
接著開始編譯 Linux kernel (在有八個 CPU cores 的電腦上)
$ CONCURRENCY_LEVEL=8 fakeroot debian/rules clean binary-generic
最後就會在上層目錄產生 Ubuntu 所使用的 Linux kernel 的 Debian packages 了。
$ ls -1 ../*.deb ../linux-cloud-tools-4.4.0-22-generic_4.4.0-22.40_amd64.deb ../linux-headers-4.4.0-22-generic_4.4.0-22.40_amd64.deb ../linux-image-4.4.0-22-generic_4.4.0-22.40_amd64.deb ../linux-image-extra-4.4.0-22-generic_4.4.0-22.40_amd64.deb ../linux-tools-4.4.0-22-generic_4.4.0-22.40_amd64.deb
這樣就可以將這些 Debian packages 拿去安裝使用了。
最後我放了一份在 http://people.ubuntu.com/~fourdollars/usb2rs232/ 上面,也許有人剛好也需要想要測試一下效果如何。
2015年11月9日 星期一
手動快速編譯 Ubuntu 14.04 當中 Linux kernel 裡面的 i915 module
首先要下載 Linux kernel source tree
$ git clone git://kernel.ubuntu.com/ubuntu/ubuntu-trusty.git
然後進去該目錄,並且切換到 vivid branch (這邊使用的是 Ubuntu 14.04 當中 LTS Enablement Stacks 當中的 vivid)
$ git checkout -b vivid origin/lts-backport-vivid
快速產生目標的 .config
$ cat debian.vivid/config/config.common.ubuntu debian.vivid/config/amd64/config.common.amd64 debian.vivid/config/amd64/config.flavour.generic > .config
執行一些設定腳本
$ make oldconfig && make prepare && make scripts
設定環境變數 (接下來會使用到)
$ export KDIR=$PWD
複製 Module.symvers (如果要編譯的 Linux kernel 跟系統所使用的剛好相同)
$ cp -v /lib/modules/$(uname -r)/build/Module.symvers Module.symvers
不然就需要至少編譯整個 Linux kernel 一遍才行 (-j? 可以參考 /proc/cpuinfo 的數量來決定)
$ make -j8
切換到該 module 的目錄底下,不過 Ubuntu 的 Linux kernel 目前有兩份不同的 i915 module,一份放在 drivers/gpu/drm/i915 底下,另一份放在 ubuntu/i915 底下。
$ cd drivers/gpu/drm/i915
或是
$ cd ubuntu/i915
然後開始編譯 (J=? 可以參考 /proc/cpuinfo 的數量來決定)
$ make -C $KDIR M=$PWD J=8
參考資料:Kernel/BuildYourOwnKernel - Ubuntu Wiki 跟 Documentation/kbuild/modules.txt
2014年7月15日 星期二
在 Ubuntu 上面安裝 mainline kernels
所謂的 mainline kernels 就是在 The Linux Kernel Archives 上面由 Linus Torvalds 本人釋出的版本, 而 Ubuntu 本來有一個 Ubuntu Kernel PPA 專門用來編譯這些 mainline kernels, 只是後來不曉得為何就不再使用 PPA 改用手動編譯的方式,可能是因為 Linux kernel 的釋出方式有了許多變化,除了原本的 stable 跟 mainline 還另加入了 longterm 的支援, 而 Ubuntu 的 Kernel team 本來就有準備一個 http://kernel.ubuntu.com/~kernel-ppa/mainline/ 上面備份了所有的 mainline kernels, 所以就繼續沿用這樣的名稱,但其實這上面還包括了 stable 跟 longterm 後來所有的版本。
總之 http://kernel.ubuntu.com/~kernel-ppa/mainline/ 上面放的是沒有 Ubuntu 額外加料的原始 kernel 版本,只是都編譯成了 Debian package, 所以想要使用的人可以直接下載來安裝就可以使用了,而這些 kernel 如果在安裝使用上會有什麼問題,當然也不會在 Ubuntu 的支援之中,這些 kernel 的存在只是用來測試的,藉由安裝不同的版本來找出問題是在哪兩個版本之間發生的,或是在哪兩個版本之間解決的,進而幫助開發者縮小問題發生的地方,來找出相關合適的修補檔。
但是這樣不斷地手動下載安裝,也是很麻煩的,所以我寫了一個小工具來幫忙,它就叫做 mainline-kernels.sh,下載後像下面這樣執行就可以看到使用說明:
$ ./mainline-kernels.sh --help
Usage ./mainline-kernels.sh:
-h|--help The manual of this script
-f|--from NUM Lower bound of kernel version
-t|--to NUM Upper bound of kernel version
-l|--list List available kernel versions
-r|--remove Remove mainline kernels
可以先使用 ./mainline-kernels.sh --list 來找出現在有哪些 kernel 可以使用。
$ ./mainline-kernels.sh --list 2.6.15 2.6.24.7 2.6.24 2.6.25 2.6.26 2.6.27.47-intrepid 2.6.27.58-intrepid 2.6.27.59-intrepid 2.6.27.60-intrepid 2.6.27.61-intrepid 2.6.27.62-intrepid 2.6.27 2.6.28.10 2.6.28 2.6.29.6 2.6.29 2.6.30.10 2.6.30 ... 3.15~rc3-utopic 3.15~rc4-utopic 3.15~rc5-utopic 3.15~rc6-utopic 3.15~rc7-utopic 3.15~rc8-utopic 3.15-utopic 3.15.1-utopic 3.15.2-utopic 3.15.3-utopic 3.15.4-utopic 3.15.5-utopic 3.16~rc1-utopic 3.16~rc2-utopic 3.16~rc3-utopic 3.16~rc4-utopic 3.16~rc5-utopic
然後直接安裝想要的 Linux kernel
$ ./mainline-kernels.sh 3.16~rc4-utopic 3.16~rc5-utopic
或是指定一個範圍來安裝
./mainline-kernels.sh --from 3.15~ --to 3.16
或是什麼都不指定直接執行,之後再慢慢從選單上面挑選。
./mainline-kernels.sh
最後再將安裝的 Linux kernel 移除掉。
./mainline-kernels.sh --remove
要提醒的一點是,這邊的版本號碼是遵循 Debian version 的規則,所以波浪符號有特別的意義,可以參考我以前的文章。
最後分享一下 Ubuntu to Mainline kernel version mapping,結束這一回合。
2009年6月17日 星期三
FreedomHEC Taipei 2009 - Day 2
背景故事是說老闆要他 porting 一個 WLAN driver 可是沒有 datasheet 可以參考
剛好那個 WLAN driver 少了四個整數值的 header file
問題是他也不熟 ARM 的組合語言 於是他就憑藉著 GCC 的 Cross Compiler 還有中斷向量表的基本觀念
在程式碼裡面填入 asm("nop"); 指令識別透過 arm-linux-gcc -S 的指令轉譯成 ARM 的組合語言
利用這樣的技巧找出無限迴圈跟函式執行進入點 ARM 的組合語言
然後將記憶體整個 dump 出來分析 (通常網通裝置的 Linux 系統所使用的記憶體不會太大, 一般在 64M 以下)
還有透過將無限迴圈放到中斷向量表裡面一步一步抽絲剝繭地將四個重要的整數值找出來
第二個議程由 Peter Stuge 來介紹 CoreBoot (前身為 LinuxBIOS)
CoreBoot 最早叫做 LinuxBIOS 就名稱上看來就是用來啟動 Linux 的 BIOS
後來因為它也可以載入 Linux 以外的 Payload (Payload 不負責任譯為"某種會花費硬體資源的載體")
就連 GRUB 也算是一種 Payload 更多的 Payloads 在 http://www.coreboot.org/Payloads 可以看到
這東西的概念簡單說就是 GPL 授權的 BIOS 讓從事 BIOS 開發不用再從頭寫起
目前已經支援某些特定主機板的清單可以在 http://www.coreboot.org/Supported_Motherboards 上面看到
另外有趣的小東西是 BSD 授權的 Libpayload 讓你寫出自己的載體讓 CoreBoot 來載入
第三個議程由 Jon Corbet 來介紹 Kernel Community
介紹整個 Linux Kernel 開發的合作模式
就是 Linus Torvalds 本人並不會直接收別人給他的 Patch
所以別天真的以為可以把自己的 Patch 直接送給 Linus Torvalds
Linus Torvalds 只會從幾位重要的 Developer 那邊接收 Changesets
Linux Kernel 是個相當活耀開發的計畫有上千個活躍的開發者
Linus Torvalds 不可能一個人去處理所有的程式碼合併跟衝突解決
當然這所有的工作都是靠優秀的 Git 分散式版本控制系統還有優秀的同伴們協力達成的 (他們演講時沒怎麼提到 Git)
簡單說就是 Linus Torvalds 會收一小群人給的 Changesets 然後那一小群人又會從其他人那邊收 Changesets 或是 Patch
最後在 Merge Window 的時候全部再匯集在一起然後釋出 rc1
然後就是 Stabilization 所以不會再接受任何新功能
經過好幾次的 rcN release 覺得差不多了就正式 release 然後再繼續下一個 cycle
一個 cycle 大約 8~12 個星期
一個 stable 的 release 只會維護半年的安全性跟嚴重錯誤修正
另外就是有兩個特別的開發樹
一個是 linux-next 提前為下一個 mainline cycle 的 patches 整合做測試
一個是 -mm 以 linux-next 為基底收集更多雜七雜八的 patches 來做測試
最後子系統的維護者們其實才是把關者也就是所有的 patches 應該要直接送給這些維護者們去做 merge 才對
但是這些子系統的維護者們也並不是擁有絕對的權利
也就是說凡是都還是有商量的餘地
第四個議程 Greg KH 介紹 Linux Driver Project
總之 Greg KH 說把你的 Linux Driver 送交到這個計畫吧
這邊會收任何 Kernel Module 的 patches
也歡迎硬體廠商提供測試機器協助他們測試驅動程式是否正常
就算硬體都還沒有生出來也沒關係
反正早點送 patches 早點 Code Review
不用等到都做完再去送 patches
或者是你的硬體需要有人寫 Linux Driver 嗎
這邊有太多閒著沒事想要寫 Linux Driver 的人
要簽署 NDA 文件也是可以接受的
Linux Driver Project 的網址在 http://www.linuxdriverproject.org/
台灣的硬體廠商們還不快點行動嗎~ :P
第五個議題 Harald Welte 介紹 GPL Compliance
簡單講就是你有用 Linux System 做硬體嗎?
那麼你最好依照相關的規定把該放出來的 Source Code 放出來
人在做 天在看 還有我們一群擅長逆向工程的高手在看 前面 CIH 就介紹過一些方法了
不然我們找到證據就會跑去告你喔~ :O
你看我們有很多合作的模範廠商
咦~ 有些被我們告過囉~ 不過沒關係~ 後來大家都和好了~ :P
另外就是提醒程式開發者們
如果程式碼裡面有一些錯字沒關係就留在那邊
那些錯字可以方便以後我們逆向工程找證據出來
最後就是所有的講者上台接受大家問問題~
照片可以在 http://www.flickr.com/photos/acelan/3617233294/
然後就聽到大長輩田欣先生在用英文一些問題
還有這個活動籌辦人之一的 Scott Tsai 提供即時的中英雙向翻譯
Scott 自己本身也問了一些問題
在聽眾們沒有什麼問題的情況下
講者反問了聽眾們一些問題
然後又聽見田欣先生在用英文回答
還有幾位強者 Matt Hsu, Thinker, ... 也是用英文在問問題回答講者的問題
這兩天的活動於是就圓滿的結束了~
中午提供的便當還蠻好吃的~ :P
第一天中午的便當主菜有雞腿副菜有豬肉
第二天中午的便當主菜有魚副菜也有豬肉
中午吃飯的時候旁邊的窗簾被整個拉開
可以從 14 樓的窗戶看到一排山還有內湖的摩天輪
景色相當好看~ :D
以上是筆者參加過後得心得分享
因為過了一星期才憑回憶攥寫
內容不一定與當天實際情狀相符
FreedomHEC Taipei 2009 - Day 1
中文應該是翻成『自由硬體工程師研討會』
如果沒弄錯今年是第二次舉辦 (因為第一次我沒跟到... >_<)
這次的活動總共兩天的議程
網址 http://freedomhectaipei.pbworks.com/
FreedomHEC Taipei 2009 - Day 1
第一個議程由 Jon Corbet 介紹 2.6.X 每個正式 Release 版本改進了哪些功能
只是單純地介紹歷史帶過... 不過內容好像在跟 Jon Corbet 在 LWN 上面寫的都一樣
也就是說他的投影片就是那些每次 Linux Kernel Release 時都會在 LWN 上面寫的東西是一樣的
第二個議程由 Jim Huang (jserv) & Matt Hsu 講 Qi (气) 這個簡單化的 bootloader
內容主要是在講 Qi 將 bootloader 的功能盡量地簡化把複雜的功能交給一個客製化的 Linux Kernel 來處理
也就是說 Qi 只專注在載入一個客製化的 Linux Kernel 然後再讓客製化的 Linux Kernel 透過 kexec() 來載入另一個 Linux Kernel
好處是那個客製化的 Linux Kernel 可以透過許多原本就已經支援的網路裝置
將另一個放在 TFTP 或是 NFS 上面的 Linux Kernel 載入記憶體中並且執行起來
或是載入執行在 SD / USB 等裝置上面的 Linux Kernel
在一些 Flash 儲存裝置的 Linux Driver 還沒有 Ready 前就可以做先期的開發工作
第三個議程是由 Fred Chien 介紹 Linux 快速開機的方法
像是分析啟動時的開機時間統計然後調整 /etc/init.d 裡面 script 執行的順序
或是利用一些 readahead 之類的工具事先將需要載入系統的函式庫提先載入
還有把不需要的 Linux Kernel Module 拿掉 把需要的 Linux Kernel Module build-in
改 XWindow 的滑鼠驅動程式 ... (這個筆者兩三年前在前公司也弄過, 還有改 VGA Driver)
另外就是利用休眠的功能將記憶體的資料寫到儲存裝置上
下次開機再將那些資料讀回記憶體之中
還有關閉掉一些在 BIOS 裡面不需要啟動的硬體功能減少 BIOS 啟動時間
或是將一些系統服務的啟動放在 XWindow 起來之後再去做
第四個議題是由在 VIA 服務的 Joseph Chan 介紹 VIA 是怎麼將他們公司的硬體驅動程式提交進 Linux Kernel mainline 裡面
有兩點需要注意的
第一點 Coding Style
Linux Kernel 有著慣用的 Coding Style 沒理由 Linux Kernel 的 Source Code 要去 follow 某間公司的 Coding Style
所以想要提交程式碼進去 Linux Kernel 的廠商首先就是要調整 Coding Style 去適應 Linux Kernel
而不是自己關上門來硬幹等到最後提交的時候才發現 Coding Style 要大修改
第二點 Mailing List 上面的 Review Feedback
並不是將程式碼提交出去就算是交差了事了,更重要的是要聆聽開發者的意見還有耐心等待
並不是開發者都閒閒沒事做在那邊等著別人送 Patch 給他 Review,所以要等到開發者有時間才會去看你的程式碼去給 Review Feedback
還有要注意的是收到回應後應該要馬上給對方回應儘快去修改程式碼再去做提交
而 Joseph Chan 正是將 VIA 所遭遇到的慘痛經驗分享給與會者
第五個議題是由 Greg KH 帶著大家一步一步去寫出 Linux Kernel 上面的 USB 溫度計的 Kernel Module
Greg KH 與前面的講者 Jon Corbet 剛好都是 Linux 驅動程式這本書籍的作者
所以其實 Greg KH 介紹的東西在看過這本書之後,其實很快就可以上手了
主要的重點在於 Greg KH 介紹了 USB Subsystem 的基本架構
介紹 Interface/Config 跟 IN/OUT/Endpoint{Interrupt,Bulk,Isolate} 這些觀念
然後就是一個範例一個範例地帶大家一步一步地寫出 USB 溫度計的驅動程式