Linux Driver Book 筆記
Ch 2 Module modprobe
: 只會 search 已安裝於 /lib/modulesSymbol EXPORT_SYMBOL(name)
& EXPORT_SYMBOL_GPL(name)
當時行程 1 2 3 4 5 6 struct task_struct{};struct task_struct *current;current->comm current->pid
module 參數 1 2 3 4 5 static char * whom = "world" ;module_param(whom, charp, S_IRUGO);
Kernel Type
C Type
bool
int
invboll
相反邏輯
charp
cahr *
int
int
long
long
short
short
uint
uint
ulong
ulong
ushort
ushort
User-Space VS Kernel-Space Driver See P38
Module 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <linux/init.h> module_init(init_function); module_exit(cleanup_function); // 初始用,初始化完畢後會被回收(存放在特殊的 ELF section) __init __initdata __exit __exitdata // hotplug,若 kernel 設定為不支援 hotplug 的話,同 __init __devinit __devinitdata
CH 3 Character Device Major & Minor Number 1 2 3 ls -l /dev crw-rw-rw- 1 root wheel 18, 3 6 10 18:44 cu.Yume-WirelessiAP-1 brw-r----- 1 root operator 1, 0 6 10 18:44 disk0
cu.Yume-WirelessiAP-1
Major: 18
Minor: 3
Character device
disk0
Major: 1
Minor: 0
Block device
1 2 3 4 5 6 7 8 9 //<linux/types.h> // 32 bit // 前 12 bit Major // 後 20 bit Minor dev_t int MAJOR(dev_t dev); int MINOR(dev_t dev); dev_t MKDEV(int majotr, int minor);
裝置編號的配置與釋放 1 2 3 //<linux/fs.h> int register_chrdev_region(dev_t first, unsigned int count, char *name); void unregister_chrdev_region(dev_t first, unsigned int count);
可以觀看各個驅動程式的 Major 1 2 3 4 cat /proc/devices Character Devices: 1 mem
rc.local 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #!/bin/sh module="scull" device="scull" mode="644" /sbin/insmod ./$module .ko $* || exit 1 rm -f /dev/${device} [0-3] major=$(awk "\$2 = = \$module\" {print \$1}" /proc/devices) mknod /dev/${device} 0 c $major 0 mknod /dev/${device} 1 c $major 1 mknod /dev/${device} 2 c $major 2 mknod /dev/${device} 3 c $major 3 group="staff" grep -q '^staff:' /etc/group || group="wheel" chgrp $group /dev/${device} [0-3] chmod $mod /dev/${device} [0-3]
重要資料結構 <linux/fs.h>
struct file_operations
Kernel
System Call
When NULL
用途
struct module *owner;
通常是 THIS_MODULE
-
-
-
-
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
read()
-EINVAL
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
write()
-EINVAL
-
-
-
-
int (*open) (struct inode *, struct file *);
open()
可 NULL
kernel 不會發現檔案被打開
int (*release) (struct inode *, struct file *);
可 NULL
kernel 不會發現檔案被 release
-
-
-
-
loff_t (*llseek) (struct file *, loff_t, int);
-
-
-
-
int (*mmap) (struct file *, struct vm_area_struct *);
mmap()
-ENODEV
unsigned int (*poll) (struct file *, struct poll_table_struct *);
poll() epoll() select()
可 NULL
1 2 3 4 5 6 7 8 9 10 11 12 struct file { // 讀寫權限 fmode_t f_mode; // loff_t -> long long 64bit // 目前讀取位置 loff_t f_pos; // 特性: 如 O_NONBLOCK (nonblocking operation) // <linux/fcntl.h> unsigned int f_flags; const struct file_operations *f_op; void *private_data; }
1 2 3 4 5 6 7 8 9 10 11 struct inode { // Major & Minort dev_t i_rdev; union { struct pipe_inode_info *i_pipe; struct block_device *i_bdev; struct cdev *i_cdev; char *i_link; }; }
註冊字元裝置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 //<linux/cdev.h> struct cdev { struct kobject kobj; struct module *owner; const struct file_operations *ops; struct list_head list; dev_t dev; unsigned int count; }; struct cdev *my_cdev = cdev_alloc(); mycdev->ops = &my_fops; // 初始化 cdev struct cdev *cdev_alloc(void); // 將 cdev 嵌入到自訂 struct void cdev_init(struct cdev *, const struct file_operations *); // cdev 加入核心 int cdev_add(struct cdev *, dev_t, unsigned); // 註銷 cdev void cdev_del(struct cdev *);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 struct scull_dev { struct scull_qset *data; int quantum; int qset; unsigned long size; unsigned int access_key; struct semaphore sem; struct cdev cdev; } static void scull_setup_cdev(struct scull_dev *dev, int index) { int err, devno = MKDEV(scull_major, scull_minor + index); cdev_init(&dev->cdev, &scull_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &scull_fops; err = cdev_add(&dev->cdev, devno, 1); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // <linux/kernel.h> container_of(pointer, container_type, container_field); #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) int scull_open(struct inode *inode, struct file *filp) { struct scull_dev *dev; dev = container_of(inode->i_cdev, struct scull_dev, cdev); filp->private_data = dev; // 奇淫技巧:將找到 scull_dev 放到 file 私有資料區 // ... }