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
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值