繁体   English   中英

Linux内核char驱动程序写调用未按预期工作

[英]Linux kernel char driver write call is not working as expected

我正在尝试使用字符驱动程序实现FIFO。 但是,在写入设备时,它似乎不起作用。 它似乎并没有结束循环。 任何帮助或链接表示赞赏。 我已经从许多来源获得帮助,所以当前的代码有些混乱,而实际情况并非如此。

static ssize_t dev_write(struct file *filp, const char *buff, size_t len, loff_t *off) {
int mode;
int ind;
ssize_t count = -ENOMEM;
printk(KERN_ALERT "to be written : %s\n", buff);
mode = iminor(filp->f_dentry->d_inode);
printk(KERN_ALERT "Device minor : %d\n", mode);
if ((mode == 1) || (mode ==3))
        return -EINVAL;
if (mode == 0){
    count = 0;
    ind = 0;
    if (buff[ind] == NULL) {
        return -ENOMEM;
    }
    printk(KERN_ALERT "Write position1 : %d\n", writePos1);
    while(ind<=len) {  //loop untill we have something to writer
        if (down_interruptible(&buffer1_e)) { //taking flag first isn't right because that won't allow other guyto give access to our turn.
                printk(KERN_ALERT "buffer1 flag didn't work\t %d", buffer1_e.count);
                return -ERESTARTSYS;
        }
        else {
            if (down_interruptible(&flag1)){
                up(&buffer1_e);         //must because we couldn't write it properly
                return -EINVAL;
            }
            else {
                queue1[writePos1] = buff[ind];
                printk(KERN_ALERT "Write %d %c\n",ind,queue1[writePos1]);
                if (writePos1 == 9){
                     writePos1 = 0;
                }
                else
                     writePos1++;
                count++;
            }
            up(&flag1);
        }
        up(&buffer1_f);
        off += count;
        ind++;
    }
    printk(KERN_ALERT "Write position1 now: %d\t and count%d\n", writePos1,count);
    return count-1;
}

我只是编写了自己的模块,并且怀疑您的问题是调用dev_write的进程期望dev_write返回写入的字节数。 如果您没有返回正确的数字(我看到您正在返回count-1),则dev_write将被反复调用。

我发现dev_read是相似的-直到它返回0,该过程将反复调用它-期望有更多的字符要检索(这很有意义)。

我已经编写/修改了一个更加简单的模块,该模块说明了如何将模块用作字符缓冲区(对不起,编写起来很仓促)。 它应该允许您向它回显一个字符串,并在接收或读取它时返回该字符串。 当您make run时就可以证明这一点。 我相信您将能够轻松地对其进行修改以使其成为FIFO。

对于崩溃的内核或其他问题,我不承担任何责任,无论如何,您都应该使用VM。

很长,所以在我的github上:

git clone https://github.com/n-hutton/tempRepo
cd tempRepo
make
make run

最后,我更正了完整的代码。 这是非常不成熟的,对于少数逻辑而言,这是不合逻辑的,但我仍然愿意这样做。 @Nathan Hutton在改进和使它起作用方面提供了很多帮助。 我为此感谢他。 尽管仍有很多问题,我仍然有一个主要的疑问,如果您可以在内核日志中跟踪它,则每次使用(echo“ test” | cat> / dev / fifo0)写入设备时,都会添加一个额外的换行符。要正确运行它,您还需要创建4个字符设备,它们的主要编号为240,次要编号为0、1、2、3。 mknod可以用作:“ mknod / dev / fifo(0,1,2,3)c 240(0,1,2,3)-m 777” //一次0,1,2,3和777可以修改粒度。 最后的工作代码:

#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/unistd.h>
#include <linux/time.h>
#include <linux/semaphore.h>

#define DEVNO 240
#define DEVNAME "fifo"
MODULE_LICENSE("GPL");
DECLARE_WAIT_QUEUE_HEAD(writing1);
//static short writeFlag1=0;
static DEFINE_SEMAPHORE(flag1);
static DEFINE_SEMAPHORE(flag2);
static struct semaphore buffer1_f;
static struct semaphore buffer2_f;
static struct semaphore buffer1_e;
static struct semaphore buffer2_e;

DECLARE_WAIT_QUEUE_HEAD(writing2);
//static short writeFlag2=0;

static char queue1[10]={0};
static short readPos1=0;
static short writePos1=0;
//static short qsize1=0;

static char queue2[10]={0};
static short readPos2=0;
static short writePos2=0;
//static short qsize2=0;

static int times=0;

static int dev_open(struct inode *,struct file *);
static int dev_rls(struct inode *,struct file *);
static ssize_t dev_read(struct file *,char *,size_t,loff_t *);
static ssize_t dev_write(struct file *,const char *,size_t,loff_t *);

static struct file_operations fops={
  .read=dev_read,
  .write=dev_write,
  .open=dev_open,
  .release=dev_rls,
};

int init_module(void){
  unsigned int devno = 240;
  char *devname = "fifo";
  int t;
  sema_init(&buffer1_f,0);
  sema_init(&buffer2_f,0);
  sema_init(&buffer1_e,10);
  sema_init(&buffer2_e,10);
  memset(queue1,0,10);
  memset(queue2,0,10);
  t=register_chrdev(devno,devname,&fops);
  if(t<0) printk(KERN_ALERT "device reg failed. \n");
  else printk(KERN_ALERT "Device registered. \n");
  return t;
}

void cleanup_module(void) {
  unregister_chrdev(240,"fifo");
  printk(KERN_ALERT "Device has been removed");
}

static int dev_open(struct inode *inod, struct file *fil){
  times++;
  printk(KERN_ALERT "Device opened %d times\n",times);
  return 0;
}

static ssize_t dev_read(struct file *filep, char *buff, size_t len, loff_t *off) {
  int mode = iminor((filep->f_dentry->d_inode));
  short count;
  printk(KERN_ALERT "Device minor when read : %d\n", mode);
  if ((mode == 0) || (mode ==2))
      return -EINVAL;
  else if (mode == 1){
    count = 0;
    printk(KERN_ALERT "Read position1 when read: %d\n", readPos1);
    while(len) {  //loop untill we have something to write or empty buffer
      if (readPos1==writePos1){
        printk(KERN_ALERT "Returning chars put to buffer: %d\n", count);
        return count;
      }
      if (down_interruptible(&buffer1_f)) {
          printk(KERN_ALERT "flag1 didn't work");
          return -ERESTARTSYS;
      }
      else {
        if (down_interruptible(&flag1)){
          return -EINVAL;
        }
        else {
          printk(KERN_ALERT "Read %c\n",queue1[readPos1]);
          put_user(queue1[readPos1],buff++);
                    if (writePos1==-1) writePos1=readPos1;
          if (readPos1 == 9) readPos1 = 0;
          else readPos1++;
          count++;
        }
        up(&flag1);
      }
      up(&buffer1_e);
    }
    printk(KERN_ALERT "Read position1 now: %d\t and count%d\n", readPos1,count);
    return count;  
  }
  else if (mode == 3){
    count = 0;
    printk(KERN_ALERT "Read position2 when read: %d\n", readPos2);
    while(len) {  //loop untill we have something to write or empty buffer
      if (readPos2==writePos2){
        printk(KERN_ALERT "Returning chars put to buffer: %d\n", count);
        return count;
      }
      if (down_interruptible(&buffer2_f)) {
          printk(KERN_ALERT "flag2 didn't work");
          return -ERESTARTSYS;
      }
      else {
        if (down_interruptible(&flag2)){
          return -EINVAL;
        }
        else {
          printk(KERN_ALERT "Read %c\n",queue2[readPos2]);
          put_user(queue2[readPos2],buff++);
                    if (writePos2==-1) writePos2=readPos2;
          if (readPos2 == 9) readPos2 = 0;
          else readPos2++;
          count++;
        }
        up(&flag2);
      }
      up(&buffer2_e);
    }
    printk(KERN_ALERT "Read position2 now: %d\t and count%d\n", readPos2,count);
    return count;  
  }
  else {
    printk(KERN_ALERT "Not correct mode\n");
    return -1;
  }
}
static char Message[100] = "Initial message\n";
static ssize_t dev_write(struct file *filp, const char *buff, size_t len, loff_t *off) {
  int mode;
  int ind;
  ssize_t count = -ENOMEM;
  int i;
  //Let's copy the message onto our stack so we can be clear what we are getting
  for (i = 0; i < 99 && i < len; i++){
    char getChar;
    get_user(getChar, buff + i);
    Message[i] = getChar;
  }
  Message[i] = '\0';
    printk(KERN_ALERT "to be written : %s\n", Message);
  mode = iminor(filp->f_dentry->d_inode);
  printk(KERN_ALERT "Device minor : %d\n", mode);
  if ((mode == 1) || (mode ==3))
    return -EINVAL;
  else if (mode == 0){
    count = 0;
    ind = 0;
    if (( buff == NULL) ||  (*buff == 0)) {
      return -ENOMEM;
    }
    printk(KERN_ALERT "Write position1 : %d\n", writePos1);
    while(ind<len) {  //loop untill we have something to writer
      if (down_interruptible(&buffer1_e)) { //taking flag first isn't right because that won't allow other guyto give access to our turn.
        printk(KERN_ALERT "buffer1 flag didn't work\t %d", buffer1_e.count);
        return -ERESTARTSYS;
      }
      else {
        if (down_interruptible(&flag1)){
          up(&buffer1_e);     //must because we couldn't write it properly
          return -EINVAL;
        }
        else {
          queue1[writePos1] = buff[ind];
          printk(KERN_ALERT "Write ind:%d writepos:%d readpos;%d char:%c\tascii%d\n",ind,writePos1,readPos1,queue1[writePos1],(int)queue1[writePos1]);
                    if (readPos1==((writePos1+1)%10)) {
                        writePos1=-1;
                    }
          else if (writePos1 == 9){
             writePos1 = 0;
          }
          else
             writePos1++;
          count++;
        }
                printk(KERN_ALERT "writepos:%d",writePos1);
        up(&flag1);
      }
      up(&buffer1_f);
      off += count;
      ind++;
    }
    printk(KERN_ALERT "Write position1 now: %d\t and count%d\n", writePos1,(int)count);
    printk(KERN_ALERT "Note: our allowable buffer length was %d\n", (int)len);
    return count;
  }
  else if (mode == 2){
    count = 0;
    ind = 0;
    if (( buff == NULL) ||  (*buff == 0)) {
      return -ENOMEM;
    }
    printk(KERN_ALERT "Write position2 : %d\n", writePos2);
    while(ind<len) {  //loop untill we have something to writer
      if (down_interruptible(&buffer2_e)) { //taking flag first isn't right because that won't allow other guyto give access to our turn.
        printk(KERN_ALERT "buffer2 flag didn't work\t %d", buffer2_e.count);
        return -ERESTARTSYS;
      }
      else {
        if (down_interruptible(&flag2)){
          up(&buffer2_e);     //must because we couldn't write it properly
          return -EINVAL;
        }
        else {
          queue2[writePos2] = buff[ind];
          printk(KERN_ALERT "Write ind:%d writepos2:%d readpos2;%d char:%c\tascii%d\n",ind,writePos2,readPos2,queue2[writePos2],(int)queue2[writePos2]);
                    if (readPos2==((writePos2+1)%10)) {
                        writePos2=-1;
                    }
          else if (writePos2 == 9){
             writePos2 = 0;
          }
          else
             writePos2++;
          count++;
        }
                printk(KERN_ALERT "writepos:%d",writePos2);
        up(&flag2);
      }
      up(&buffer2_f);
      off += count;
      ind++;
    }
    printk(KERN_ALERT "Write position2 now: %d\t and count%d\n", writePos2,(int)count);
    printk(KERN_ALERT "Note: our allowable buffer length was %d\n", (int)len);
    return count;
  }
  else {
    printk(KERN_ALERT "This meant wrong device minor accessed\n");
    return -1;
  }
}
static int dev_rls(struct inode *inod, struct file *fil) {
  printk(KERN_ALERT "Device is closed\n");
  return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM