简介

设备文件,用户程序和内核程序之间的通讯。并非是正常的文件,只是从程序的角度来看。他们像是文件。所有的设备文件都存放在 /dev目录下面。
创建设备文件有两种途径。

  1. 手动创建(mknod)
  2. 自动创建(函数)

    手动创建

    1. mknod -m <permissions> <name> <device type> <major> <minor>
    2. mknod console c 5 1
    3. mknod null c 1 3

    代码

    ```c

    include

    include

    include

    include

    include

dev_t dev = 0;

static int __init Creatdevicefile_init(void) { /Allocating Major number/ if ((alloc_chrdev_region(&dev, 0, 1, “Embetronicx_Dev”)) < 0) { printk(KERN_INFO “Cannot allocate major number for device\n”); return -1; } printk(KERN_INFO “Major = %d Minor = %d \n”, MAJOR(dev), MINOR(dev)); printk(KERN_INFO “Kernel Module Inserted Successfully…\n”); return 0; }

void __exit Creatdevicefile_exit(void) { unregister_chrdev_region(dev, 1); printk(KERN_INFO “Kernel Module Removed Successfully…\n”); }

module_init(Creatdevicefile_init); module_exit(Creatdevicefile_exit);

MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“zhouchengzhu 1073355312@qq.com“); MODULE_DESCRIPTION(“A simple hello world driver”); MODULE_VERSION(“2:1.0”);

  1. 上面是创建一种字符类型 。但是挂载以后查看/dev文件夹。并没有新的设备文件出来。<br />这个时候我们就要手动创建设备文件了。

/dev # cat /proc/devices | grep Embetronicx_Dev 250 Embetronicx_Dev

  1. 现在直到对应的主设备号为 250了。现在创建对应的设备文件

/dev # mknod /dev/testdev c 250 1

现在我们就可以看到设备文件了

/dev # ls -al | grep testdev crw-r—r— 1 0 0 250, 1 May 31 05:32 testdev

  1. <a name="EYfGI"></a>
  2. ## 自动创建
  3. 可以使用 udev 处理设备文件的自动创建。Udev 是 Linux 内核的设备管理器,该内核动态创建/删除 /dev 目录中的设备节点。只需按照以下步骤操作。
  4. 1. Include the header file **linux/device.h** and **linux/kdev_t.h**
  5. 1. Create the struct Class
  6. 1. Create Device with the class which is created by the above step
  7. <a name="NOldi"></a>
  8. ### Create the class
  9. 这将为我们的设备驱动程序创建结构类。它将在/sys/类/下创建一个结构。
  10. ```c
  11. # 调用此函数以后。才可以创建设备文件
  12. struct class * class_create (struct module *owner, const char *name);
  13. void class_destroy (struct class * cls);

Create Device

  1. struct device *device_create (struct *class, struct device *parent, dev_t dev, const char *fmt, ...);
  2. void device_destroy (struct class * class, dev_t devt

代码

  1. #include <linux/kernel.h>
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/kdev_t.h>
  5. #include <linux/fs.h>
  6. #include <linux/device.h>
  7. dev_t dev = 0;
  8. static struct class *dev_class;
  9. static int __init Creatdevicefile_init(void)
  10. {
  11. /*Allocating Major number*/
  12. if((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) <0){
  13. printk(KERN_INFO "Cannot allocate major number for device\n");
  14. return -1;
  15. }
  16. printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
  17. /*Creating struct class*/
  18. if((dev_class = class_create(THIS_MODULE,"etx_class")) == NULL){
  19. printk(KERN_INFO "Cannot create the struct class for device\n");
  20. goto r_class;
  21. }
  22. /*Creating device*/
  23. if((device_create(dev_class,NULL,dev,NULL,"etx_device")) == NULL){
  24. printk(KERN_INFO "Cannot create the Device\n");
  25. goto r_device;
  26. }
  27. printk(KERN_INFO "Kernel Module Inserted Successfully...\n");
  28. return 0;
  29. r_device:
  30. class_destroy(dev_class);
  31. r_class:
  32. unregister_chrdev_region(dev,1);
  33. return -1;
  34. }
  35. void __exit Creatdevicefile_exit(void)
  36. {
  37. device_destroy(dev_class,dev);
  38. class_destroy(dev_class);
  39. unregister_chrdev_region(dev, 1);
  40. printk(KERN_INFO "Kernel Module Removed Successfully...\n");
  41. }
  42. module_init(Creatdevicefile_init);
  43. module_exit(Creatdevicefile_exit);
  44. MODULE_LICENSE("GPL");
  45. MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");
  46. MODULE_DESCRIPTION("A simple hello world driver");
  47. MODULE_VERSION("2:1.0");

插入上面的模块以后,我们可以看到, /dev 文件下面多了一个etx_device 设备文件。
并且/sys/class 下面多出了一个etx_class 文件夹。其下也有一个etx_device 设备文件。

  1. /dev # ls -al | grep etx_device
  2. crw-rw---- 1 0 0 250, 0 May 31 14:31 etx_device
  3. /sys/class/etx_class # ls
  4. etx_device

字符设备操作函数

下面我们展示怎么打开这些设备文件,如果我们想要打开,写入,读取和关闭这些设备文件,我们需要像驱动程序注册一些结构。

字符驱动程序的Cdev结构和文件操作

cdev 结构体

  1. struct cdev {
  2. struct kobject kobj;
  3. struct module *owner;
  4. const struct file_operations *ops;
  5. struct list_head list;
  6. dev_t dev;
  7. unsigned int count;
  8. } __randomize_layout;

这个结构体我们需要填充两个字段。

  1. file_operations # 文件操作函数
  2. owner # THIS_MODULE 宏

我们有两种方法来分配和初始化这个结构体。

  1. Runtime Allocation
  2. Own allocation
    1. struct cdev *my_cdev = cdev_alloc( );
    2. my_cdev->ops = &my_fops;
    或者
    1. void cdev_init(struct cdev *cdev, struct file_operations *fops);
    2. int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
    关于file_operations 我们一般只需要只考虑read,open,close几个函数
    1. ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    2. ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    3. int (*open) (struct inode *, struct file *);

    代码

    模块

    ```c

    include

    include

    include

    include

    include

    include

    include

    include //kmalloc()

    include //copy_to/from_user()

define mem_size 1024

dev_t dev = 0; static struct class dev_class; static struct cdev etx_cdev; uint8_t kernel_buffer;

static int init etx_driver_init(void); static void exit etx_driver_exit(void); static int etx_open(struct inode inode, struct file file); static int etx_release(struct inode inode, struct file file); static ssize_t etx_read(struct file filp, char __user buf, size_t len, loff_t off); static ssize_t etx_write(struct file filp, const char buf, size_t len, loff_t off);

static struct file_operations fops = { .owner = THIS_MODULE, .read = etx_read, .write = etx_write, .open = etx_open, .release = etx_release, };

static int etx_open(struct inode inode, struct file file) { /Creating Physical memory/ if ((kernel_buffer = kmalloc(mem_size, GFP_KERNEL)) == 0) { printk(KERN_INFO “Cannot allocate memory in kernel\n”); return -1; } printk(KERN_INFO “Device File Opened…!!!\n”); return 0; }

static int etx_release(struct inode inode, struct file file) { kfree(kernel_buffer); printk(KERN_INFO “Device File Closed…!!!\n”); return 0; }

static ssize_t etx_read(struct file filp, char __user buf, size_t len, loff_t off) { int ret = copy_to_user(buf, kernel_buffer, mem_size); (void)ret; printk(KERN_INFO “Data Read : Done!\n”); return mem_size; } static ssize_t etx_write(struct file filp, const char __user buf, size_t len, loff_t off) { int ret = copy_from_user(kernel_buffer, buf, len); (void)ret; printk(KERN_INFO “Data Write : Done!\n”); return len; }

static int __init etx_driver_init(void) { /Allocating Major number/ if ((alloc_chrdev_region(&dev, 0, 1, “etx_Dev”)) < 0) { printk(KERN_INFO “Cannot allocate major number\n”); return -1; } printk(KERN_INFO “Major = %d Minor = %d \n”, MAJOR(dev), MINOR(dev));

/Creating cdev structure/ cdev_init(&etx_cdev, &fops);

/Adding character device to the system/ if ((cdev_add(&etx_cdev, dev, 1)) < 0) { printk(KERN_INFO “Cannot add the device to the system\n”); goto r_class; }

/Creating struct class/ if ((dev_class = class_create(THIS_MODULE, “etx_class”)) == NULL) { printk(KERN_INFO “Cannot create the struct class\n”); goto r_class; }

/Creating device/ if ((device_create(dev_class, NULL, dev, NULL, “etx_device”)) == NULL) { printk(KERN_INFO “Cannot create the Device 1\n”); goto r_device; } printk(KERN_INFO “Device Driver Insert…Done!!!\n”); return 0;

r_device: class_destroy(dev_class); r_class: unregister_chrdev_region(dev, 1); return -1; }

void __exit etx_driver_exit(void) { device_destroy(dev_class, dev); class_destroy(dev_class); cdev_del(&etx_cdev); unregister_chrdev_region(dev, 1); printk(KERN_INFO “Device Driver Remove…Done!!!\n”); }

module_init(etx_driver_init); module_exit(etx_driver_exit);

MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“zhouchengzhu 1073355312@qq.com“); MODULE_DESCRIPTION(“A real module demo”); MODULE_VERSION(“2:1.0”);

  1. <a name="juitB"></a>
  2. #### APP
  3. ```c
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. int8_t write_buf[1024];
  12. int8_t read_buf[1024];
  13. int main()
  14. {
  15. int fd;
  16. char option;
  17. printf("*********************************\n");
  18. printf("*******WWW.EmbeTronicX.com*******\n");
  19. fd = open("/dev/etx_device", O_RDWR);
  20. if (fd < 0)
  21. {
  22. printf("Cannot open device file...\n");
  23. return 0;
  24. }
  25. while (1)
  26. {
  27. printf("****Please Enter the Option******\n");
  28. printf(" 1. Write \n");
  29. printf(" 2. Read \n");
  30. printf(" 3. Exit \n");
  31. printf("*********************************\n");
  32. scanf(" %c", &option);
  33. printf("Your Option = %c\n", option);
  34. switch (option)
  35. {
  36. case '1':
  37. printf("Enter the string to write into driver :");
  38. scanf(" %[^\t\n]s", write_buf);
  39. printf("Data Writing ...");
  40. write(fd, write_buf, strlen(write_buf) + 1);
  41. printf("Done!\n");
  42. break;
  43. case '2':
  44. printf("Data Reading ...");
  45. read(fd, read_buf, 1024);
  46. printf("Done!\n\n");
  47. printf("Data = %s\n\n", read_buf);
  48. break;
  49. case '3':
  50. close(fd);
  51. exit(1);
  52. break;
  53. default:
  54. printf("Enter Valid option = %c\n", option);
  55. break;
  56. }
  57. }
  58. close(fd);
  59. }

参考资料