# Devices and Modules In this chapter, we discuss four kernel components related to device drivers and device management: > * **Device types**—Classifications used in all Unix systems to unify behavior of common devices > * **Modules**—The mechanism by which the Linux kernel can load and unload object code on demand > * **Kernel objects**—Support for adding simple object-oriented behavior and a parent/child relationship to kernel data structures > * **Sysfs**—A filesystem representation of the system’s device tree > # Device Types * **Block devices** (支援seeking) * accessed via ***block device node*** in /dev * example * hard drives * Blu-ray discs * memory devices (flash) * Character devices * accessed via ***character device node*** * not addressable(只能循序的存取資料,cdev看起來就是一塊資料塊而已,你可以前後移動存取他), providing access to data as a stream of bytes(like a file), * 存取方法 * mmap * lseek * example * keyboards * mice * printers * most pseudo-devices * Network devices * provide access to a network via a physical adapter(like 802.11 card) * specific protocol(ex. IP) * 打破unix's everything is a file的設計規則,accessed by ***socket API*** but no file. * miscellaneous devices * 簡寫miscdevs * cdevs的一簡單種 * 讓開發者更好上手??? * pseduo devies.(少數)(多數drivers還是描述硬體居多) * 不是所有的device drivers都描述physical devices.有些drivers是virtual的,提供access to kernel functionality. * kernel random number generator * /dev/random * /dev/urandom * null device * /dev/null * zero device * /dev/zero * full device * /dev/full * memory device * /dev/mem # **Modules** * 儘管kernel只在他自己的address space運行,linux kernel is modular, supporting dynamic insertion and removal of code form itself at runtime. Hello,World! * have entry points * have exit points * live in their own files. ``` /* * hello.c – The Hello, World! Kernel Module */ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> /* * hello_init – the init function, called when the module is loaded. * Returns zero if successfully loaded, nonzero otherwise. */ static int hello_init(void) { printk(KERN_ALERT “I bear a charmed life.\n”); return 0; } /* * hello_exit – the exit function, called when the module is removed. */ static void hello_exit(void) { printk(KERN_ALERT “Out, out, brief candle!\n”); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“Shakespeare”); MODULE_DESCRIPTION(“A Hello, World Module”); ``` Actual modules(init) * register resources * initialize hardware * allocate data structures.. Actual modules(exit) * free resources * shutdown * reset hardware **non-GPL modules cannot invoke GPL-only symbols We cover GPL-only symbols in the section “Exported Symbols”** **drivers liveing in the source tree** * drivers for character devices * /drivers/char * block devices drivers * /drivers/block/ * usb drivers(cdev) * /drivers/usb/ # adding drivers & compile ex. **liveing in the source tree** * create a fishing subdir inside drivers/char/ * add a line to the Makefile in drivers/char/Makefile > * obj-m += fishing/ * This causes the build system to descend into the fishing/ subdirectory whenever it compiles modules > * obj-$(CONFIG_FISHING_POLE) += fishing/ * Finally, inside drivers/char/fishing/, you add a new Makefile with the following line: > obj-m += fishing.o * The build system now descends into fishing/ and builds the module fishing.ko from fishing.c.Yes, confusingly, you write an extension of .o but the module is compiled as .ko.As before, more likely your fishing pole driver’s compilation is conditional on a configuration option. So you probably want to write the following: > * obj-$(CONFIG_FISHING_POLE) += fishing.o * One day, your fishing pole driver might get so complicated—autodetection of fishing line test is just the latest “must have!”—that it grows to occupy more than one source file. No problem, anglers! You simply make your Makefile read the following: > * obj-$(CONFIG_FISHING_POLE) += fishing.o fishing-objs := fishing-main.o fishing-line.o * Now, fishing-main.c and fishing-line.c will be compiled and linked into fishing.ko whenever CONFIG_FISHING_POLE is set. Finally, you might need to pass to the C compiler additional compile flags during the build process solely for your file.To do so, simply add a line such as the following to your Makefile: > EXTRA_CFLAGS += -DTITANIUM_POLE * To compile, run the kernel build process as usual. If your module’s build was conditioned on a configuration option, as it was with CONFIG_FISHING_POLE, make sure that the option is enabled before beginning # Living Externally * create a Makefile in your own source directory with this single line: > * obj-m := fishing.o * This compiles fishing.c into fishing.ko. If your source spans multiple files, two lines will suffice: > * obj-m := fishing.o fishing-objs := fishing-main.o fishing-line.o * This example compiles fishing-main.c and fishing-line.c into fishing.ko. The main difference in living externally is the build process. Because your module lives outside the kernel tree, you need to instruct make on how to find the kernel source files and base Makefile.This is also easy: > make -C /kernel/source/location SUBDIRS=$PWD modules * In this example, /kernel/source/location is the location of your configured kernel source tree. Recall that you should not store your working copy of the kernel source tree in /usr/src/linux but somewhere else, easily accessible, in your home directory # Installing Modules Compiled modules are installed into **/lib/modules/version/kernel/**, where each directory under kernel/ corresponds to the module’s location in the kernel source tree. For example, with a kernel version of 2.6.34, the compiled fishing pole module would live at **/lib/modules/2.6.34/kernel/drivers/char/fishing.ko** if you stuck it directly in drivers/char/. The following build command is used to install compiled modules into the correct location: > make modules_install > This needs to be run as root. ![](https://i.imgur.com/CLR6eoA.png) # Generating Module Dependencies module dependency information > /lib/modules/version/modules.dep > * To build the module dependency information > * depmod > * To perform a quick update, rebuilding only the information for modules newer than the dependency information, run as root > * depmod -A > # Managing Configuration Options * 就是用Kconfig(kernel2.6之後的Kbuild sytem) * add an entry to the **Kconfig** file responsible for the applicable branch of the kernel source tree * If the fishing pole driver lives in **drivers/char/**, you use **drivers/char/Kconfig.** * 如果想放在新的dir下,你要create新的Kconfig,並且用已經存在的上層目錄Kconfig把你source進來 > * source “drivers/char/fishing/Kconfig” > ex. ![](https://i.imgur.com/x6mksBn.png) * config FISHING_POLE: 你設的CONFIG_XXX * tristate: Y or M or N * if this option represented a feature and not a device driver—use the directive **bool** instead of **tristate** * default: default Y N or M * depend: 相依性設定 > * depends on FISH_TANK(代表CONFIG_FISH_TANK沒有被enable的話你這個CONFIG就會被預設成N) > * select: 不管相依性直接預設打開 * &&: depends and selects可設成多個 > depends on EXAMPLE_DRIVERS && !NO_FISHING_ALLOWED > (前面設 後面不設才成立 * if: trisate and bool可以用if來決定 > * bool “Deep Sea Mode” if OCEAN > # Module Parameters > module_param(name, type, perm); > # kernel全局符號表 當module被成功insert進kernel,你export的symbols就會被加入kernel的全局symbol表內,各module之間可能會有符號相依性 * moduleA可能會用moduleB提供的symbol * 所以在一系列的insert module中順序是很重要的 * example * mosdos仰賴fat module * USB module仰賴usbcore, input module 模組之間的符號堆疊關係如下圖 ![](https://i.imgur.com/OBo3x5q.png) Loading Modules * 不建議的做法(沒有dependency, error checking and reporting) > * insmod module.ko > * 建議的做法(可把有dependency的module都load進來,有防呆) > * modprobe xxx.ko [ module parameters ] > * The modprobe command can also be used to remove modules from the kernel. To remove a module, as root, run(這個做法也會把相依的module都移除掉,比rmmod好) > * modprobe –r modules > # Exported Symbols * When modules are loaded, they are dynamically linked into the kernel * 像userspace一樣,dynamically linked binaries可以用export來使用external functions * in kernel,我們用 * EXPORT_SYMBOL() * EXPORT_SYMBOL_GPL(). * 只有被EXPORT_SYMBOL後的function才會被其他module看到 * Core code can call any nonstatic interface in the kernel because all core source files are linked into a single base image(module的rule比較嚴格 * The set of exported kernel symbols are known as the exported kernel interfaces. ![](https://i.imgur.com/ZMw2riG.png) * **If your code is configurable as a module, you must ensure that when compiled as a module all interfaces that it uses are exported. Otherwise linking errors (and a broken module) result.** # The Device Model The device model provides a single mechanism for representing devices and describing their topology in the system. Such a system provides several benefits: * Minimization of code duplication * A mechanism for providing common facilities, such as reference counting * The capability to enumerate all the devices in the system, view their status, and see to what bus they attach * The capability to generate a complete and valid tree of the entire device structure of the system, including all buses and interconnections * The capability to link devices to their drivers and vice versa * The capability to categorize devices by their class, such as input device, without the need to understand the physical device topology * The capability to walk the tree of devices from the leaves up to the root, powering down devices in the correct order 核心概念: 用tree來記錄device的拓樸結構(順序有重要性) ex. * what drive connects to what controller * what device connects to what bus * When powering down, the kernel must power down the lower (leaf) nodes of the tree before the higher nodes * for example: * 關usb controller之前要關usb mouse * 關PCI bus之前要關 usb controller * like usbmouse-->usbcontroller-->PIC bus(Tree結構) # Kobjects device model的核心就是Kobjects, Kernel object的簡寫 which is represented by struct kobject and defined in <linux/kobject.h> The kobject is similar to the Object class in object-oriented languages such as C# or Java. It provides basic facilities, such as reference counting, a name, and a parent pointer, enabling the creation of a hierarchy of objects. ![](https://i.imgur.com/3fmWmbq.png) * The parent pointer points to this kobject’s parent * The name pointer points to the name of this kobject. * 就創造了一個object的階層結構跟關係 * sysfs: a user-space filesystem representation of the kobject object hierarchy inside the kernel. * *sd: points to a sysfs_dirent structure that represents this kobject in sysfs. Inside this structure is an inode structure representing the kobject in the sysfs filesystem. * kref: reference counting * *ktype & *kset: describe and group kobjects cdev結構就有包kobject ![](https://i.imgur.com/wr7m3FE.png) # Ktypes 想成是哪種工作,伐木工 建築工... Kobjects are associated with a specific type, called a ktype, short for kernel object type ![](https://i.imgur.com/05Ughsq.png) * describing default behavior for a family of kobjects * *release * pointer points to the deconstructor called when a kobject’s reference count reaches zero.This function is responsible for freeing any memory associated with this kobject and otherwise cleaning up. * sysfs_ops * variable points to a sysfs_ops structure.This structure describes the behavior of sysfs files on read and write. It’s covered in more detail in the section “Adding Files to sysfs # Ksets ![](https://i.imgur.com/VWw3AYn.png) # Managing and Manipulating Kobjects The first step in using a kobject is declaring and initializing it. > void kobject_init(struct kobject *kobj, struct kobj_type *ktype); > The function’s first parameter is the kobject to initialize. Before calling this function,the kobject must be zeroed.This might normally happen during the initialization of the larger function in which the kobject is embedded. If not, a simple call to memset()does the trick > memset(kobj, 0, sizeof (*kobj)); > ![](https://i.imgur.com/lBCnLUd.png) ![](https://i.imgur.com/z0hDE1G.png) ![](https://i.imgur.com/wPaq7Pc.png) ![](https://i.imgur.com/s41vHpU.png) ![](https://i.imgur.com/kHm8a3Z.png) # sysfs 一開始提出這個架構是為了解決Power mangement的問題,為了好debug,開發者把這個tree架構export成一個filesystem. Most systems mount it at /sys. * 讓user可以看到device的拓樸結構 * /proc * sysfs原本叫 driverfs = Kobjects * 大多數系統把他mount在/sys * sysfs背後的魔術是把kobjects的目錄結構用dentry連起來,就export成filesystem ![](https://i.imgur.com/6FSROBH.png) ![](https://i.imgur.com/UtBB6QF.png) * class: devices on the system organized by high-level function * dev: registered device nodes * bus: system buses * block: one directory for each of the registered block devices * firmware: low-level subsystems such as ACPI, EDD, EFI * kernel: kernel configuration options and status information * module: system loaded modules * devices: device topology of the system ![](https://i.imgur.com/oIucXO9.png) # sysfs的規定 sysfs filesystem是代替ioctl() on device nodes 或 procfs filsystem的好方案,現今的kernel開發者用sysfs attributes實作許多的kernel functionality在適當的directory上。 ex: * 不要再去用ioctl()寫device node。 * 因為ioctl()使用不定引數,參數是否合乎規定完全要自己去判斷,很容易出錯。 * 簡單的加上一個sysfs attribute在driver's sysfs directory就好了 為了保持sysfs的乾淨跟直覺,有些規定須要遵守 * First, sysfs attributes should export one value per file.Values should be text-based and map to simple C types * makes reading and writing trivial from the command line * enables C programs to easily slurp the kernel’s data from sysfs into their own variables * The goal is to avoid the highly structured or highly messy representation of data we have today in /proc * Ultimately, think of sysfs attributes as mapping to individual kernel variables (as they usually do) * and keep in mind ease of manipulation from user-space, particularly from the shell * Second, organize data in sysfs in a clean hierarchy * Finally, remember that sysfs provides a kernel-to-user service and is thus a sort of user-space ABI # The Kernel Events Layer 用Kobjects實作出一個kernel-to-user的通知機制 The Kernel Event Layer models events as signals emitting from objects—specifically, kobjects, * 因為Kobjects map to sysfs paths. * the source of each event is a sysfs path. If the event in question has to do with your first hard drive, /sys/block/hda is the source address