简介
设备文件,用户程序和内核程序之间的通讯。并非是正常的文件,只是从程序的角度来看。他们像是文件。所有的设备文件都存放在 /dev目录下面。
创建设备文件有两种途径。
- 手动创建(mknod)
- 自动创建(函数)
手动创建
mknod -m <permissions> <name> <device type> <major> <minor>mknod console c 5 1mknod null c 1 3
代码
```cinclude
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”);
上面是创建一种字符类型 。但是挂载以后查看/dev文件夹。并没有新的设备文件出来。<br />这个时候我们就要手动创建设备文件了。
/dev # cat /proc/devices | grep Embetronicx_Dev 250 Embetronicx_Dev
现在直到对应的主设备号为 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
<a name="EYfGI"></a>## 自动创建可以使用 udev 处理设备文件的自动创建。Udev 是 Linux 内核的设备管理器,该内核动态创建/删除 /dev 目录中的设备节点。只需按照以下步骤操作。1. Include the header file **linux/device.h** and **linux/kdev_t.h**1. Create the struct Class1. Create Device with the class which is created by the above step<a name="NOldi"></a>### Create the class这将为我们的设备驱动程序创建结构类。它将在/sys/类/下创建一个结构。```c# 调用此函数以后。才可以创建设备文件struct class * class_create (struct module *owner, const char *name);void class_destroy (struct class * cls);
Create Device
struct device *device_create (struct *class, struct device *parent, dev_t dev, const char *fmt, ...);void device_destroy (struct class * class, dev_t devt
代码
#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/kdev_t.h>#include <linux/fs.h>#include <linux/device.h>dev_t dev = 0;static struct class *dev_class;static int __init Creatdevicefile_init(void){/*Allocating Major number*/if((alloc_chrdev_region(&dev, 0, 1, "etx_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));/*Creating struct class*/if((dev_class = class_create(THIS_MODULE,"etx_class")) == NULL){printk(KERN_INFO "Cannot create the struct class for device\n");goto r_class;}/*Creating device*/if((device_create(dev_class,NULL,dev,NULL,"etx_device")) == NULL){printk(KERN_INFO "Cannot create the Device\n");goto r_device;}printk(KERN_INFO "Kernel Module Inserted Successfully...\n");return 0;r_device:class_destroy(dev_class);r_class:unregister_chrdev_region(dev,1);return -1;}void __exit Creatdevicefile_exit(void){device_destroy(dev_class,dev);class_destroy(dev_class);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");
插入上面的模块以后,我们可以看到, /dev 文件下面多了一个etx_device 设备文件。
并且/sys/class 下面多出了一个etx_class 文件夹。其下也有一个etx_device 设备文件。
/dev # ls -al | grep etx_devicecrw-rw---- 1 0 0 250, 0 May 31 14:31 etx_device/sys/class/etx_class # lsetx_device
字符设备操作函数
下面我们展示怎么打开这些设备文件,如果我们想要打开,写入,读取和关闭这些设备文件,我们需要像驱动程序注册一些结构。
字符驱动程序的Cdev结构和文件操作
cdev 结构体
struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;} __randomize_layout;
这个结构体我们需要填充两个字段。
file_operations # 文件操作函数owner # THIS_MODULE 宏
我们有两种方法来分配和初始化这个结构体。
- Runtime Allocation
- Own allocation
或者struct cdev *my_cdev = cdev_alloc( );my_cdev->ops = &my_fops;
关于void cdev_init(struct cdev *cdev, struct file_operations *fops);int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
file_operations我们一般只需要只考虑read,open,close几个函数ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);int (*open) (struct inode *, struct file *);
代码
模块
```cinclude
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”);
<a name="juitB"></a>#### APP```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>int8_t write_buf[1024];int8_t read_buf[1024];int main(){int fd;char option;printf("*********************************\n");printf("*******WWW.EmbeTronicX.com*******\n");fd = open("/dev/etx_device", O_RDWR);if (fd < 0){printf("Cannot open device file...\n");return 0;}while (1){printf("****Please Enter the Option******\n");printf(" 1. Write \n");printf(" 2. Read \n");printf(" 3. Exit \n");printf("*********************************\n");scanf(" %c", &option);printf("Your Option = %c\n", option);switch (option){case '1':printf("Enter the string to write into driver :");scanf(" %[^\t\n]s", write_buf);printf("Data Writing ...");write(fd, write_buf, strlen(write_buf) + 1);printf("Done!\n");break;case '2':printf("Data Reading ...");read(fd, read_buf, 1024);printf("Done!\n\n");printf("Data = %s\n\n", read_buf);break;case '3':close(fd);exit(1);break;default:printf("Enter Valid option = %c\n", option);break;}}close(fd);}
