Linux字符设备原理探究--1

来源:互联网 发布:如何做好业务员知乎 编辑:程序博客网 时间:2024/05/21 17:30

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);
}

原创粉丝点击