当前位置:   article > 正文

linux字符设备驱动+fops应用测试程序

linux字符设备驱动+fops应用测试程序

linux字符设备驱动

mychar.c,支持fops和/proc下的proc_fops接口:

#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/fs.h>  
#include <linux/cdev.h>  
#include <linux/uaccess.h>  
#include <linux/slab.h>  // 包含这个头文件来使用 kmalloc 和 kfree
#include <linux/proc_fs.h>  
#include <linux/seq_file.h>

#define DEVICE_NAME "mychar"  
#define CLASS_NAME  "mychar_class"  
#define BUFFER_SIZE 1024  
  
static int major;  
static struct cdev *my_cdev;  
static char *buffer;  
static int buffer_size = BUFFER_SIZE;  
  
static int mychar_open(struct inode *inode, struct file *file) {  
    printk(KERN_INFO "mychar_open\n");  
    return 0;  
}  
  
static ssize_t mychar_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {  
    unsigned long p = *ppos;  
    unsigned int copy;  
  
    if (p >= buffer_size)  
        return 0;  
  
    if (count > buffer_size - p)  
        count = buffer_size - p;  
  
    if (copy_to_user(buf, buffer + p, count))  
        return -EFAULT;  
  
    *ppos += count;  
    return count;  
}  
  
static ssize_t mychar_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {  
    unsigned long p = *ppos;  
    unsigned int copy;  
  
    if (p >= buffer_size)  
        return 0;  
  
    if (count > buffer_size - p)  
        count = buffer_size - p;  
  
    if (copy_from_user(buffer + p, buf, count))  
        return -EFAULT;  
  
    *ppos += count;  
    return count;  
}  
  
static loff_t mychar_llseek(struct file *file, loff_t offset, int whence) {  
    loff_t newpos = file->f_pos;  
  
    switch (whence) {  
    case SEEK_SET:  
        newpos = offset;  
        break;  
    case SEEK_CUR:  
        newpos += offset;  
        break;  
    case SEEK_END:  
        newpos = buffer_size + offset;  
        break;  
    default:  
        return -EINVAL;  
    }  
  
    if (newpos < 0 || newpos > buffer_size)  
        return -EINVAL;  
  
    file->f_pos = newpos;  
    return newpos;  
}  
  
static struct file_operations mychar_fops = {  
    .owner = THIS_MODULE,  
    .open = mychar_open,  
    .read = mychar_read,  
    .write = mychar_write,  
//    .llseek = mychar_llseek,  
};  
  
// 假设你有一个字符设备的私有数据结构
struct mychar_dev {
    // ... 设备特定的数据 ...
    char buffer[4096]; // 示例缓冲区
    size_t buffer_pos; // 示例缓冲区中的当前位置
};
static struct mychar_dev mychar_device;

// /proc 文件的读取处理函数  
static ssize_t mychar_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {  
    size_t len;  
    if (*ppos >= sizeof(mychar_device.buffer) || count == 0)  
        return 0;  
  
    len = min(count, sizeof(mychar_device.buffer) - (size_t)*ppos);  
    if (copy_to_user(buf, mychar_device.buffer + *ppos, len))  
        return -EFAULT;  
  
    *ppos += len;  
    return len;  
}  
  
// /proc 文件的写入处理函数  
static ssize_t mychar_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {  
    size_t len;  
    if (*ppos >= sizeof(mychar_device.buffer) || count == 0)  
        return 0;  
  
    len = min(count, sizeof(mychar_device.buffer) - (size_t)*ppos);  
    if (copy_from_user(mychar_device.buffer + *ppos, buf, len))  
        return -EFAULT;  
  
    // 更新设备缓冲区的位置(如果需要的话)  
    // 这里我们简单地增加偏移量,但你可以根据需要进行更复杂的处理  
    *ppos += len;  
    // 注意:在实际的设备驱动中,你可能需要同步缓冲区到硬件或执行其他操作  
  
    return len;  
}  
  
// /proc 文件的 file_operations 结构体  
static const struct file_operations mychar_proc_fops = {  
    .owner = THIS_MODULE,  
    .read = mychar_proc_read,  
    .write = mychar_proc_write,  
    // 注意:没有 open 和 release,因为 /proc 文件系统的处理是自动的  
    // 也没有 llseek,因为 /proc 文件通常不支持随机访问  
};  

static struct class *mychar_class;
static struct proc_dir_entry *mychar_proc_entry;

static int __init mychar_init(void) {  
    int err;  
    dev_t devno = MKDEV(major, 0);  
  
    if (major) {  
        my_cdev = cdev_alloc();  
        my_cdev->owner = THIS_MODULE;  
        my_cdev->ops = &mychar_fops;  
        my_cdev->dev = devno;  
        err = cdev_add(my_cdev, MKDEV(major, 0), 1);  
  
        if (err) {  
            printk(KERN_NOTICE "Error %d adding mychar", err);  
            return err;  
        }  
    } else {  
        err = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);  
        if (err < 0) {  
            printk(KERN_NOTICE "Error %d registering character device", err);  
            return err;  
        }  
        major = MAJOR(devno);  
        my_cdev = cdev_alloc();  
        my_cdev->owner = THIS_MODULE;  
        my_cdev->ops = &mychar_fops;  
        my_cdev->dev = devno;  
        err = cdev_add(my_cdev, MKDEV(major, 0), 1);
	if (err) {  
            unregister_chrdev_region(MKDEV(major, 0), 1);  
            printk(KERN_NOTICE "Error %d adding mychar", err);  
            return err;  
        }  
    }  
  
    buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);  
    if (!buffer) {  
        cdev_del(my_cdev);  
        unregister_chrdev_region(MKDEV(major, 0), 1);  
        printk(KERN_NOTICE "Failed to allocate device buffer\n");  
        return -ENOMEM;  
    }  
  
    // 创建设备类  
    mychar_class = class_create(THIS_MODULE, CLASS_NAME);  
    if (IS_ERR(mychar_class)) {  
        printk(KERN_WARNING "Failed to register device class\n");  
        cdev_del(my_cdev);  
        unregister_chrdev_region(MKDEV(major, 0), 1);  
        kfree(buffer);  
        return PTR_ERR(mychar_class);  
    }  
  
    // 创建设备  
    device_create(mychar_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);  

    // 创建 /proc 文件
    mychar_proc_entry = proc_create("mychar", 0666, NULL, &mychar_proc_fops);  
    if (!mychar_proc_entry) {  
        pr_err("Failed to create /proc/mychar\n");  
        return -ENOMEM; // 或者其他适当的错误码  
    }  


    printk(KERN_INFO "mychar device registered with major number %d\n", major);  
    return 0;  
}  
  
static void __exit mychar_exit(void) {  
    device_destroy(mychar_class, MKDEV(major, 0));  
    class_destroy(mychar_class);  
    cdev_del(my_cdev);  
    unregister_chrdev_region(MKDEV(major, 0), 1);  
    kfree(buffer);  
    if (mychar_proc_entry) {
        remove_proc_entry("mychar", NULL);
    }
    printk(KERN_INFO "mychar device unregistered\n");  
}  
  
module_init(mychar_init);  
module_exit(mychar_exit);  
  
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("Your Name");  
MODULE_DESCRIPTION("A simple character device driver");

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227

Makefile:


KERN_DIR = /home/book/demo/linux-5.4

obj-m += mychar.o  
  
all:  
	make -C $(KERN_DIR) M=`pwd` modules
  
clean:  
	make -C $(KERN_DIR) M=`pwd` modules clean

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

lseek.c应用:

#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
  
#define BUFFER_SIZE 2048  // 定义缓冲区大小  
  
int main(int argc, char *argv[]) {  
    int fd;  
    ssize_t ret;  
    off_t pos;  
    char buffer[BUFFER_SIZE];  
  
    // 假设 fd 已经被正确打开  
    fd = open(argv[1], O_RDONLY);  
    if (fd < 0) {  
        perror("open failed");  
        return EXIT_FAILURE;  
    }  
  
    // 首次读取(可能不需要,但根据原始代码保留)  
    ret = read(fd, buffer, 0);  // 这里传递 0 字节,实际上不会读取任何内容  
    if (ret != 0) {  
        perror("Unexpected read return");  
        close(fd);  
        return EXIT_FAILURE;  
    }  
    printf("***********read ret=%d\n", ret);
  
    // 重置文件位置  
    pos = lseek(fd, 0, SEEK_SET);  
    if (pos < 0) {  
        perror("lseek failed");  
        close(fd);  
        return EXIT_FAILURE;  
    }  
    printf("***********lseek pos=%d\n", (int)pos);
  
    // 清理缓冲区(虽然在这个场景下可能不是必需的)  
    memset(buffer, 0, BUFFER_SIZE);  
  
    // 读取文件内容到缓冲区  
    ret = read(fd, buffer, BUFFER_SIZE);  
    if (ret < 0) {  
        perror("read failed");  
        close(fd);  
        return EXIT_FAILURE;  
    }  
    printf("***********read ret=%d\n", ret);
  
    // 检查是否读取了足够的数据来检查换行符  
    if (ret < (ssize_t)(BUFFER_SIZE >> 1)) {  
        char *bptr = buffer;  
  
        // 查找换行符  
        while (*bptr && *bptr != '\n') {  
            bptr++;  
        }  
  
        if (*bptr == '\n') {  
            const off_t offset = 2 + (bptr - buffer);  
  	    printf("***********offset=%d\n", (int)offset);
            // 跳转到换行符后的位置  
            pos = lseek(fd, offset, SEEK_SET);  
            if (pos == (off_t)-1) {  
                perror("lseek failed");  
                close(fd);  
                return EXIT_FAILURE;  
            }  
	    printf("***********lseek pos=%d\n", (int)pos);
  
            // 从新位置读取(如果需要)  
            // 注意:这里可能需要额外的逻辑来决定是否再次读取  
            // 这里仅作为示例,不实际读取  
            ret = read(fd, buffer, BUFFER_SIZE);
	    printf("***********read ret=%d\n", ret);  
            // (void)ret;  
        }  
    }  

	off_t dec;

	pos = lseek(fd, 0, SEEK_END);
	printf("***********lseek pos=%d\n", (int)pos);
	if (pos < 0)
		return EXIT_FAILURE;
	dec = pos / 13;
	printf("***********dec=%d\n", (int)dec);
	if (dec < 1)
		dec = 1;
	while (pos > 0) {
		off_t seek_pos;

		seek_pos = lseek(fd, pos, SEEK_SET);
		printf("***********lseek seek_pos=%d\n", (int)seek_pos);
		if (seek_pos < 0)
			break;
		ret = read(fd, buffer, 5);
		printf("***********read ret=%d\n", ret);
		(void)ret;

		if (dec > pos)
			dec = pos;
		pos -= dec;
	}


    // 关闭文件描述符  
    close(fd);  
  
    return EXIT_SUCCESS;  
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117

scandir.c应用:

#include <stdio.h>
#include <dirent.h>

int  main(int argc,char* argv[],char* envp[]) {
    struct dirent **namelist;
    printf("argc=%d, argv[0]=%s, argv[1]=%s\n", argc, argv[0], argv[1]);
    int numEntries = scandir(argv[1], &namelist, NULL, alphasort);
    if (numEntries < 0) {
        perror("scandir");
    } else {
        for (int i = 0; i < numEntries; i++) {
            printf("File %d: %s\n", i, namelist[i]->d_name);
        }
    }

    // 释放动态分配的内存
    for (int i = 0; i < numEntries; i++) {
        free(namelist[i]);
    }
    free(namelist);

    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/886749
推荐阅读
相关标签
  

闽ICP备14008679号