memdev.ko --- 字符设备驱动程序

linux驱动内核裁剪及烧录 c裁剪在menuconfig中选择 阅读详情

1. memdev.c

#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <asm/system.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

#include "memdev.h"

static int mem_major = MEMDEV_MAJOR;
static int mem_minor = MEMDEV_MINOR;

module_param(mem_major, int, S_IRUGO);

struct mem_dev *mem_devp;  //声明全局结构体指针
struct cdev cdev; //静态定义的结构,就不需要分配内存空间

int mem_open(struct inode *inode, struct file *filp)
{
    struct mem_dev *dev;
    printk(KERN_INFO "xxha: --- mem_open\n");

    int num = MINOR(inode -> i_rdev); //num(即次设备号)表示有多少个同类设备。

    if (num >= MEMDEV_NR_DEVS)
        return -ENODEV;
    dev = &mem_devp[num];  //指定一个设备

    filp->private_data = dev; //将设备内容赋给 filp->private_data, 供read, write 使用。

    return 0;
}

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

static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) //这函数的参数不能变,只有函数名可
以变
                                                                                        //__user 表示用户空间
{
    unsigned long p = *ppos;
    unsigned int count = size;
    int ret = 0;
    struct mem_dev *dev = filp->private_data; //获得open中赋值的filp->private_data设备结构体指针

    if (p >= MEMDEV_SIZE)  //判断读位置是否有效,即是否在设备内存内部
        return 0;
    if (count > MEMDEV_SIZE - p) //需要读的长度,如果大于可以读的长度
        count = MEMDEV_SIZE -p;

    if (copy_to_user(buf, (void*)(dev->data + p), count)) { //读设备内容到 buf 缓存。
                                                            //从 (void*)(dev->data + p) 地址开始读取
                                                            //读取count个字节

        ret = -EFAULT;  //若copy_to_user()出错,返回-EFAULT;
    } else {            //若copy_to_user()没有出错;
        *ppos += count;   //更改读指针的位置
        ret = count;      //返回count,读取的字节数
        printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
    }
    return ret;
}

static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
    unsigned long p = *ppos;
    unsigned int count = size;
    int ret = 0;
    struct mem_dev *dev = filp->private_data;  //获得设备结构体指针

    if (p >= MEMDEV_SIZE)
        return 0;
    if (count > MEMDEV_SIZE - p)
        count = MEMDEV_SIZE - p;

    if (copy_from_user(dev->data + p, buf, count))  //把用户空间地址buf中的数据,写入dev->data + p 内核空间地址。
                                                    //写入count个字节
        ret = -EFAULT;     //若出错,返回错误
    else {                 //若copy_from_user()没出错,则返回0,也就是运行else部分。
        *ppos += count;    //调整当前指针。
        ret = count;       //返回写入的字节数。
        printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
    }
    return ret;
}

static loff_t mem_llseek(struct file *filp, loff_t offset, int whence) //whence --- 从哪开始偏移
                                                                       //offset --- 偏移量
{
    loff_t newpos;

    switch(whence){
        case 0:  //SEEK_SET --- 头位置
            newpos = offset;
            break;
        case 1:  //SEEK_CUR --- 当前位置
            newpos = filp->f_pos + offset;   //filp->f_pos --- 文件描述符中当前文件指针位置
            break;
        case 2:  //SEEK_END --- 尾位置
            newpos = MEMDEV_SIZE -1 + offset;
            break;
        default: //cannot happen
            return -EINVAL;
    }
    if ((newpos < 0) || (newpos > MEMDEV_SIZE))
        return -EINVAL;

    filp->f_pos = newpos; //改变文件的读写位置
    return newpos;
}

static const struct file_operations mem_fops =
{
    .owner = THIS_MODULE,
    .llseek = mem_llseek,
    .read = mem_read,
    .write = mem_write,
    .open = mem_open,
    .release = mem_release,
};

//加载设备驱动
static int memdev_init(void)
{
    int result;
    int i;

    printk(KERN_INFO "xxha: ---  memdev_init\n");
    dev_t devno = MKDEV(mem_major, 0); //利用主设备号和次设备号,获得设备号

    if (mem_major){
        printk(KERN_INFO "xxha: ---  mem_major != 0, static cahr devno\n");
        printk(KERN_INFO "xxha: ---  devno = %d\n", devno);
        result = register_chrdev_region(devno, 2, "memdev"); //静态分配设备号, 一共分配2个设备
    } else {
        printk(KERN_INFO "xxha: ---  mem_major = 0, alloc char devno\n");
        result = alloc_chrdev_region(&devno, 0, 2, "memdev"); //如果mem_major = 0, 则使用动态分配设备号,
                                                              //获得设备号devno,也是2个设备,次设备号从0开始。
        printk(KERN_INFO "xxha: ---  devno = %d\n", devno);
        mem_major = MAJOR(devno);
        mem_minor = MINOR(devno);
        printk(KERN_INFO "xxha: ---  dev major = %d\n", mem_major);
        printk(KERN_INFO "xxha: ---  dev minor = %d\n", mem_minor);
    }

    if(result < 0){
        printk(KERN_INFO "xxha: --- dev no alloc failed\n");
        return result;
    }

    printk(KERN_INFO "xxha: ---  cdev_init\n");
    cdev_init(&cdev, &mem_fops);  //初始化cdev
    cdev.owner = THIS_MODULE;
    cdev.ops = &mem_fops;

    printk(KERN_INFO "xxha: ---  cdev_add\n");
//  result = cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);  //注册cdev驱动程序进入内核。
    result = cdev_add(&cdev, devno, MEMDEV_NR_DEVS);  //注册cdev驱动程序进入内核。
    if(result){
        printk(KERN_INFO "xxha: --- cdev_add failed\n");
        return result;
    }

    //为设备的描述结构mem_devp分配内存
    mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
    if (!mem_devp){
        result = - ENOMEM;
        goto fail_malloc;
    }
    memset(mem_devp, 0, sizeof(struct mem_dev));

    //为设备分配内存
    for(i = 0; i < MEMDEV_NR_DEVS; i++){
        mem_devp[i].size = MEMDEV_SIZE; //内存设备大小
        mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL); //为设备分配内存
        memset(mem_devp[i].data, 0, MEMDEV_SIZE); //清空设备内存
    }

    printk(KERN_INFO "xxha: ---  module_init finished\n");
    return 0;

fail_malloc:
    unregister_chrdev_region(devno, 1);
    return result;
}

//卸载模块
static void memdev_exit(void)
{
    cdev_del(&cdev); //从内核中注消字符设备
    kfree(mem_devp); //释放设备结构体内存
    unregister_chrdev_region(MKDEV(mem_major, 0), 2); //释放设备号

}

MODULE_AUTHOR("Lamdoc Xu");
MODULE_LICENSE("GPL");

module_init(memdev_init);
module_exit(memdev_exit);

2. memdev.h 头文件

#ifndef _MEMDEV_H_
#define _MEMDEV_H_

#ifndef MEMDEV_MAJOR
#define MEMDEV_MAJOR 0
#endif

#ifndef MEMDEV_MINOR
#define MEMDEV_MINOR 0
#endif

#ifndef MEMDEV_NR_DEVS
#define MEMDEV_NR_DEVS 1
#endif

#ifndef MEMDEV_SIZE
#define MEMDEV_SIZE 4096
#endif

//mem设备描述结构体
struct mem_dev {
    char *data;  //内存地址
    unsigned long size; //内存设备大小
};

#endif  //_MEMDEV_H_

3. Makefile, 用来make 成 .ko 文件,编译完成后,需要chmod 777 memdev.ko, 才能用来 sudo insmod memdev.ko,加载驱动。

KERNELDIR ?= /lib/modules/3.0.0-12-generic/build/
PWD := $(shell pwd)
obj-m := memdev.o
default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
    rm *.o *.ko *.mod.c *.symvers *.order

4. app-mem.c  //应用程序,测试驱动的应用程序

#include <stdio.h>


int main()
{
    FILE *fp0 = NULL;
    char Buf[4096];

    strcpy(Buf, "Mem is char dev!");
    printf("Buf: %s\n", Buf);

    fp0 = fopen("/dev/memdev0", "r+");
    if (fp0 == NULL)
    {
        printf("Open Memdev0 Error!\n");
        return -1;
    }

    fwrite(Buf, sizeof(Buf), 1, fp0);

    fseek(fp0, 0 , SEEK_SET);

    strcpy(Buf, "Buf is NULL!");
    printf("BUF seek : %s\n", Buf);

    fread(Buf, sizeof(Buf), 1, fp0);
    printf("BUF read: %s\n", Buf);

    return 0;
}

linux下的字符设备驱动 Linux字符设备驱动程序的一个简单示例 一.开发环境: 主  机:VMWare--Fedora 9 开发板:友善之臂mini2440--256MB Nandflash  编译器:arm-linux-gcc-4.3.2   二.驱动源码: 该源码很浅显易懂,非常适合初学者。 memdev.h #ifndef _MEMDEV_H_ #define _MEMDEV_H_ 阅读详情

相关推荐

自动化测试-自愈技术

随着人工智能的发展,作为一名软件测试工程师,相信大家都会思考如何把这一前沿技术引入到我们的自动化测试当中,想一万遍不如做一遍。,传递当前页面状态,获取之前成功的定位器路径,比较它们,并生成修复的定位器列表。如果修复成功,我们可以使用 Healenium Idea 插件更新我们的自动化测试代码:插件使用修复定位器寻找修复和更新测试代码。的旧定位器去定位按钮的时候,脚本就会报错,提示 “NoSuchElement”的错误异常。现在,我们假设开发人员变更了应用程序的UI界面,改变了这个按钮的id属性,从。

qq_58223744的博客 2660

模块插入错误 insmod: can't insert 'memdev.ko': Device or resource busy

insmod: can't insert 'dev.ko': Device or resource busy 图1  模块Device or resource busy提示 什么chmod,chown都用过了,6410板子也reboot过,ftp也by后从新连接过,还是同样的结果。最后求助google(最近好上一点,不会点一两个链接就会出现链接不上),原来是设备号冲

dxmcu的专栏 8877

SRAM ECC原理与应用:从汉明码到高可靠嵌入式系统设计

在嵌入式系统与高可靠性计算领域,内存数据完整性是系统稳定运行的基石。软错误(Soft Error)由宇宙射线或芯片内部粒子引发,可能导致存储单元发生位翻转,进而引发程序跑飞或数据损坏。为应对这一物理层挑战,错误校验与纠正(ECC)技术应运而生,其核心原理基于扩展汉明码,通过增加校验位实现单错误纠正、双错误检测(SECDED)能力。这项技术通过硬件透明纠错,在提升系统可靠性的同时,几乎不影响访问性能。在汽车电子、工业控制及航空航天等对安全性要求极高的场景中,ECC已成为保障长期稳定运行的关键硬件机制。本文聚焦

weixin_28728265的博客 529

LINUX字符设备驱动程序实例(scull)

摘自:http://blog.chinaunix.net/uid-11829250-id-337300.html 【1.系统环境】 该驱动程序在UBUNTU10.04LTS编译通过,系统内核为linux-2.6.32-24(可使用uname -r 命令来查看当前内核的版本号) 由于安装UBUNTU10.04LTS时,没有安装LINUX内核源码,因此需要在www.kernel.org下载LINU

chinaclock的专栏 1201

VINS-Fusion实战:从零搭建无人机视觉SLAM系统(附ROS配置全流程)

本文详细介绍了如何从零开始为无人机搭建基于VINS-Fusion的视觉SLAM系统。内容涵盖硬件选型(重点推荐双目相机与IMU搭配)、ROS环境配置、传感器标定、核心参数调优以及实际飞行测试与问题排解全流程,旨在帮助开发者实现稳定、精确的无人机自主定位与导航。

wasm7browser的博客 214

【异常】Openclaw Gateway进程异常停止问题分析与解决方案

本文分析了Gateway服务异常停止的问题,提出了三种解决方案。核心问题是缺乏进程守护和自动恢复机制,导致服务崩溃后无法自行重启。推荐方案是使用PM2进程管理工具(方案1),提供进程监控、自动重启和开机自启功能。替代方案包括自定义守护脚本(方案2)和supervisord管理(方案3)。这些方案都能有效解决当前服务脆弱性问题,显著提升服务可用性,其中PM2方案成熟度高、配置简单,是首选解决方案。实施后可将服务从人工干预转变为自动恢复,确保业务连续性。

奶爸的编程之路,也就一周冷个三天 457

字符设备驱动程序(write & read)——开发步骤(5)

运用应用程序调用自己编写的字符设备驱动 将字符设备驱动程序make,编译一下 导入模块并查看模块 sudo insmod memdev.ko sudo lsmod 创建设备文件memdev0并查看,在/dev目录下 cd /dev sudo mknod 设备文件名 c(字符设备驱动程序) 主设备号 次设备号 查看主设备号 cat /proc/devices 创建设备文件 sudo mknod memdev0 c 241 0 编译mem_app.c文件,生成可执行文件a

Solong 962

CAN轴控制流【6041,6040】

【代码】CAN轴控制流【6041,6040】

cfqq1989的博客 1782

memdev字符设备驱动mem_llseek文件定位函数出错

错误:     自己编写了memdev字符设备驱动程序,加载驱动模块后,执行应用程序./app_mem程序来测试驱动,出现了如下问题。                向设备文件中写入数据正常,但是当要从设备文件中读出“写入的数据时”,提示buf is null没有数据   分析:     1、printk函数打印的提示信息“written 4096 bytes(s) from 0”,

马道人生 1494

使用再生龙备份还原liunx系统(精确每一步)

再生龙镜像可自行到官网下载(ISO/ZIP格式均可),然后使用tuxboot烧录工具制作启动盘,另外准备一个U盘用来存储备份的镜像文件,即再生龙盘和存储盘是两个分开的。当然也可以用分区工具把同一个硬盘分区来使用,比较方便,先学会基本的吧,只是告诉有个捷径,省个U盘。

米可的博客! 8366

29.Labview界面设计 --- (下篇)自定义控件库、界面布局与外观设计

1.自定义控件外观(自定义控件)1.1 自定义外观库1.2 手动自定义控件外观2. 前面板控件布局方式(控件排布)2.1 模块化控制布局方式2.2 数据采集布局方式3. 前面板外观优化项(背景设计)3.1 前面板背景设计3.2 前面板窗口整理本节第一部分教大家安装一种可以直接用的自定义控件库,第二部分教大家如何自己设计控件并保存调用。

关注我,更多技术问题欢迎私聊~ 4781

字符设备驱动代码完整分析

1.编译、安装驱动程序 linux系统中,驱动程序通常采用内核模块的程序结构来进行编码。因此编译、安装驱动程序实质是编译、安装内核模块memdev.c #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/uaccess.h> int

夜黯竹亭风的博客 3044

手把手教你学Simulink--基于Simulink的高增益DC-DC变换器仿真建模

特点高电压增益:可以在不使用变压器的情况下实现较大的电压升压比。适用于低电压源:如太阳能电池板、燃料电池等提供的低压直流电源。效率问题:设计时需特别注意提高效率,减少能量损失。挑战电路复杂性:通常涉及多个电感和电容,以及复杂的开关模式。元件选择:合适的元件参数对于达到理想性能至关重要。控制策略:确保高效稳定运行的同时,适应负载变化。首先明确要模拟的任务内容。实现特定的电压增益比(例如从24V升至380V)。根据预期的输入输出电压确定合适的电路拓扑和元件值。

MHD0815的博客 173

Android实现简单字符驱动程序及测试

这看来老罗的Androidzhilv

Javen.tang的专栏 1267

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

17、字符设备控制技术

字符设备控制技术 前面的学习,我们学习了驱动程序,实现程序的读写功能。现在设备还有一项更重要的功能--控制。 控制设备的函数:ioctl。 Cmd:参数是我们发送的命令,例如重启。 第三个参数:是依赖第二个,例如我们要修改波特率的值,我们就会在第三个参数传上波特率的值。当第二个不需要参数,就是空值。 前面知道,当我们系统调用read函数的时候,系统...

ashe9657的博客 132

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

字符设备驱动程序的使用

1.编译、安装驱动linux系统中,驱动程序通常采用内核模块的程序结构来进行编码,因此,编译、安装一个驱动程序,其实质就是编译、安装一个内核模块。将文件memdev.c makefile 放入虚拟机中,make 得到.ko文件cp .ko rootfs启动开发板 insmod *.ko2.创建设备文件通过字符设备文件,应用程序可以使用相应的字符设备驱动程序来控制字符设备。创建字符设备文件...

weixin_30763455的博客 140

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

第四季-专题10-字符设备驱动模型

专题10-字符设备驱动模型 第1课-使用字符驱动程序 编译/安装驱动 在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码。因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块。 例子:字符设备驱动程序 编写makefile文件: obj-m := memdev.o KDIR := /home/S5-driver/lesson7/...

weixin_38168760的博客 156

[国嵌攻略][112][使用字符设备驱动]

编译/安装驱动程序 在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码。因此编译/安装一个驱动程序,其实就是编译/安装一个内核模块。 示例: make insmod memdev.ko 创建设备文件 应用程序->设备文件->驱动程序 通过字符设备文件,应用程序可以使用相应的字符设备驱动程序来控制字符设备。创建字符设备文件的方法一般有两种: 1.使用m...

weixin_30305735的博客 63

字符设备驱动(一)

1.字符设备驱动基础知识图解链接:Linux 设备驱动之字符设备(一) http://blog.chinaunix.net/uid-26833883-id-4369060.html Linux 设备驱动之字符设备(二) http://blog.chinaunix.net/uid-26833883-id-4369117.html Linux 设备驱动之字符设备(三) http://blog.

岁月不中留,可堪回首否? 450

Linux字符设备驱动实验代码

Linux字符设备驱动实验代码 去发现同类优质开源项目:https://gitcode.com/ 简介 本仓库包含了一个简单的Linux字符设备驱动程序及其测试代码。通过这个实验,您可以了解Linux操作系统如何管理字符设备,以及如何编写和测试字符设备驱动程序。 本资源整合了网上众多不完整内容,为您提供了一个完整的实验环境。其中包括以下文件:memdev.c、memdev.h、app-mem.c和...

gitblog_06746的博客 355

linux 字符运行程序设计,Linux字符设备驱动编程

加入内核源码树外① 建立两个文件scull.c,scull.h,以及Makefile文件Makefile文件② 用make进行编译,生成scull.ko驱动程序模块③ 把scull.ko模块加载到内核,并且查看scull.ko驱动④ 查看当前设备使用的主设备号,主设备号为260⑤ 首先应该在/dev/目录下创建与该驱动程序相对应的文件节点,查看创建好的驱动程序节点文件并修改scull的权限。⑥ 编...

weixin_33037313的博客 127

linux字符设备

先查看自己的内核版本 #uname-r

qq413187589的专栏 784

字符设备控制技术

字符设备控制技术1.设备控制理论1.1作用1.2应用程序接口1.3设备驱动方法2.设备控制实现2.1定义命令2.2实现设备方法3实现字符设备控制1.1.控制理论作用大部分驱动程序除了需要提供读写设备的能力以外,还需要具备控制设备的能力。1.2应用程序接口在用户空间,使用ioctl系统调用来控制设备,原型如下: int ioctl(int fd,unsigned long cmd,…) fd:要控

夜黯竹亭风的博客 490

嵌入式linux插入内核模块Error: could not insert module xxx.ko: Device or resource busy处理

设备号冲突导致 处理方法: 1.输入$cat /proc/devices 查看驱动的设备号 2.选择一个不冲突的设备号进行编译 参考文献: 1.http://blog.csdn.net/zzc_19/article/details/8648332 为了防止网页无法访问,现将引用文献拷贝至此 最近看了几集国嵌的关于字符设备驱动视频教程,自己跟着视频上面敲代码。字符设备驱动,用...

weixin_30895603的博客 1200

Linux驱动开发入门:从Hello World到字符设备驱动实战

Linux内核模块是操作系统与硬件交互的核心组件,其本质是一种可动态加载到内核空间执行的代码。理解其工作原理,关键在于掌握内核模块的编译、加载机制以及内核与用户空间的安全数据交换。这项技术对于嵌入式系统、物联网设备开发具有极高的价值,它使得开发者能够为定制硬件编写专用接口,实现高效、稳定的底层控制。在具体应用场景中,字符设备驱动是最常见的形式之一,它通过文件操作接口(如open、read、write)为用户程序提供访问硬件的通道。本文聚焦于Linux驱动开发实践,通过一个完整的“内存字符设备”驱动项目,详细

weixin_33908217的博客 453
上一篇: 错误: 初始值设定项里有未知的字段‘ioctl’
下一篇: IS_ERR() 与 PTR_ERR()
lamdoc
博客等级 码龄18年 155粉丝 655原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值