自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux驅動 | cdev_init、cdev_alloc的區(qū)別

系統(tǒng) Linux
外設有MPU6050、LED兩個設備,他們通過外設電路連接到SOC的對應的引腳上。程序要操作外設,就要通過設置soc中對應的SFR來與外設交互。

[[424054]]

這兩個函數(shù)是字符設備初始化相關的內(nèi)核函數(shù)。

要想了解這兩個函數(shù),必須要知道字符設備的架構,以及字符設備創(chuàng)建的流程。

關于字符設備可以參考下面這篇文章 《手把手教Linux驅動3-之字符設備架構詳解,有這篇就夠了》

一、字符設備架構

下面我們以兩個設備:LED、MPU6050為例來講解字符設備的架構

由上圖所示:

1、硬件

外設有MPU6050、LED兩個設備,他們通過外設電路連接到SOC的對應的引腳上。程序要操作外設,就要通過設置soc中對應的SFR來與外設交互。

2、驅動層

  • 每一個字符設備都必須首先定義一個結構體變量struct cdev,并注冊到內(nèi)核中
  • 所有的該變量在內(nèi)核中會通過鏈表進程管理,其中成員list用于將所有鏈表串接起來
  • 用于操作外設的功能函數(shù)全部被封裝在struct file_operations中,包括read、write等
  • 每一個字符設備都必須要有一個設備號,保存在成員dev中,
  • 主、次設備號只能被分配一次
  • 所有的字符設備號,都由數(shù)組chrdevs統(tǒng)一管理
  • chrdevs是一個指針數(shù)組,成員類型為**struct char_device_struct ***,下標與字符設備號有一定的對應關系,
  • **struct char_device_struct **中有成員:
  1. unsigned int major; 
  2. struct cdev *cdev;  

major : 是主設備號 cdev : 指向該字符設備號對應的cdev結構體

3、應用層、VFS層

  • 用戶如果想操作硬件,必須調(diào)用內(nèi)核中的struct file_operations中的操作函數(shù),
  • 那么如何才能找到該結構體呢?必須要依賴文件節(jié)點來查找,可以通過以下命令來創(chuàng)建
  1. mknod  /dev/led c 250 0 
  2.  mknod 創(chuàng)建設備文件,可以使字符設備,也可以是塊設備 
  3.  /dev/led 設備文件名 
  4.  c  字符設備 
  5.  250  主設備號 
  6.  0    次設備號 

字符設備文件屬性中最重要的屬性就是字符設備號,該設備號和chedevs的下標有一定對應關系

  • 通過mknod創(chuàng)建的文件,VFS層會分配一個結構體變量來維護該文件,類型為struct inode
  • 每新建1個文件內(nèi)核都會創(chuàng)建不同的結構體變量與之對應
  • 應用程序要操作某個字符設備,那么必須先通過系統(tǒng)調(diào)用open()來打開該字符設備
  • 該函數(shù)會返回一個唯一的整型文件描述符,同時內(nèi)核中會分配結構體變量,類型為struct file,并與文件描述符一一對應,該結構體維護在struct task_struct中
  • 每次打開某個文件,都會分配不同的文件描述符,所以需要用不同的變量來保存文件描述符

二、字符設備創(chuàng)建的流程

了解了架構之后,那么我們來看一下內(nèi)核中完整的創(chuàng)建字符設備的流程及對應的函數(shù)調(diào)用關系:

如下圖所示,字符設備的創(chuàng)建主要包括以下三個步驟:

  1. 申請設備號
  2. 初始化cdev
  3. 注冊cdev 調(diào)用的函數(shù)見右側

下面是一個最簡單的額字符設備創(chuàng)建的實例

  1. /*   
  2.  *一口Linux 
  3.  *2021.6.21 
  4.  *version: 1.0.0 
  5. */ 
  6.  
  7. #include <linux/init.h> 
  8. #include <linux/module.h> 
  9. #include <linux/kdev_t.h> 
  10. #include <linux/fs.h> 
  11. #include <linux/cdev.h> 
  12.  
  13. static int major = 237; 
  14. static int minor = 0; 
  15. static dev_t devno; 
  16. static struct cdev cdev; 
  17. static int hello_open (struct inode *inode, struct file *filep) 
  18.  printk("hello_open()\n"); 
  19.  return 0; 
  20. static struct file_operations hello_ops =  
  21.  .open = hello_open, 
  22. }; 
  23. static int hello_init(void) 
  24.  int result; 
  25.  int error;  
  26.  printk("hello_init \n"); 
  27.  devno = MKDEV(major,minor);  
  28.  result = register_chrdev_region(devno, 1, "test"); 
  29.  if(result<0) 
  30.  { 
  31.   printk("register_chrdev_region fail \n"); 
  32.   return result; 
  33.  } 
  34.  cdev_init(&cdev,&hello_ops); 
  35.  error = cdev_add(&cdev,devno,1); 
  36.  if(error < 0) 
  37.  { 
  38.   printk("cdev_add fail \n"); 
  39.   unregister_chrdev_region(devno,1); 
  40.   return error; 
  41.  } 
  42.  return 0; 
  43. static void hello_exit(void) 
  44.  printk("hello_exit \n"); 
  45.  cdev_del(cdev); 
  46.  unregister_chrdev_region(devno,1); 
  47.  return
  48. module_init(hello_init); 
  49. module_exit(hello_exit); 

該實例代碼主要功能:

  1. 申請了字符設備號237
  2. 初始化cdev,并注冊了cdev

應用程序如果要想使用,還必須創(chuàng)建字符設備節(jié)點

  1. mknod /dev/test c 237 0 

這樣應用程序就可以通過設備節(jié)點/dev/test 調(diào)用到對應的內(nèi)核操作函數(shù).open = hello_open,

  1. /*   
  2.  *一口Linux 
  3.  *2021.6.21 
  4.  *version: 1.0.0 
  5. */ 
  6.  
  7. #include <stdio.h> 
  8. #include <sys/types.h> 
  9. #include <sys/stat.h> 
  10. #include <fcntl.h> 
  11. main() 
  12.  int fd; 
  13.  fd = open("/dev/test",O_RDWR); 
  14.  if(fd<0) 
  15.  { 
  16.   perror("open fail \n"); 
  17.   return
  18.  } 
  19.  printf("open ok \n "); 

三、函數(shù)功能和定義

搞懂上面字符設備創(chuàng)建步驟之后,我們就可以來真正分析cdev_init、cdev_alloc這兩個函數(shù)了

1. cdev_init()

  1. 原型 
  2. void cdev_init(struct cdev *cdev, const struct file_operations *fops) 
  3.  
  4. 功能 
  5.  用于初始化cdev結構體,并填充其成員ops 
  6. 參數(shù) 
  7.    cdev:字符設備 
  8.    fops :驅動操作函數(shù)集合 
  9. 返回值 
  10.   無 

該函數(shù)實現(xiàn)如下:

  1. /** 
  2.  * cdev_init() - initialize a cdev structure 
  3.  * @cdev: the structure to initialize 
  4.  * @fops: the file_operations for this device 
  5.  * 
  6.  * Initializes @cdev, remembering @fops, making it ready to add to the 
  7.  * system with cdev_add(). 
  8.  */ 
  9. void cdev_init(struct cdev *cdev, const struct file_operations *fops) 
  10.  memset(cdev, 0, sizeof *cdev); 
  11.  INIT_LIST_HEAD(&cdev->list); 
  12.  kobject_init(&cdev->kobj, &ktype_cdev_default); 
  13.  cdev->ops = fops; 

2. cdev_alloc

  1. 原型 
  2. struct cdev *cdev_alloc(void) 
  3.  
  4. 功能 
  5.  用于分配cdev結構體,并添加到內(nèi)核中 
  6. 參數(shù) 
  7. 返回值 
  8.   成功:返回分配的cdev結構體變量指針 
  9.   失?。?nbsp;返回NULL 

該函數(shù)實現(xiàn)如下:

  1. /** 
  2.  * cdev_alloc() - allocate a cdev structure 
  3.  * 
  4.  * Allocates and returns a cdev structure, or NULL on failure. 
  5.  */ 
  6. struct cdev *cdev_alloc(void) 
  7.  struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL); 
  8.  if (p) { 
  9.   INIT_LIST_HEAD(&p->list); 
  10.   kobject_init(&p->kobj, &ktype_cdev_dynamic); 
  11.  } 
  12.  return p; 

注意,該函數(shù)分配的cdev需要free掉 該函數(shù)沒有初始化cdev->ops成員

四、cdev_alloc()的使用

該函數(shù)主要用于讓用戶省去操作cdev的操作,只需要提供**struct file_operations **變量就可以通過以下函數(shù)注冊字符設備

  1. static inline int register_chrdev(unsigned int major, const char *name
  2.       const struct file_operations *fops) 
  3.  return __register_chrdev(major, 0, 256, name, fops); 

其中函數(shù)__register_chrdev()定義如下:

  1. /** 
  2.  * __register_chrdev() - create and register a cdev occupying a range of minors 
  3.  * @major: major device number or 0 for dynamic allocation 
  4.  * @baseminor: first of the requested range of minor numbers 
  5.  * @count: the number of minor numbers required 
  6.  * @namename of this range of devices 
  7.  * @fops: file operations associated with this devices 
  8.  * 
  9.  * If @major == 0 this functions will dynamically allocate a major and return 
  10.  * its number. 
  11.  * 
  12.  * If @major > 0 this function will attempt to reserve a device with the given 
  13.  * major number and will return zero on success. 
  14.  * 
  15.  * Returns a -ve errno on failure. 
  16.  * 
  17.  * The name of this device has nothing to do with the name of the device in 
  18.  * /dev. It only helps to keep track of the different owners of devices. If 
  19.  * your module name has only one type of devices it's ok to use e.g. the name 
  20.  * of the module here. 
  21.  */ 
  22. int __register_chrdev(unsigned int major, unsigned int baseminor, 
  23.         unsigned int count, const char *name
  24.         const struct file_operations *fops) 
  25.  struct char_device_struct *cd; 
  26.  struct cdev *cdev; 
  27.  int err = -ENOMEM; 
  28.  
  29.  cd = __register_chrdev_region(major, baseminor, countname); 
  30.  if (IS_ERR(cd)) 
  31.   return PTR_ERR(cd); 
  32.  
  33.  cdev = cdev_alloc(); 
  34.  if (!cdev) 
  35.   goto out2; 
  36.  
  37.  cdev->owner = fops->owner; 
  38.  cdev->ops = fops; 
  39.  kobject_set_name(&cdev->kobj, "%s"name); 
  40.  
  41.  err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); 
  42.  if (err) 
  43.   goto out
  44.  
  45.  cd->cdev = cdev; 
  46.  
  47.  return major ? 0 : cd->major; 
  48. out
  49.  kobject_put(&cdev->kobj); 
  50. out2: 
  51.  kfree(__unregister_chrdev_region(cd->major, baseminor, count)); 
  52.  return err; 

可以看到該函數(shù),復用了cdev_alloc()、cdev_add(),我們只需要提供以下3個參數(shù)即可:

  1. unsigned int major  主設備號 
  2. const char *name    設備號名字 
  3. const struct file_operations *fops 驅動操作函數(shù)集合 

五、結論

cdev_alloc()函數(shù)相當于

  1. struct cdev cdev; 
  2. cdev_init($cdev,&hello_ops) 

本文轉載自微信公眾號「一口Linux」

 

責任編輯:姜華 來源: 一口Linux
相關推薦

2013-07-25 13:15:55

iOS開發(fā)學習new與allocinit區(qū)別

2017-02-14 12:34:28

iOSAllocInit

2021-10-11 08:51:05

Linux console Linux 系統(tǒng)

2011-01-14 17:05:52

Linuxinit

2022-07-07 06:27:59

Python__init____new__

2021-03-11 12:23:13

Linux驅動開發(fā)

2010-03-03 09:16:17

2012-05-28 15:49:06

Linux凱迪拉克

2020-12-03 08:59:06

Linux設備驅動

2021-11-29 07:55:45

Linux GPIO Linux 系統(tǒng)

2011-04-11 13:26:25

Linux驅動

2009-12-17 09:56:26

Linux添加驅動模塊

2015-07-20 10:00:28

Linux內(nèi)核編碼風格

2017-03-23 14:30:13

Linux內(nèi)核驅動編碼風格

2009-12-03 10:12:24

LinuxUnix

2017-11-06 17:16:55

Linux設備驅動并發(fā)控制

2023-05-15 08:58:41

塊設備驅動Linux

2021-08-10 11:30:30

Linux代碼中斷控制器

2021-08-03 15:10:26

Linux代碼驅動

2011-09-05 17:44:49

LinuxUnix
點贊
收藏

51CTO技術棧公眾號