dev_fifo.c
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#define MAJOR_NUM 250
struct _MycDev {
int len;
char buff[50];
struct cdev cdev;
};
static dev_t g_pDevNum = {0};
struct _MycDev *g_pcDev;
struct class *g_pCla;
//register device num
static int m_Ndevices = 1;
module_param(m_Ndevices, int, 0644);
MODULE_PARM_DESC(m_Ndevices, "The number of devices for register.\n");
static int myDev_fifo_open(struct indoe *inode, struct file *file);
static ssize_t mydev_fifo_read(struct file *file, char __user *ubuf, size_t size, loff_t *ppos);
static ssize_t mydev_fifo_write(struct file *file, const char __user *ubuf, size_t size, loff_t *ppos);
long mydev_fifo_unlocked_ioctl(struct file *file, unsigned int cmd,unsigned long arg);
int __init MyDev_Fifo_Init(void);
void __exit MyDev_Fifo_Exit(void);
static int mydev_fifo_open(struct indoe *inode, struct file *file)
{
return 0;
}
static ssize_t mydev_fifo_read(struct file *file, char __user *ubuf, size_t size, loff_t *ppos)
{
return 0;
}
static ssize_t mydev_fifo_write(struct file *file, const char __user *ubuf, size_t size, loff_t *ppos)
{
return 0;
}
long mydev_fifo_unlocked_ioctl(struct file *file, unsigned int cmd,unsigned long arg)
{
return 0;
}
//设备操作函数接口
static const struct file_operations fifo_operations = {
.owner = THIS_MODULE,
.open = mydev_fifo_open,
.read = mydev_fifo_read,
.write = mydev_fifo_write,
.unlocked_ioctl = mydev_fifo_unlocked_ioctl,
};
int __init MyDev_Fifo_Init(void)
{
int ret;
int i =0;
int j = 0;
struct device *device;
g_pcDev = kzalloc(m_Ndevices * sizeof(struct _MycDev), GFP_KERNEL);
if(!g_pcDev){
return -ENOMEM;
printk(KERN_NOTICE "Error add cdevdemo");
}
//设备号 : 主设备号(12bit) | 次设备号(20bit)
g_pDevNum = MKDEV(MAJOR_NUM, 0);
//静态注册设备号
ret = register_chrdev_region(g_pDevNum, m_Ndevices, "dev_fifo");
if(ret < 0){
//静态注册失败,进行动态注册设备号
ret = alloc_chrdev_region(&g_pDevNum,0,m_Ndevices,"dev_fifo");
if(ret < 0){
printk("Fail to register_chrdev_region\n");
goto err_register_chrdev_region;
}
}
//创建设备类
g_pCla = class_create(THIS_MODULE, "dev_fifo");
if(IS_ERR(g_pCla)){
ret = PTR_ERR(g_pCla);
goto err_class_create;
}
printk("device: %d \n", m_Ndevices);
for(i=0; i < m_Ndevices; i++){
//init 字符设备
cdev_init(&g_pcDev[i].cdev, &fifo_operations);
//添加设备到操作系统
ret = cdev_add(&g_pcDev[i].cdev,g_pDevNum + i,1);
if (ret < 0){
goto err_cdev_add;
}
//导出设备信息到用户空间(/sys/class/类名/设备名)
device = device_create(g_pCla,NULL,g_pDevNum + i,NULL,"dev_fifo%d",i);
if(IS_ERR(device)){
ret = PTR_ERR(device);
printk("Fail to device_create\n");
goto err_device_create;
}
}
printk("Register dev_fito to system,ok!\n");
return 0;
err_register_chrdev_region:
return ret;
err_class_create:
unregister_chrdev_region(g_pDevNum, m_Ndevices);
err_cdev_add:
//将已经添加的全部除去
for(j=0; j < i; j++){
cdev_del(&g_pcDev[j].cdev);
}
err_device_create:
//将已经导出的设备信息除去
for(j = 0;j < i; j++){
device_destroy(g_pCla,g_pDevNum + j);
}
}
void __exit MyDev_Fifo_Exit(void)
{
int i;
//删除sysfs文件系统中的设备
for(i = 0;i < m_Ndevices;i ++){
device_destroy(g_pCla,g_pDevNum + i);
}
//删除系统中的设备类
class_destroy(g_pCla);
//从系统中删除添加的字符设备
for(i = 0;i < m_Ndevices;i ++){
cdev_del(&g_pcDev[i].cdev);
}
//释放申请的设备号
unregister_chrdev_region(g_pDevNum, m_Ndevices);
return;
}
MODULE_LICENSE("GPL");
module_init(MyDev_Fifo_Init);
module_exit(MyDev_Fifo_Exit);
Makefile
ifeq ($(KERNELRELEASE),)
KERNEL_DIR ?=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
modules:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
.PHONY:modules clean
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
else
obj-m := dev_fifo.o
endif