简介
设备文件,用户程序和内核程序之间的通讯。并非是正常的文件,只是从程序的角度来看。他们像是文件。所有的设备文件都存放在 /dev目录下面。
创建设备文件有两种途径。
- 手动创建(mknod)
- 自动创建(函数)
手动创建
mknod -m <permissions> <name> <device type> <major> <minor>
mknod console c 5 1
mknod 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 Class
1. 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_device
crw-rw---- 1 0 0 250, 0 May 31 14:31 etx_device
/sys/class/etx_class # ls
etx_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);
}