Linux字符設備原理探究--1

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章