Linux字符设备驱动实验

本文介绍了一个名为 Blackhole 的 Linux 设备驱动程序的设计与实现。该设备允许无限写入但无法从中读取数据。文章提供了驱动代码及测试程序,并详细记录了编译安装过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 实验目的: 
实现一个名字为 blackhole 的设备:从该设备读不到任何数据,却可以写入任意多的数据。

2. 实验环境 
系统:Ubuntu 14.04 
内核版本:3.13.0-24

3. 实验代码

//blackhole.c
//驱动代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>

int scull_major = 0;
int scull_minor = 0;
struct cdev cdev;

#define MAX_SIZE 10
size_t size = 0;
char store[MAX_SIZE];

int scull_open(struct inode *inode, struct file *filp) {
    /* trim to 0 the length of the device if open was write-only */
    if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
        size = 0;
    }
    return 0; /* success */
}

int scull_release(struct inode *inode, struct file *filp) {
    return 0;
}

ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){
    //读函数照常即可。
    ssize_t retval = 0;
     if (*f_pos >= size)
        goto out;
     if (*f_pos + count > size)
        count = size - *f_pos;
     if (copy_to_user(buf, store + *f_pos, count)) {
        retval = -EFAULT;
        goto out;
     }

     *f_pos += count;
     retval = count;
 out:
        return retval;
}

ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos){
    return count;//返回输入的字符的size,假装已经写入了该写入的字符。
}

loff_t scull_llseek(struct file *filp, loff_t off, int whence){
    loff_t newpos;
    switch(whence) {
        case 0: /* SEEK_SET */
            newpos = off;
            break;
        case 1: /* SEEK_CUR */
            newpos = filp->f_pos + off;
            break;
        case 2: /* SEEK_END */
            newpos = size + off;
            break;
        default: /* can't happen */
            return -EINVAL;
    }
    if (newpos < 0)
        return -EINVAL;
    filp->f_pos = newpos;
    return newpos;
}

struct file_operations scull_fops = {
    .owner = THIS_MODULE,
    .llseek = scull_llseek,
    .read = scull_read,
    .write = scull_write,
    .release = scull_release,
};

int scull_init_module(void){
    int result; dev_t dev = 0;
/*
 * Get a range of minor numbers to work with, asking for a dynamic major
 */
    result = alloc_chrdev_region(&dev, scull_minor, 1, "scull");
    scull_major = MAJOR(dev);
    if (result < 0) {
        printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
        return result;
    }
    /* register our device */
    cdev_init(&cdev, &scull_fops);
    cdev.owner = THIS_MODULE;
    cdev.ops = &scull_fops;
    result = cdev_add (&cdev, dev, 1);
    if (result) {
        printk(KERN_WARNING "Error %d adding scull", result);
        unregister_chrdev_region(dev, 1);
        return result;
    }
    return 0; /* succeed */
}

void scull_cleanup_module(void){
    /* cleanup_module is never called if registering failed */
    dev_t dev;
    cdev_del(&cdev);
    dev = MKDEV(scull_major, scull_minor);
    unregister_chrdev_region(dev, 1);
}

module_init(scull_init_module);
module_exit(scull_cleanup_module);


 
 
  • 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
//Makefile
//驱动的Makefile文件
obj-m := blackhole.o
 
 
  • 1
  • 2
  • 3
//testDev.c
//测试设备情况代码
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/rtc.h>
#include <linux/ioctl.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int fd;
    int i;
    char data[256] = {0};
    int retval;

    fd = open("/dev/scull", O_RDWR);
    if (fd == 1) {
        perror("open error\n");
        exit(-1);
    }
    printf("open /dev/scull successfully\n");

    retval = write(fd, "1234567", 7);//你要写入的东西。
    if (retval == -1) {
        perror("write error\n");
        exit(-1);
    }
    retval = lseek(fd, 0, 0);
    if (retval == -1) {
        perror("lseek error\n");
        exit(-1);
    }
    retval = read(fd, data, 10);
    if (retval == -1) {
        perror("read error\n");
        exit(-1);
    }
    printf("read successfully: %s\n", data);
    close(fd);
    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
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

4. 实验过程

  1. 编译驱动程序。 
    · 把Makefile文件和驱动代码blackhole.c放在一个目录下,在这个目录下执行命令:

    make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
       
       
    • 1
  2. 安装驱动模块。 
    · 执行命令:

    sudo insmod blackhole.ko 
       
       
    • 1
  3. 检查设备安装情况,记录设备号。 
    · 执行命令,并记录设备号:

    cat /proc/devices | grep scull
       
       
    • 1
  4. 在文件系统里创建设备对应的条目 
    · 执行命令,请注意:命令中的第一个数字 250 应替换为你的系统中设备分配到的 号码,不同系统中分配到的号码可能不一样。:

    sudo mknod /dev/scull c 250 0
       
       
    • 1

    5.测试设备 
    · 编译运行testDev.c:

    sudo gcc testDev.c -o testDev.o
    sudo ./testDev.o
       
       
    • 1
    • 2

这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值