Linux字符设备驱动实验

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);

//Makefile
//驱动的Makefile文件
obj-m := blackhole.o
//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;
}

4. 实验过程

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

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

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

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

    sudo mknod /dev/scull c 250 0

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

    sudo gcc testDev.c -o testDev.o
    sudo ./testDev.o

这里写图片描述

参考文档
- linux驱动学习3:实现一简单完整驱动(包括open,read,write,ioctl)
http://blog.csdn.net/yangjin_unique/article/details/8222465
- 北京交通大学杨武杰老师课程课件

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux字符设备驱动实验是指在Linux操作系统中编写和测试字符设备驱动程序的过程。字符设备驱动程序负责与字符设备进行交互,包括输入输出数据、控制设备和处理设备的状态等。 在进行Linux字符设备驱动实验之前,首先需要了解字符设备字符设备驱动的基本概念及其工作原理。字符设备是指以字符为单位进行输入输出的设备,如串口、打印机等。字符设备驱动是指将操作系统与字符设备进行交互的程序。 在实验中,我们通常需要编写一个字符设备驱动程序,包括初始化设备、读写数据、控制设备等功能。首先,我们需要定义字符设备驱动的数据结构,包括设备号、驱动程序打开、关闭等函数的实现。然后,我们需要实现字符设备驱动的读写函数来实现数据的输入输出。最后,我们可以进行一些附加功能的实现,如控制设备的状态、处理中断等。 在实验过程中,我们需要使用Linux内核提供的字符设备接口来进行字符设备驱动的编写和测试。可以使用一些工具和命令来加载和测试字符设备驱动程序,如insmod、rmmod等。通过这些工具和命令,我们可以加载和卸载字符设备驱动程序,并在用户空间进行数据的读写操作,来测试字符设备驱动的功能和性能。 Linux字符设备驱动实验可以帮助我们深入了解字符设备字符设备驱动的工作原理,并学习Linux内核的开发和调试技术。通过实验,我们可以更好地理解操作系统和驱动程序之间的关系,提高我们在Linux系统开发和嵌入式系统开发中的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值