1 Linux字符設備概述
Linux從各異的設備中提取共性,將其劃分成三大類:字符設備、塊設備和網絡設備。
內核針對每一類設備都提供了對應的驅動模型框架,包括內核設施和文件系統接口。
常見的字符設備-鍵盤、鼠標、液晶顯示、打印機等.
常見的塊設備--flash、sd卡、硬盤.
2 常用的數據結構
2.1 file_operations
--struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
--};
//在設備驅動中主要是實現的是file_operations中的方法--open/read/write/mmap等
2.2 字符設備--struct cdev
--struct cdev {
struct kobject kobj; /*字符設備內核對象*/
struct module *owner; /*字符設備驅動程序所在的內核模塊對象指針*/
const struct file_operations *ops; /*訪問字符設備的操作方法*/
struct list_head list; /*字符設備鏈表*/
dev_t dev; /*字符設備號*/
unsigned int count; /*同一個主設備的次設備號的個數-->串口*/
--};
3 常見的操作
3.1 定義字符設備
--定義字符設備通常有兩種方法:靜態定義(struct cdev char_dev)
--動態定義:struct cdev char_dev = cdev_alloc( );-->常用;
3.2 初始化字符設備
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops; /*將fops賦值給cdev->ops, 從文件系統來訪問*/
}
3.3 分配字符設備號
--Linux系統中設備號由主設備號和次設備號構成,主設備號主要來定位對應的設備驅動程序,
--次設備號主要來管理若干同類設備--例如串口;
--linux用dev_t類型變量來標識一個設備號-->32位無符號的整數;
--dev_t由高12位主設備號+低20位次設備號構成。
常用操作:
---1 MAJOR(dev)--取主設備號,MINOR(dev)-取次設備號
----------MKDEV(ma_dev, mi_dev)--將主設備號和次設備號構成設備號
---2 分配設備號
靜態分配:
----/**
* register_chrdev_region() - register a range of device numbers
* @from: the first in the desired range of device numbers; must include
* the major number.
* @count: the number of consecutive device numbers required
* @name: the name of the device or driver.
*
* Return value is zero on success, a negative error code on failure.
*/
int register_chrdev_region(dev_t from, unsigned count, const char *name)
{
struct char_device_struct *cd;
dev_t to = from + count;
dev_t n, next;
for (n = from; n < to; n = next) {
next = MKDEV(MAJOR(n)+1, 0);
if (next > to)
next = to;
cd = __register_chrdev_region(MAJOR(n), MINOR(n),
next - n, name);
if (IS_ERR(cd))
goto fail;
}
return 0;
}
--主要是將當前設備驅動程序所使用的設備號記錄到chrdevs數組中.
動態分配:
/**
* alloc_chrdev_region() - register a range of char device numbers
* @dev: output parameter for first assigned number
* @baseminor: first of the requested range of minor numbers
* @count: the number of minor numbers required
* @name: the name of the associated device or driver
*
* Allocates a range of char device numbers. The major number will be
* chosen dynamically, and returned (along with the first minor number)
* in @dev. Returns zero or a negative error code.
*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name)
{
struct char_device_struct *cd;
/* Register a single major with a specified minor range.
*
* If major == 0 this functions will dynamically allocate a major and return
* its number.
*/
cd = __register_chrdev_region(0, baseminor, count, name);
*dev = MKDEV(cd->major, cd->baseminor);
return 0;
}
3.4 註冊字符設備
/**
* cdev_add() - add a char device to the system
* @p: the cdev structure for the device
* @dev: the first device number for which this device is responsible
* @count: the number of consecutive minor numbers corresponding to this
* device
*
* cdev_add() adds the device represented by @p to the system, making it
* live immediately. A negative error code is returned on failure.
*/
struct kobj_map {
struct probe {
struct probe *next;
dev_t dev;
unsigned long range;
struct module *owner;
kobj_probe_t *get;
int (*lock)(dev_t, void *);
void *data;
} *probes[255];
struct mutex *lock;
};
/*
static struct kobj_map *cdev_map;static struct kobj_map *cdev_map; -->全局變量cdev_map;
在Linux啓動期間由chrdev_init函數負責初始化
*/
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
p->dev = dev;
p->count = count;
/*將設備加入到cdev_map(hash表)中*/
return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}