Linux kernel 即使在类_create和设备_create之后,/dev下也没有设备条目

Linux kernel 即使在类_create和设备_create之后,/dev下也没有设备条目,linux-kernel,linux-device-driver,Linux Kernel,Linux Device Driver,我正在制作一个简单的char驱动程序,我了解到有两种方法可以让我的驱动程序与-alloc_chrdev_region(和register_chrdev_region)和register_chrdev配对。我最初是从register_chrdev开始的,它给了我我的专业号,还在/dev中创建了条目(使用类和设备创建) 但是,当我将register_chrdev更改为alloc_chrdev_region以获取主编号(使用chrdev_init和chrdev_add)时,其余的条目函数保持不变,我在

我正在制作一个简单的char驱动程序,我了解到有两种方法可以让我的驱动程序与-alloc_chrdev_region(和register_chrdev_region)和register_chrdev配对。我最初是从register_chrdev开始的,它给了我我的专业号,还在/dev中创建了条目(使用类和设备创建)

但是,当我将register_chrdev更改为alloc_chrdev_region以获取主编号(使用chrdev_init和chrdev_add)时,其余的条目函数保持不变,我在/dev中看不到条目,尽管当我使用mknode手动创建条目并运行测试应用程序以使用驱动程序时,它工作得很好

下面是不生成/dev条目的入口点代码

#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/device.h>
#include<linux/kernel.h>
#include<linux/slab.h>
#include<linux/uaccess.h>
#include<linux/stat.h>
#include<linux/cdev.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/kdev_t.h>


#define DEVICE_NAME "myCharDevice"
#define MODULE_NAME "myCharDriver"
#define CLASS_NAME "myCharClass"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("YASH BHATT");
MODULE_VERSION(".01");

static char *bufferMemory;
static int bufferPointer;
static int bufferSize = 15;
static dev_t myChrDevid;
static struct cdev *myChrDevCdev;
static struct class *pmyCharClass;
static struct device *pmyCharDevice;
int majorNumber = 0;

static int charDriverOpen(struct inode *inodep, struct file *filep);
static int charDriverClose(struct inode *inodep, struct file *filep);
static ssize_t charDriverWrite(struct file *filep, const char *buffer, size_t len, loff_t *offset);
static ssize_t charDriverRead(struct file *filep, char *buffer, size_t len, loff_t *offset);
static int charDriverEntry(void);
static void charDriverExit(void);
static ssize_t attrShowData(struct device*, struct device_attribute*, char*);
static ssize_t attrStoreData(struct device*, struct device_attribute*, const char*, size_t);
static ssize_t attrShowBuffer(struct device*, struct device_attribute*, char*);
static ssize_t attrStoreBuffer(struct device*, struct device_attribute*, const char*, size_t);

/* The following function is called when the file placed on the sysfs is accessed for read*/
static ssize_t attrShowData(struct device* pDev, struct device_attribute* attr, char* buffer)
{
    printk(KERN_INFO "MESG: The data has been accessed through the entry in sysfs\n");
    if (bufferPointer == 0)
    {
        printk(KERN_WARNING "Thre is no data to read from  buffer!\n");
        return -1;
    }
    strncpy(buffer, bufferMemory, bufferPointer);
    /* Note : Here we can directly use strncpy because we are already in kernel space and do not need to translate address*/
    return bufferPointer;
}

static ssize_t attrStoreData(struct device* pDev, struct device_attribute* attr, const char* buffer, size_t length)
{
    printk(KERN_INFO "Writing to attribute\n");
    bufferPointer = length;
    strncpy(bufferMemory, buffer, length);
    return length;
}

static ssize_t attrShowBuffer(struct device* pDev, struct device_attribute* attr, char* buffer)
{
    int counter;
    int temp = bufferSize;
    char bufferSizeArray[4] = {0};
    counter = 3;
    //printk(KERN_INFO "Buffer = %d\n",bufferSize % 10);
    do
    {
        bufferSizeArray[counter] = '0' + (bufferSize % 10);
        //printk(KERN_INFO "Character at %d is : %c\n",counter,bufferSizeArray[counter]);
        bufferSize /= 10;
        counter--;
    }
    while(counter != -1);
    strncpy(buffer, bufferSizeArray, 4);
    bufferSize = temp;
    /* Note : Here we can directly use strncpy because we are already in kernel space and do not need to translate address*/
    return 4;
}

static ssize_t attrStoreBuffer(struct device* pDev, struct device_attribute* attr, const char* buffer, size_t length)
{
    int counter;
    bufferPointer = length;
    //printk(KERN_INFO "Length : %d With first char %c\n",length,buffer[0]);
    bufferSize = 0;
    for (counter = 0; counter < length-1 ; counter++)
    {
        bufferSize = (bufferSize * 10) + (buffer[counter] - '0') ;
    }
    //printk(KERN_INFO "Buffer size new : %d\n",bufferSize);
    return length;
}
/* These macros converts the function in to instances dev_attr_<_name>*/
/* Defination of the macro is as follows : DEVICE_ATTR(_name, _mode, _show, _store) */
/* Note the actual implementation of the macro makes an entry in the struct device_attribute. This macro does that for us */
static DEVICE_ATTR(ShowData, S_IRWXU, attrShowData, attrStoreData); // S_IRUSR gives read access to the user 
static DEVICE_ATTR(Buffer, S_IRWXU, attrShowBuffer, attrStoreBuffer);   // S_IRUSR gives read access to the user 

static struct file_operations fops = 
{
    .open = charDriverOpen,
    .release = charDriverClose,
    .read = charDriverRead,
    .write = charDriverWrite,
};


static int __init charDriverEntry()
{
    int returnValue;
    //majorNumber = register_chrdev(0, DEVICE_NAME, &fops);

    returnValue = alloc_chrdev_region(&myChrDevid, 0, 1, DEVICE_NAME); 
    /* This function takes 4 arguments - dev_t address, start of minor number, range/count of minor number, Name; Note - unlike register_chrdev fops have not
        yet been tied to the major number */

    if (returnValue < 0)
    {
        printk(KERN_ALERT "ERROR : can not aquire major number! error %d",returnValue);
        return -1;
    }
    printk(KERN_INFO "Aquired Major Number! : %d\n", MAJOR(myChrDevid));

    //cdev_init(&myChrDevCdev,&fops);
    myChrDevCdev = cdev_alloc();
    if (IS_ERR(myChrDevCdev))
    {
        printk(KERN_ALERT "Failed to allocate space for CharDev struct\n");
        unregister_chrdev_region(myChrDevid, 1);
        return -1;
    }
        cdev_init(myChrDevCdev,&fops);
        myChrDevCdev->owner = THIS_MODULE;
        //myChrDevCdev->ops = &fops;/* this function inits the c_dev structure with memset 0 and then does basic konject setup and then adds fops to cdev struct*/


    /* this function adds the cdev to the kernel structure so that it becomes available for the users to use it */


    // Now we will create class for this device
    pmyCharClass = class_create(THIS_MODULE,CLASS_NAME);
    if (IS_ERR(pmyCharClass))
    {
        printk(KERN_ALERT "Failed to Register Class\n");
        cdev_del(myChrDevCdev);
        kfree(myChrDevCdev);
        unregister_chrdev_region(myChrDevid, 1);
        return -1;
    }
    printk(KERN_INFO "Class created!\n");

    pmyCharDevice = device_create(pmyCharClass, NULL, MKDEV(majorNumber,0),NULL,DEVICE_NAME);
    if (IS_ERR(pmyCharDevice))
    {
        printk(KERN_ALERT "Failed to Register Class\n");
        class_unregister(pmyCharClass);
        class_destroy(pmyCharClass);
        cdev_del(myChrDevCdev);
        kfree(myChrDevCdev);
        unregister_chrdev_region(myChrDevid, 1);
        return -1;
    }
    printk(KERN_INFO "Device created!\n");

    returnValue = cdev_add(myChrDevCdev, myChrDevid, 1);
    if (returnValue < 0)
    {
        printk(KERN_ALERT "Failed to add chdev \n");
        return -1;
    }
    /* We now have created the class and we have aquired major numer. But we have not yet tied out created fileops with anything. 
        We will do that now */
    //returnValue = cdev_init(cdev)     
    printk(KERN_INFO "Now We will create the attribute entry in sysfs\n");
    /* the function used is device_create_file(struct device *, struct device_attribute*) */
    device_create_file(pmyCharDevice, &dev_attr_ShowData);      // The second argumnet is the structure created by the DEVICE_ATTR macro
    device_create_file(pmyCharDevice, &dev_attr_Buffer);
    return 0;
}

static void __exit charDriverExit()
{
    device_remove_file(pmyCharDevice, &dev_attr_Buffer);
    device_remove_file(pmyCharDevice, &dev_attr_ShowData);
    device_destroy(pmyCharClass, MKDEV(majorNumber,0));
    class_unregister(pmyCharClass);
    class_destroy(pmyCharClass);
    //unregister_chrdev(majorNumber,DEVICE_NAME);
    cdev_del(myChrDevCdev);
    unregister_chrdev_region(myChrDevid, 1);
    kfree(myChrDevCdev);
    printk(KERN_INFO "Unmounting module done !\n");
}

static int charDriverOpen(struct inode *inodep, struct file *filep)
{
    if ((filep->f_flags & O_ACCMODE) != O_RDWR)
    {
        printk(KERN_ALERT "WARNING : This driver can only be opened in both read and write mode\n");
        return -1;
    }
    printk(KERN_INFO "INFO : CHARATER DRIVER OPENED\n");
    bufferMemory = kmalloc(bufferSize,GFP_KERNEL);
    bufferPointer = 0;
    return 0;   
}

static int charDriverClose(struct inode *inodep, struct file *filep)
{
    kfree(bufferMemory);
    printk(KERN_INFO "INFO : CHARACTER DRIVER CLOSED\n");
    return 0;
}

static ssize_t charDriverWrite(struct file *filep, const char *buffer, size_t len, loff_t *offset)
{
    // Here we will only allow to write one byte of data 
    if (len > bufferSize)
    {
        printk(KERN_WARNING "Attempted to write data larger than 15 byte!\n");
        return 0;
    }
    //bufferMemory[bufferPointer] = *buffer;
    copy_from_user(bufferMemory, buffer, len);
    bufferPointer += len;
    return len;
}

static ssize_t charDriverRead(struct file *filep, char *buffer, size_t len, loff_t *offset)
{
    if(len > bufferSize || len > bufferPointer)
    {
        printk(KERN_WARNING "Attempting to read more than buffer size ! Deny\n");
        return 0;
    }
    copy_to_user(buffer, bufferMemory, len);
//  buffer[0] = bufferMemory[0];
    bufferPointer -= len;
    return len;
}

module_init(charDriverEntry);
module_exit(charDriverExit);
module_param(bufferSize, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(bufferSize, "Buffer Memory Size [15]");
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义设备名称“myCharDevice”
#定义模块名称“myCharDriver”
#定义类名称“myCharClass”
模块许可证(“GPL”);
模块作者(“YASH BHATT”);
模块_版本(“.01”);
静态字符*缓冲存储器;
静态int缓冲指针;
静态int bufferSize=15;
静态开发myChrDevid;
静态结构cdev*mychrdevdev;
静态结构类*pmyCharClass;
静态结构设备*pmyCharDevice;
int majorNumber=0;
静态int-chardriverpen(结构inode*inodep,结构文件*filep);
静态int-charDriverClose(结构inode*inodep,结构文件*filep);
静态ssize\t charDriverWrite(结构文件*filep,常量字符*buffer,大小长度,loff\t*offset);
静态ssize\u t charDriverRead(结构文件*filep,char*缓冲区,大小长度,loff\u t*偏移量);
静态int charDriverEntry(无效);
静态孔隙ChardriveXit(孔隙);
静态ssize_t attrShowData(结构设备*,结构设备属性*,字符*);
静态ssize\u t属性存储数据(结构设备*、结构设备属性*、常量字符*、大小\u t);
静态ssize_t attrShowBuffer(结构设备*,结构设备属性*,字符*);
静态ssize\u t attrStoreBuffer(结构设备*、结构设备属性*、常量字符*、大小\u t);
/*当访问放置在sysfs上的文件进行读取时,将调用以下函数*/
静态ssize_t attrShowData(结构设备*pDev,结构设备属性*attr,字符*buffer)
{
printk(KERN_INFO“MESG:已通过sysfs中的条目访问数据\n”);
if(bufferPointer==0)
{
printk(KERN_警告“没有数据可从缓冲区读取!\n”);
返回-1;
}
strncpy(缓冲区、缓冲内存、缓冲指针);
/*注意:这里我们可以直接使用strncpy,因为我们已经在内核空间中,不需要转换地址*/
返回缓冲指针;
}
静态ssize_t attrStoreData(结构设备*pDev,结构设备属性*attr,常量字符*buffer,大小\u t长度)
{
printk(KERN_INFO“写入属性”\n);
缓冲指针=长度;
strncpy(bufferMemory,buffer,length);
返回长度;
}
静态ssize\u t attrShowBuffer(结构设备*pDev,结构设备属性*attr,字符*buffer)
{
整数计数器;
int temp=缓冲区大小;
char bufferSizeArray[4]={0};
计数器=3;
//printk(内核信息“缓冲区=%d\n”,缓冲区大小%10);
做
{
bufferSizeArray[计数器]=“0”+(bufferSize%10);
//printk(KERN_INFO“字符在%d处为:%c\n”,计数器,bufferSizeArray[计数器];
缓冲区大小/=10;
计数器--;
}
while(计数器!=-1);
strncpy(buffer,bufferSizeArray,4);
缓冲区大小=温度;
/*注意:这里我们可以直接使用strncpy,因为我们已经在内核空间中,不需要转换地址*/
返回4;
}
静态ssize\u t attrStoreBuffer(结构设备*pDev,结构设备属性*attr,常量字符*buffer,大小\u t长度)
{
整数计数器;
缓冲指针=长度;
//printk(KERN_INFO“长度:%d,第一个字符为%c\n”,长度,缓冲区[0]);
缓冲区大小=0;
用于(计数器=0;计数器<长度-1;计数器++)
{
缓冲区大小=(缓冲区大小*10)+(缓冲区[计数器]-“0”);
}
//printk(KERN_INFO“Buffer size new:%d\n”,bufferSize);
返回长度;
}
/*这些宏将函数转换为实例dev_attr_*/
/*宏的定义如下:设备属性(\u名称、\u模式、\u显示、\u存储)*/
/*注意:宏的实际实现在struct device_属性中创建了一个条目。这个宏为我们实现了这一点*/
静态设备_ATTR(ShowData、S_IRWXU、attrShowData、attrStoreData);//S_IRUSR为用户提供读取权限
静态设备_ATTR(缓冲区、S_IRWXU、attrShowBuffer、attrStoreBuffer);//S_IRUSR为用户提供读取权限
静态结构文件\u操作fops=
{
.open=chardrivelopen,
.release=charDriverClose,
.read=charDriverRead,
.write=charDriverWrite,
};
静态int uu init charDriverEntry()
{
返回值;
//majorNumber=寄存器chrdev(0,设备名称和fops);
returnValue=alloc\u chrdev\u区域(&myChrDevid,0,1,设备名称);
/*此函数接受4个参数-dev_t address、次要数字的开始、次要数字的范围/计数、Name;注意-与register_不同,chrdev fops没有
然而,这与主要数字有关*/
如果(返回值<0)
{
printk(KERN_警报“错误:无法获取主要编号!错误%d”,返回值);
返回-1;
}
printk(KERN_INFO“获取的专业编号:%d\n”,专业(myChrDevid));
//cdev_init(&mychrdevcdevdev,&fops);
myChrDevCdev=cdev_alloc();
如果(是错误的(myChrDevCdev))
{
printk(KERN_警报“未能为CharDev结构分配空间”\n);
注销Chrdevu地区(myChrDevid,1);
返回-1;
}
cdev_init(myChrDevCdev和fops);
myChrDevCdev->owner=此_模块;
//myChrDevCdev->ops=&fops;/*此函数使用memset 0初始化c_dev结构,然后执行基本的konject设置,然后将fops添加到cdev结构中*/
/*此函数将cdev添加到内核结构中,以便用户可以使用cdev