Linux Device Drivers ─
Device Number
裝置的存取,是透過它們在檔案系統裡的名稱;這些名稱可成為特殊檔(special file)、裝置檔(device file)或檔案系統是的節點(node),但不管哪些說法意義都一樣。裝置檔一般來說都集中在/dev/目錄下。字元裝置會出現c字樣而區塊裝置則被標示為b。
在日期欄位之前兩個以逗號隔開的數值,由左而右,依序是裝置檔的(major number)和(minor number)。
[root@localhost ldd3]# ls -l /dev/
?? 0
crw-rw----+ 1 root root 14, 12 2012-01-30 09:17 adsp
crw------- 1 root root 10, 175 2012-01-30 09:17 agpgart
crw-rw----+ 1 root root 14, 4 2012-01-30 09:17 audio
crw------- 1 root root 5, 1 2012-01-30 09:18 console
crw-rw---- 1 root root 10, 63 2012-01-30 09:17 cpu_dma_latency
brw-rw---- 1 root disk 253, 0 2012-01-30 09:17 dm-0
brw-rw---- 1 root disk 253, 1 2012-01-30 09:17 dm-1
裝置編號有以下幾個要點:
- 主編號與次編號兩者合稱「裝置編號」
- 以dev_t型別來表示裝置編號
- dev_t是一個32-bit無號數,其中12bits是主編號,其餘20bits留給次編號
- MAJOR(dev_t dev) 取得主編號
- MINOR(dev_t dev) 取得次編號
- MKDEV(int major, int minor) 將主次編號合併
- 可在【/proc/devices】中看到建立的裝置編號
建立裝置編號的方法主要可以分為兩個,
- 靜態登記法(kernel 2.4的傳統方法, 2.6也有某些驅動程式用之)
- 動態登記法(kernel 2.6開始建議採用)
範例如下:
- 靜態登記法
dev_num_sta.c
#include <linux/init.h> /* modules */
#include <linux/module.h> /* module */
#include <linux/types.h> /* dev_t type */
#include <linux/fs.h> /* chrdev allocation */
#include "dev_num_sta.h"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Emil Chen");
MODULE_DESCRIPTION("Static set MAJOR/MINOR number");
dev_t dev;
int major_num=222, minor_num=1;
static int __init_dev(void)
{
printk(KERN_INFO "Static setting major and minor number...\n");
int alloc_ret = 0;
dev = MKDEV(major_num, minor_num);
// alloc_chrdev_region return 0 on success
alloc_ret = register_chrdev_region(dev, DEVNUM_COUNT, DEVNUM_NAME);
if(alloc_ret){
printk(KERN_WARNING "%s : could not get major %d\n", __func__, major_num);
}
else{
printk(KERN_WARNING "%s : registered with major number:%i, minor number:%i\n",
__func__, MAJOR(dev), MINOR(dev));
}
return alloc_ret;
return 0;
}
static void __exit_dev(void)
{
printk(KERN_INFO "dev_num Module removed.\n");
/* Free the devices */
unregister_chrdev_region(dev,DEVNUM_COUNT);
}
module_init(__init_dev);
module_exit(__exit_dev);
dev_num_sta.h
#ifndef __DEVNUM1_H_
#define __DEVNUM1_H_
// Number of devices
#define DEVNUM_COUNT 4
// Name of the driver
#define DEVNUM_NAME "dev_num_sta"
// First minor number
#define DEVNUM_MINOR_START 0
#endif /* dev_num.h included */
Makefile
APP= dev_num_sta
KERNELDIR ?= $(shell pwd)/../../..
PWD := $(shell pwd)
obj-m := $(APP).o
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
- 動態登記法
dev_num_dyn.c
#include <linux/init.h> /* modules */
#include <linux/module.h> /* module */
#include <linux/types.h> /* dev_t type */
#include <linux/fs.h> /* chrdev allocation */
#include "dev_num_dyn.h"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Emil Chen");
MODULE_DESCRIPTION("20120306");
dev_t dev;
static int __init_dev(void)
{
printk(KERN_INFO "Dynamic allocate major and minor number...\n");
int alloc_ret = 0;
// alloc_chrdev_region return 0 on success
alloc_ret = alloc_chrdev_region(&dev, DEVNUM_MINOR_START, DEVNUM_COUNT, DEVNUM_NAME);
if(alloc_ret){
printk(KERN_WARNING "%s : could not allocate device\n", __func__);
}
else{
printk(KERN_WARNING "%s : registered with major number:%i, minor number:%i\n",
__func__, MAJOR(dev), MINOR(dev));
}
return alloc_ret;
return 0;
}
static void __exit_dev(void)
{
printk(KERN_INFO "dev_num Module removed.\n");
/* Free the devices */
unregister_chrdev_region(dev,DEVNUM_COUNT);
}
module_init(__init_dev);
module_exit(__exit_dev);
dev_num_dyn.h
#ifndef __DEVNUM1_H_
#define __DEVNUM1_H_
// Number of devices
#define DEVNUM_COUNT 4
// Name of the driver
#define DEVNUM_NAME "dev_num_dyn"
// First minor number
#define DEVNUM_MINOR_START 0
#endif /* dev_num.h included */
Makefile
APP= dev_num_dyn
KERNELDIR ?= $(shell pwd)/../../..
PWD := $(shell pwd)
obj-$(CONFIG_EMIL_LDD) := $(APP).o
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean