linux-kernel - 使用旧的设备文件作为字符设备驱动程序

标签 linux-kernel linux-device-driver device-driver ioctl

当我作为初学者尝试设备驱动程序时,我有两个问题。

  1. 我创建了一个模块,加载了它,它动态地获取了主编号 251。次要设备数量仅保留 1,即次要设备号 0。为了测试,我在设备文件(使用 mknod 创建)上尝试了 echo 和 cat,它按预期工作。现在,如果我卸载模块但不删除/dev 条目并再次加载具有相同主编号的模块并尝试写入/读取先前使用的相同设备文件,内核将崩溃。我知道我们不应该这样做,但只是想了解在这种情况下发生的情况导致了这次崩溃。我认为 VFS 会做一些事情。

  2. 当我对设备文件执行 cat 操作时,读取会无限期地发生。为什么?要停止这种情况需要使用偏移操作。这看起来是因为默认读取的缓冲区长度为 32768?

编辑:进一步,我添加了一个 ioctl 函数,如下所示,然后我收到有关 init 和 cleanup 函数的存储类的错误,如果没有定义 ioctl,它们可以很好地工作。没有获取 ioctl 和 init/cleanup 函数的存储类之间的链接。更新的代码已发布。错误如下:

    /home/diwakar/Documents/my_modules/first_test_module/flowTest.c:95:12: error: invalid storage class for function ‘flow_init’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_init’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:98:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_ioctl’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:112:13: error: invalid storage class for function ‘flow_terminate’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: error: invalid storage class for function ‘__inittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: invalid storage class for function ‘__exittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: expected declaration or statement at end of input
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: At top level:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:73:13: warning: ‘flow_ioctl’ defined but not used [-Wunused-function]

下面是代码:

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/errno.h>
#include <linux/ioctl.h>

#define SUCCESS 0
#define BUF_LEN 80

#define FLOWTEST_MAGIC 'f'
#define FLOW_QUERY _IOR(FLOWTEST_MAGIC,1,int)

MODULE_LICENSE("GPL");
int minor_num=0,i;
int num_devices=1;
int fopen=0,counter=0,ioctl_test;

static struct cdev ms_flow_cd;
static char c;

///// Open , close and rest of the things

static int flow_open(struct inode *f_inode, struct file *f_file)
{
printk(KERN_ALERT "flowtest device: OPEN\n");
return SUCCESS;
}

static ssize_t flow_read(struct file *f_file, char __user *buf, size_t
  len, loff_t *off)
{
  printk(KERN_INFO "flowtest Driver: READ()\nlength len=%d, Offset = %d\n",len,*off);

/* Check to avoid the infinitely printing on screen. Return 1 on first read, and 0 on subsequent read */
if(*off==1)
return 0;

printk(KERN_INFO "Copying...\n");
copy_to_user(buf,&c,1);
printk(KERN_INFO "Copied : %s\n",buf);

*off = *off+1;
return 1;       // Return 1 on first read 


}

 static ssize_t flow_write(struct file *f_file, const char __user *buf,
  size_t len, loff_t *off)
{
  printk(KERN_INFO "flowtest Driver: WRITE()\n");
 if (copy_from_user(&c,buf+len-2,1) != 0)
  return -EFAULT;
 else
 {
 printk(KERN_INFO "Length len = %d\n\nLast character written  is  - %c\n",len,*(buf+len-2));
 return len;
}
}

static int flow_close(struct inode *i, struct file *f)
{
  printk(KERN_INFO "ms_tty Device: CLOSE()\n");
  return 0;
}

///* ioctl commands *///

static long flow_ioctl (struct file *filp,unsigned int cmd, unsigned long arg)
{
    switch(cmd) {
        case FLOW_QUERY:
            ioctl_test=51;
            return ioctl_test;
        default: 
            return -ENOTTY; 
} 
///////////////////File operations structure below/////////////////////////

struct file_operations flow_fops = {
         .owner =    THIS_MODULE,
         .llseek =   NULL,
         .read =     flow_read,
         .write =    flow_write,
         .unlocked_ioctl =   flow_ioctl,
         .open =     flow_open,
         .release =  flow_close
 };


static int flow_init(void)
    {
    printk(KERN_ALERT "Here with flowTest module ... loading...\n");
 int result=0;
 dev_t dev=0;
result = alloc_chrdev_region(&dev, minor_num, 
num_devices,"mod_flowtest");                              // allocate major number dynamically.

i=MAJOR(dev);
printk(KERN_ALERT "Major allocated = %d",i);

cdev_init(&ms_flow_cd,&flow_fops);
cdev_add(&ms_flow_cd,dev,1);

return 0;
    }

static void flow_terminate(void)
    {
    dev_t devno=MKDEV(i,0);         // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
    printk(KERN_ALERT "Going out... exiting...\n");
    unregister_chrdev_region(devno,num_devices);        //remove entry from the /proc/devices
    }

module_init(flow_init);
module_exit(flow_terminate);

最佳答案

1- 你失踪了 cdev_del()在你的清理函数中。这意味着设备保持注册状态,但处理它的函数被卸载,从而导致崩溃。另外,cdev_add 可能在下一次加载时失败,但您不知道,因为您没有检查返回值。

2-看起来不错...你修改offset,返回正确的字节数,然后如果offset为1则返回0,这表示EOF。但你真的应该检查 *off >= 1。

编辑- 传递到读取处理函数的长度完全来自用户空间 read() 。如果用户打开设备文件并调用read(fd, buf, 32768); ,这仅意味着用户想要读取最多 32768 字节的数据。该长度会一直传递到您的读取处理程序。如果您没有 32768 字节的数据可供提供,则提供您拥有的数据,并返回长度。现在,用户代码不确定这是否是文件末尾,因此它会尝试另一个 32768 读取。您现在确实没有数据,因此返回 0,这告诉用户代码它已达到 EOF,因此它停止。

总之,您在读取处理程序中看到的某种默认值只是实用程序 cat 的 block 大小。用于阅读任何内容。如果您想在读取功能中看到不同的数字,请尝试使用 dd相反,因为它允许您指定 block 大小。

dd if=/dev/flowtest of=/dev/null bs=512 count=1

此外,这应该读取一个 block 并停止,因为您指定了 count=1。如果省略 count=1,它看起来更像 cat ,并尝试读取直到 EOF。

关于linux-kernel - 使用旧的设备文件作为字符设备驱动程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16933015/

相关文章:

linux非标准串行控制台

linux-kernel - Linux函数class_device_create改为?

linux - 如何从内核模块写入 TTY?

c++ - 如何在 Linux 中获取 USB 驱动器标签?

linux - 如何跟踪Linux内核中的write系统调用?

linux - 适用于 Linux 的 PCIe DMA 驱动程序

android - 蓝牙低功耗(蓝牙 4.0)与 Android/Linux

linux-kernel - 更改中断描述符表

windows-xp - 分页池内存还是非分页池内存?? (windows驱动开发)

c++ - 如何在 Windows 中以编程方式强制重启/重新加载播放设备?