linux实验 模块与设备驱动

(1)首先新建并编写了字符驱动设备chardev.c文件,文件代码如下:

/*
* 创建一个字符设备(读写)
*/
/* 必要的头文件,内核模块标准头文件 */
#include<linux/init.h>
#include<linux/kernel.h> /*内核工作*/
#include<linux/slab.h>/**/
#include<linux/vmalloc.h>
#include<linux/module.h> /*明确指定是模块*/
#include<linux/moduleparam.h>
/*对于字符设备*/
#include<linux/fs.h> /*字符设备定义*/
#include<linux/cdev.h>
#include<asm/system.h>
#include<asm/uaccess.h>
 
MODULE_AUTHOR("author");
MODULE_LICENSE("GPL");
 
struct char_dev *char_device;
int dev_major=0;
int dev_minor=0;
 
module_param(dev_major,int,S_IRUGO);
module_param(dev_minor,int,S_IRUGO);
 
//设备存储区的指针
char *p_mem=NULL;
//设备存储区的大小
long len=1000;
 
 
//表示设备的数据结构
struct char_dev
{
         char * data; // 模块中的数据
         long len; // 数据长度
         struct cdev cdev; //Linux 字符设备结构,由系统定义 
};
 
 
int char_open(struct inode *inode,struct file *filp)
{
         struct char_dev *dev;
         //从inode 获取设备结构体
         dev=container_of(inode->i_cdev,struct char_dev,cdev);
         //赋值给file 结构体
         filp->private_data=dev;
         return 0;
}
 
 
//读时将调用的函数
static ssize_t char_read(struct file * filp, char __user *buf, size_t count, loff_t *offset)
{
             char * buffer = (char *)filp->private_data;   
      if(copy_to_user(buf, buffer, count))
             {
                 printk("copy_to_user error/n");
                 return -EFAULT;
             }
         printk("You are using the read function!");
             return count ;
}
 
 
//参数定义和char_read 类似
static ssize_t char_write(struct file * filp, const char __user *buf, size_t count, loff_t *offset)
{
     char * buffer = (char *)filp->private_data;
             //printk("new  %p/n", buffer);
             if(copy_from_user(buffer, buf, count))
             {
                   printk("copy_from_user error/n");
                 return -EFAULT;
             }
             return count;
}
 
 
//读写完毕后调用的函数
int char_release(struct inode *inode,struct file *filp)
{
         return 0;
}
 
 
//定义设备节点文件的操作
static struct file_operations char_ops={
.owner = THIS_MODULE,
.open = char_open,
.read = char_read,
.write = char_write,
.release =char_release
};
 
 
//设备初始化时调用的函数,用于获取存储区内存空间
int memory_init(void)
{
         p_mem=vmalloc(len*sizeof(char));
         if(!p_mem)
         {
                   printk(KERN_ALERT "error-memory_init/n");
                   return -1;
         }
         return 1;
}
 
 
//设备初始化
static int dev_init(void)
{
         int result=0;
         dev_t dev=0;
         dev_t devno=0;
         int err=0;
        
         //获取存储区
         //如果定义了主设备号
         if(dev_major)
         {
                   //则按照定义的设备号注册设备
                   dev=MKDEV(dev_major,dev_minor);
                   result=register_chrdev_region(dev,1,"char_dev");
         }else{
                   //否则分配新的设备号
                   result=alloc_chrdev_region(&dev,dev_minor,1,"char_dev");
                   dev_major=MAJOR(dev);
         }
         if(result < 0)
         {
                   printk(KERN_ALERT "can't get major %d/n",dev_major);
                   return result;
         }
         //返回主设备号
         printk("the dev_major %d/n",dev_major);
         //获取全局char_dev 结构体
         char_device = kmalloc(sizeof(struct char_dev),GFP_KERNEL);
         if(!char_device)
         {
                   result=-ENOMEM;
                   return result;
         }
         memset(char_device,0,sizeof(struct char_dev));
         //使用定义了的文件操作char_ops 初始化cdev
         cdev_init(&char_device->cdev, &char_ops);
         char_device->cdev.owner = THIS_MODULE;
         char_device->cdev.ops = &char_ops;
         //使用后区的设备号注册设备
         devno=MKDEV(dev_major,dev_minor);
         //添加此字符设备到系统
         err=cdev_add(&char_device->cdev,devno,1);
         char_device->data=p_mem;
         char_device->len=len;
         return 0;
}
 
 
//设备被移出时调用
static void dev_exit(void)
{
         dev_t devno=0;
 
         devno = MKDEV(dev_major,dev_minor);
         cdev_del(&char_device->cdev);
         kfree(char_device);
         unregister_chrdev_region(devno,1);
}
 
 
//注册模块初始化和卸载函数
module_init(dev_init);
module_exit(dev_exit);

2.写Makefile文件

obj-m := chardev.o

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)

all:
	$(MAKE) -C $(KERNELDIR) M=$(PWD)

(3)使用make 命令,生成驱动程序chardev.ko

(4)用root 挂载设备:

    insmod chardev.ko

(5)在文件系统为其创建一个代表节点(建立设备文件)

#dmesg 寻找主设备号,找到后挂载,设备号要相同

创建节点命令格式如下:

mknod /dev/<dev_name><type><major_number><minor_number>

例如(若主设备号为249)

   mknod mychardev0 c 250 0

(6)修改属性:

   chmod 666 mychardev*


(7) test.cpp内容

#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
 
int main()
{
         int fd;
         char buffer_write[20] = "Hello World!";
         char buffer_read[20] = "Hello China!";
         fd=open("mychardev0", O_RDWR);
 
         if(fd < 0)
         {
                   cout<<"open dev error!"<<endl;
                   exit(fd);
         }
 
         //向指定设备写入用户输入文本
         cout<<"Please input the text:"<<endl;
         cin>>buffer_write;
         write(fd, buffer_write, 20);
 
         //输出设备中的内容
         read(fd, buffer_read, 20);
         cout<<"指定设备中的内容为:"<<endl<<buffer_read<<endl;
 
         close(fd);
        
         return 0;
}
权限不够加sudo
g++ test.cpp -o test

./test即可运行

rmmod mychardev0

dmesg


【终于搞定了这个实验】




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值