当前位置: 首页 > 工具软件 > MIN1PIPE > 使用案例 >

linux字符驱动实现pipe

吕华彩
2023-12-01

基本步骤

驱动所需结构体定制,驱动基本操作函数映射(struct file_operations),xx_init(),
xx_exit(), _open(), xx _release()…,最后要用module_init(),module_exit(),指明函数入出口,再用MODULE_LISCENSE(“GPL”)

驱动需求

用一个驱动操纵四个管道, 每个管道有两个设备(dev0-7),偶数i做写设备, 奇数i+1做相应的读设备

细节

一个major, 八个minor。cdev_init绑定一个struct cdev和struct file_operations, cdev_add将struct cdev和major的起始地和总设备长度绑定, 由于只有一个主设备所以class_create只用执行一次然而device_create要执行次设备数次,用于在/dev/下生成节点。不同设备节点进入可执行的功能不同,在open||release用参数struct inode来定位设备文件主副设备号, read||write则可用struct file

代码

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/semaphore.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#define f_dentry    f_path.dentry 
#define MAXNUM 100
#define MAJOR_NUM 500 

struct mydev{
    struct cdev devm;
    struct semaphore sem[4];
    wait_queue_head_t outq[4];
    int flag[4];
    char buffer[4][MAXNUM+1];
    char *rd[4], *wr[4], *end[4];
}devwrite;

static struct class *myclass;
int major = MAJOR_NUM;

static ssize_t devwrite_read(struct file*, char * ,size_t ,loff_t *);
static ssize_t devwrite_write(struct file*, const char*, size_t, loff_t *);
static int devwrite_open(struct inode *inode, struct file *file);
static int devwrite_release(struct inode *inode, struct file *file);


struct file_operations devwrite_fops =
{
    .read = devwrite_read,
    .write = devwrite_write,
    .open = devwrite_open,
    .release = devwrite_release,
};



static int devwrite_init(void)
{
    
    int i=0;
    int result = 0;
    int err = 0;
    char str[30];
    dev_t dev;
    printk("start....");
   
    /*if(major)
        {
            result = register_chrdev_region(dev, 8, "chwrite");
        }
        else
        {*/
    result = alloc_chrdev_region(&dev, 0, 8, "chwrite");
    major = MAJOR(dev);
       // }
    if(result < 0)
        return result;
    printk("SUCCESS IN REGISTER\n");
    cdev_init(&devwrite.devm, &devwrite_fops);
    printk("SUCCESS IN INIT\n");
    devwrite.devm.owner = THIS_MODULE;
    err = cdev_add(&devwrite.devm, MKDEV(major, 0), 8);
    printk("SUCCESS IN ADD\n");
    for(i=0; i<4; i++)
    {
        
        //dev = MKDEV(major, i);
       
        if(err)
            printk(KERN_INFO "ERROR IN ADDING DEV NUMBER!", err);
        else
        {
            printk(KERN_INFO "SUCCESS IN REGISTER!");
            sema_init(&devwrite.sem[i], 1);
            printk(KERN_INFO "SUCCESS IN SEM!");
            init_waitqueue_head(&devwrite.outq[i]);
            printk(KERN_INFO "SUCCESS IN OUTQ!");
            devwrite.rd[i] = devwrite.buffer[i];
            printk(KERN_INFO "SUCCESS IN BUFFER!");
            devwrite.wr[i] = devwrite.buffer[i];
            devwrite.end[i] = devwrite.buffer[i]+MAXNUM;
            devwrite.flag[i]=0;
            printk(KERN_INFO "SUCCESS IN ALL!");
        }
    
    
    }
   // sprintf(str, "mypipe%d", i);
    
    //printk(KERN_INFO "SUCCESS IN sprint!  %s", str);
    
    myclass = class_create(THIS_MODULE, "mydev");
    printk(KERN_INFO "SUCCESS IN CLASS CREATE!");
    device_create(myclass, NULL, MKDEV(major, 0), NULL, "mypipe0");
    printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
    device_create(myclass, NULL, MKDEV(major, 1), NULL, "mypipe1");
    printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
    device_create(myclass, NULL, MKDEV(major, 2), NULL, "mypipe2");
    printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
    device_create(myclass, NULL, MKDEV(major, 3), NULL, "mypipe3");
    printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
    device_create(myclass, NULL, MKDEV(major, 4), NULL, "mypipe4");
    printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
    device_create(myclass, NULL, MKDEV(major, 5), NULL, "mypipe5");
    printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
    device_create(myclass, NULL, MKDEV(major, 6), NULL, "mypipe6");
    printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
    device_create(myclass, NULL, MKDEV(major, 7), NULL, "mypipe7");
    printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
    return 0;
}

static int devwrite_open(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "SUCCESS IN ENTRANCE OPEN!");
    try_module_get(THIS_MODULE);
    printk("OPEN PIPE0\n");
    return (0);
}


static int devwrite_release(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "SUCCESS IN ENTRANCE LEFT!");
    module_put(THIS_MODULE);
    printk("CLOSE PIPE0\n");
    return (0);
}

static void devwrite_exit(void)
{
    int j=0;
    printk(KERN_INFO "SUCCESS IN ENTRANCE!");
    
    cdev_del(&devwrite.devm);
    for(j=0; j< 8; j++)
    {
        device_destroy(myclass, MKDEV(major, j));
        printk(KERN_INFO "SUCCESS IN DD!");
       
        
    }
    class_destroy(myclass);
    printk(KERN_INFO "SUCCESS IN CD!");
    unregister_chrdev_region(MKDEV(major, 0), 8);
    
    
}

static ssize_t devwrite_read(struct file* file, char * buf,size_t len,loff_t *off)
{
   int temp, tempn;
   int minor = MINOR(file->f_dentry->d_inode->i_rdev);
   temp = minor/2;
   tempn = (minor%2);
   switch(tempn)
   {
       case 0:
       {
           printk("CANT READ IN HERE!\n");
           return -EFAULT;
       }
       case 1:
       {
           if(wait_event_interruptible(devwrite.outq[temp], devwrite.flag[temp]!=0))
               return -ERESTARTSYS;
           if(down_interruptible(&devwrite.sem[temp]))
               return -ERESTARTSYS;
           devwrite.flag[temp]=0;
           
           if(devwrite.rd[temp] < devwrite.wr[temp])
           {
               len = min(len, (size_t)(devwrite.wr[temp] - devwrite.rd[temp]));
               
           }
           else
           {
               len = min(len, (size_t)(devwrite.end[temp] - devwrite.rd[temp]));
           }
           if(copy_to_user(buf, devwrite.rd[temp], len))
           {
                printk(KERN_ALERT"copy failed\n");
       
                up(&devwrite.sem[temp]);
                return -EFAULT;
           }
           devwrite.rd[temp] = devwrite.rd[temp] + len;
           if(devwrite.rd[temp] == devwrite.end[temp])
               devwrite.rd[temp] = devwrite.buffer[temp];
           up(&devwrite.sem[temp]);
           return len;
       }
       
   }
   return -EFAULT; 
}

static ssize_t devwrite_write(struct file* file, const char *buf, size_t len, loff_t *off)
{
   int temp, tempn;
   int minor = MINOR(file->f_dentry->d_inode->i_rdev);
   temp = minor/2;
   tempn = (minor%2);
   switch(tempn)
   {
       case 0:
       {
           if(down_interruptible(&devwrite.sem[temp]))
               return -ERESTARTSYS;
           if(devwrite.rd[temp] <= devwrite.wr[temp])
               len = min(len, (size_t)(devwrite.end[temp] - devwrite.wr[temp]));
           else
               len = min(len, (size_t)(devwrite.rd[temp] - devwrite.wr[temp] - 1));
           
           if(copy_from_user(devwrite.wr[temp] , buf, len))
           {
               up(&devwrite.sem[temp]);
               return -EFAULT;
           }
           
           devwrite.wr[temp] = devwrite.wr[temp] + len;
           if(devwrite.wr[temp] == devwrite.end[temp])
               devwrite.wr[temp] = devwrite.buffer[temp];
           up(&devwrite.sem[temp]);
           devwrite.flag[temp] = 1;
           wake_up_interruptible(&devwrite.outq[temp]);
           return len;
       }
       case 1:
       {
           printk("CANT WRITE IN HERE!\n");
           return -EFAULT;
       }
    }
    return -EFAULT;
}

module_init(devwrite_init);
module_exit(devwrite_exit);
MODULE_LICENSE("GPL");

Makefile

ifneq ($(KERNELRELEASE),)
    obj-m := mycdev.o#obj-m 
else
    KERNELDIR := /lib/modules/$(shell uname -r)/build 
    PWD := $(shell pwd)
modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD)
endif
clean:
	rm -f *.o *.ko *.mod.c *.symvers *.c~ *~ *.order

执行

make
insmod mycdev.ko

效果观察

echo “hello, can you hear me?” > /dev/mypipe1
cat /dev/mypipe0

卸载

rmmod mycdev.ko

调试要点

多加入printk输出错误信息
再使用 dmesg一步步检测

 类似资料: