Linux kernel 如何使读取操作在这里的伪驱动程序中只发生一次?

Linux kernel 如何使读取操作在这里的伪驱动程序中只发生一次?,linux-kernel,kernel,linux-device-driver,Linux Kernel,Kernel,Linux Device Driver,我正在尝试编写一个内核驱动程序。但是,当我在cat/dev/pSeudoDrv上执行cat操作时。它只是不断打印值。它永远不存在。我假设cat操作在读取一次后应该退出。然而,它永远在阅读。这里有什么问题 #include <linux/init.h> #include <linux/module.h> /** needed by all modules **/ #include <linux/kernel.h> /** This is for KERN_AL

我正在尝试编写一个内核驱动程序。但是,当我在cat/dev/pSeudoDrv上执行cat操作时。它只是不断打印值。它永远不存在。我假设cat操作在读取一次后应该退出。然而,它永远在阅读。这里有什么问题

#include <linux/init.h>
#include <linux/module.h> /** needed by all modules **/
#include <linux/kernel.h>  /** This is for KERN_ALERT **/
#include <linux/fs.h> /** for file operations **/
#include <linux/cdev.h>  /** character device **/
#include <linux/device.h>  /** for sys device registration in /dev/ and /sys/class **/
/** for copy_to_user **/
#include <asm/uaccess.h>


/** For class registration to work, you need GPL license **/
MODULE_LICENSE("GPL");


static struct cdev basicCdev;
static struct class *basicDriverClass;

static int  basicMajorNumber = 0;

/** Prototype for read, this will be invoked when the read function is done on to the driver **/
/** The declaration type is file operations based function pointer - read **/
static ssize_t basicRead(struct file *filp, char *buffer, size_t length,loff_t *offset);

static int basicOspen(struct inode *inode, struct file *file);   

/** File Operations function pointer table **/
/** There are plenty of file operations  **/

static struct file_operations fops = {
  .read = basicRead,
  .write = NULL,
  .open = basicOspen,
  .release = NULL
};

static ssize_t basicRead(struct file *filp, char *buffer, size_t length, loff_t *offset)
{
     char msg[1024] = "Hello SJ_read\0";
     printk(KERN_ALERT "The Read operation called\r\n");
     copy_to_user( buffer, msg, sizeof(msg) );
     return sizeof(msg);
}

static int basicOspen(struct inode *inode, struct file *file)
{

   printk("Kernel.Basic Driver Opened now!!\r\n");

   return 0;
}

static void setup_cdev(struct cdev *dev, int minor, struct file_operations *fops)
{
         int err = -1;
         /** MKDEV call creates a device number i.e. combination of major and minor number **/
         int devno = MKDEV(basicMajorNumber, minor);
         /** Initiliaze character dev with fops **/
         cdev_init(dev, fops);
         /**owner and operations initialized **/
         dev->owner = THIS_MODULE;
         dev->ops = fops;
         /** add the character device to the system**/
         /** Here 1 means only 1 minor number, you can give 2 for 2 minor device, the last param is the count of minor number enrolled **/
         err = cdev_add (dev, devno, 1);

         if (err)
         {
                 printk (KERN_NOTICE "Couldn't add cdev");
         }
 }

static int chrDriverInit(void)
{

    int result;
    dev_t dev; 

    printk("Welcome!! Device Init now..");

    /** int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name);  **/
    /** dev -> The dev_t variable type,which will get the major number that the kernel allocates.  **/
    /**The same name will appear in /proc/devices.  **/

    /** it is registering the character device **/   
    /** a major number will be dynamically allocated here **/
    result = alloc_chrdev_region(&dev, 0, 1, "pSeudoDrv");

    if( result < 0 )
    {
      printk("Error in allocating device");
      return -1;    
    }

    /** From these two if's we are avoiding the manual mknod command to create the /dev/<driver> **/
    /**  creating class, and then device created removes the dependency of calling mknod  **/
    /** A good method - the mknod way is depreciated **/
    /** mknod way is -  mknod /dev/<driver_name> c <majorNumber> <minorNumber>


    /** add the driver to /sys/class/chardrv **/
    if ((basicDriverClass = class_create(THIS_MODULE, "chardrv")) == NULL)    //$ls /sys/class
    {
        unregister_chrdev_region(dev, 1);
        return -1;
    }

     /** add the driver to /dev/pSeudoDrv -- here **/
    if (device_create(basicDriverClass, NULL, dev, NULL, "pSeudoDrv") == NULL) //$ls /dev/
    {
        class_destroy(basicDriverClass);
        unregister_chrdev_region(dev, 1);
        return -1;
    }

     /** let's see what major number was assigned by the Kernel **/
     basicMajorNumber = MAJOR(dev);
     printk("Kernel assigned major number is %d ..\r\n",basicMajorNumber );

    /** Now setup the cdev **/
    setup_cdev(&basicCdev, 0, &fops);

    return 0;   

}


static void chrDriverExit(void)
{
    /** A reverse - destroy mechansim -- the way it was created **/
    printk("Releasing Simple Devs -- %s\r\n",  __FUNCTION__);
    /** delete the character driver added **/
    cdev_del(&basicCdev);
    /** destroy the device created **/
    device_destroy(basicDriverClass, MKDEV(basicMajorNumber, 0));
    /** destroy the class created **/
    class_destroy(basicDriverClass);
    /** unregister the chr dev **/
    unregister_chrdev(basicMajorNumber, "pSeudoDrv");

}


module_init(chrDriverInit);
module_exit(chrDriverExit);
#包括
#包括所有模块所需的/****/
#包括/**这是针对内核警报的**/
#包含/**用于文件操作**/
#包括/**字符设备**/
#包括/**用于在/dev/和/sys/class中注册系统设备**/
/**用于将\u复制到\u用户**/
#包括
/**要使类注册生效,您需要GPL许可证**/
模块许可证(“GPL”);
静态结构cdev-basicdev;
静态结构类*basicDriverClass;
静态int basicMajorNumber=0;
/**对于读取的原型,当对驱动程序执行读取功能时,将调用该原型**/
/**声明类型是基于文件操作的函数指针读取**/
静态ssize\u t基本增量(结构文件*filp,字符*buffer,大小长度,loff\u t*偏移量);
静态int basicOspen(struct inode*inode,struct file*file);
/**文件操作函数指针表**/
/**有很多文件操作**/
静态结构文件\u操作fops={
.read=basicRead,
.write=NULL,
.open=basicOspen,
.release=NULL
};
静态ssize\u t基本增量(结构文件*filp,字符*buffer,大小长度,loff\u t*偏移量)
{
char msg[1024]=“你好,SJ_读取\0”;
printk(KERN_ALERT“读取操作调用\r\n”);
将_复制到_用户(缓冲区、消息、大小(消息));
返回sizeof(msg);
}
静态int basicOspen(结构inode*inode,结构文件*file)
{
printk(“Kernel.Basic驱动程序现在已打开!!\r\n”);
返回0;
}
静态无效设置\u cdev(结构cdev*dev,int minor,结构文件\u操作*fops)
{
int err=-1;
/**MKDEV调用创建一个设备编号,即主要编号和次要编号的组合**/
int devno=MKDEV(基本主数字,次要);
/**使用fops初始化角色开发**/
cdev_init(dev,fops);
/**所有者和操作已初始化**/
dev->owner=此_模块;
dev->ops=fops;
/**将字符设备添加到系统中**/
/**这里1表示只有1个次要编号,您可以为2个次要设备指定2,最后一个参数是注册的次要编号的计数**/
err=cdev_add(dev,devno,1);
如果(错误)
{
printk(KERN_通知“无法添加cdev”);
}
}
静态int CHRDIVERINIT(无效)
{
int结果;
发展与发展;
printk(“欢迎!!现在设备初始化…”);
/**int alloc_chrdev_区域(dev_t*dev,unsigned int firstminor,unsigned int count,char*name)**/
/**dev->dev_t变量类型,它将获取内核分配的主要编号**/
/**相同的名称将出现在/proc/devices中**/
/**它正在注册字符设备**/
/**将在此处动态分配主要编号**/
结果=alloc_chrdev_区域(&dev,0,1,“伪DRV”);
如果(结果<0)
{
printk(“设备分配错误”);
返回-1;
}
/**从这两个if中,我们避免使用手动mknod命令来创建/dev/**/
/**创建类,然后创建设备将删除调用mknod的依赖关系**/
/**一个很好的方法——mknod方法是折旧的**/
/**mknod的方式是-mknod/dev/c
/**将驱动程序添加到/sys/class/chardrv**/
if((basicDriverClass=class\u create(这个模块,“chardrv”))==NULL)/$ls/sys/class
{
注销chrdev_地区的注册(dev,1);
返回-1;
}
/**将驱动程序添加到/dev/pSeudoDrv--here**/
if(device_create(basicDriverClass,NULL,dev,NULL,“pSeudoDrv”)==NULL)/$ls/dev/
{
销毁类(基本类);
注销chrdev_地区的注册(dev,1);
返回-1;
}
/**让我们看看内核分配了什么主要编号**/
basicMajorNumber=主要(开发);
printk(“内核分配的主要编号为%d..\r\n”,基本主编号);
/**现在设置cdev**/
设置cdev(&basicCdev、0和fops);
返回0;
}
静态void chdriverxit(void)
{
/**一个反向破坏机制——它的创建方式**/
printk(“发布简单dev--%s\r\n”,函数);
/**删除添加的字符驱动程序**/
cdev_del(和基本开发);
/**销毁创建的设备**/
设备销毁(basicDriverClass,MKDEV(basicMajorNumber,0));
/**销毁创建的类**/
销毁类(基本类);
/**注销chr dev**/
注销chrdev(基本注册号,“伪DRV”);
}
模块初始化(chrDriverInit);
模块_出口(CHRRIVEREXIT);

basicRead
中查看您的返回值

从LDD3:

read的返回值由调用应用程序解释 节目:

  • 如果该值等于传递给读取系统调用的count参数,则已传输请求的字节数。这是 最佳情况

  • 如果该值为正,但小于计数,则仅传输了部分数据。发生这种情况的原因有很多, 取决于设备。通常,应用程序会重试 阅读。例如,如果使用fread函数进行读取 库函数重新发出系统调用,直到完成 请求的数据传输

  • 如果该值为0,则表示已到达文件末尾(并且未读取任何数据)

  • 负值表示存在错误。根据,该值指定错误是什么。返回的典型值 on错误包括-EINTR(中断的系统调用)或-EFAULT(错误 地址)

在您的例子中,sizeof(msg)小于length,它表示部分读取的用户空间。 如果你不关心部分阅读,你可以简单地做