字符设备驱动ioctl实现用户层内核层通信

测试代码实现
memdev.h
#ifndef _MEMDEV_H_
#define _MEMDEV_H_
#include<linux/ioctl.h>
#ifndef MEMDEV_MAJOR
#define MEMDEV_MAJOR 0
#endif
#ifndef MEMDEV_NR_DEVS
#define MEMDEV_NR_DEVS 2
#endif
#ifndef MEMDEV_SIZE
#define MEMDEV_SIZE 4096
#endif
struct mem_dev
{
    char *data;
    unsigned long size;
};
#define MEMDEV_IOC_MAGIC ‘k‘
#define MEMDEV_IOCPRINT _IO(MEMDEV_IOC_MAGIC,0)
#define MEMDEV_IOCGETDATA _IOR(MEMDEV_IOC_MAGIC,1,int)
#define MEMDEV_IOC_MAXNR 3
#endif
memdev.c
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/types.h>
#include<linux/fs.h>
#include<linux/errno.h>
#include<linux/mm.h>
#include<linux/sched.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include<asm/io.h>
#include<asm/system.h>
#include<asm/uaccess.h>
#include "memdev.h"
static int mem_major = MEMDEV_MAJOR;
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;
    int num = MINOR(inode->i_rdev);
    if(num >= MEMDEV_NR_DEVS)
        return -ENODEV;
    dev = &mem_devp[num];
    filp->private_data = dev;
    return 0;
}
int mem_release(struct inode *inode,struct file *filp)
{
    return 0;
}
long memdev_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
    int err = 0;
    int ret = 0;
    int ioarg = 0;
    printk("kernel cmd is : %ld\n",cmd);
    switch(cmd)
    {
    case MEMDEV_IOCPRINT:
        printk("CMD MEMDEV_IOCPRINT DONE\n\n");
        break;
    case MEMDEV_IOCGETDATA:
        ioarg = 1101;
        if(copy_to_user((int *)arg,&ioarg,sizeof(int)))
            return -EFAULT;
        break;
    default:
        return -EINVAL;
    }
    return ret;
}
static const struct file_operations mem_fops =
{
    .owner = THIS_MODULE,
    .open = mem_open,
    .release = mem_release,
    .unlocked_ioctl = memdev_ioctl,
};
static int memdev_init(void)
{
    int result;
    int i;
    dev_t devno = MKDEV(mem_major,0);
    if (mem_major)
    {
        result = register_chrdev_region(devno,2,"memdev");
        printk("first mem_major is : %ld\n",mem_major);
    }
    else
    {
        result = alloc_chrdev_region(&devno,0,2,"memdev");
        mem_major = MAJOR(devno);
        printk("second mem_major is : %ld\n",mem_major);
    }
    if(result < 0)
        return result;
    cdev_init(&cdev,&mem_fops);
    cdev.owner = THIS_MODULE;
    cdev.ops = &mem_fops;
    cdev_add(&cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS);
    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);
    }
    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_LICENSE("GPL");
module_init(memdev_init);
module_exit(memdev_exit);
Makefile
obj-m += memdev.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
all:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
app-ioctl.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include "memdev.h"
int main(void)
{
    int fd = 0;
    int cmd;
    int arg = 0;
    char Buf[4096];

    fd = open("/dev/memdev0",O_RDWR);
    if(fd < 0)
    {
        printf("Open Dev Mem Erro\n");
        return -1;
    }

    printf("call memdev_iocprint\n");
    cmd = MEMDEV_IOCPRINT;
    printf("userspace cmd is : %ld\n",cmd);
    if(ioctl(fd,cmd,&arg) < 0)
    {
        printf("call cmd MEMDEV_IOCPRINT fail\n");
        return -1;
    }
    printf("call MEMDEV_IOCGETDATA\n");
    cmd = MEMDEV_IOCGETDATA;
    if(ioctl(fd,cmd,&arg) < 0)
    {
        printf("call cmd MEMDEV_IOCGETDATA fail\n");
        return -1;
    }
    printf("in user space MEMDEV_IOCGETDATA get data is %d\n\n",arg);
    close(fd);
    return 0;
}

编译memdev,对应的设备驱动

make

insmod memdev.ko

在dmesg中会有输出结果init,在/proc/devices中生成对应的设备驱动号249

创建设备节点

cat /proc/devices中生成的memdev节点编号249

mknod /dev/memdev0 c 249 0创建设备节点,并将对应的设备节点与设备驱动号进行绑定。当打开该设备节点进行后续操作时,将会由设备驱动文件进行具体实现

编译app ioctl测试文件

gcc -o app-ioctl app-ioctl.c

./app-ioctl

正常执行结果会显示,dmesg也会显示内核结果

时间: 2024-10-03 05:03:02

字符设备驱动ioctl实现用户层内核层通信的相关文章

linux 高级字符设备驱动 ioctl操作介绍 例程分析实现【转】

转自:http://my.oschina.net/u/274829/blog/285014 1,ioctl介绍 ioctl控制设备读写数据以及关闭等. 用户空间函数原型:int ioctl(int fd,unsinged long cmd,...) fd-文件描述符 cmd-对设备的发出的控制命令 ...表示这是一个可选的参数,存在与否依赖于cmd,如cmd为修改波特率,那么....就表示波特率的值.如果cmd表示关闭,则不需要参数 内核函数原型 file_operations结构体里面long

linux设备驱动第三篇:写一个简单的字符设备驱动

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: [plain] vie

linux设备驱动第三篇:如何写一个简单的字符设备驱动?

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: [email prot

linux设备驱动第三篇:如何实现简单的字符设备驱动

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动 都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: [email pro

linux设备驱动第三篇:如何实现一个简单的字符设备驱动

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: ? 1 2 3 4 5

Linux内核分析(五)----字符设备驱动实现

原文:Linux内核分析(五)----字符设备驱动实现 Linux内核分析(五) 昨天我们对linux内核的子系统进行简单的认识,今天我们正式进入驱动的开发,我们今后的学习为了避免大家没有硬件的缺陷,我们都会以虚拟的设备为例进行学习,所以大家不必害怕没有硬件的问题. 今天我们会分析到以下内容: 1.      字符设备驱动基础 2.      简单字符设备驱动实现 3.      驱动测试 l  字符设备基础 1.       字符设备描述结构 在linux2.6内核中,使用cdev结构体描述一

从Linux内核LED驱动来理解字符设备驱动开发流程

目录 博客说明 开发环境 1. Linux字符设备驱动的组成 1.1 字符设备驱动模块加载与卸载函数 1.2 字符设备驱动的file_operations 结构体中的成员函数 2. 字符设备驱动--设备号注册卸载 2.1 设备号注册 2.2 设备号注销 3. 字符设备驱动--文件操作 参考资料 示例代码 @(从Linux内核LED驱动来理解字符设备驱动开发流程) 博客说明 撰写日期 2018.12.08 完稿日期 2019.10.06 最近维护 暂无 本文作者 multimicro 联系方式 [

Linux字符设备驱动剖析

一.先看看设备应用程序 1.很简单,open设备文件,read.write.ioctl,最后close退出.如下: intmain(int argc ,char *argv[]){ unsigned char val[1] = 1; int fd =open("/dev/LED",O_RDWR);//打开设备 write(fd,val,1);//写入设备,这里代表LED全亮 close(fd);//关闭设备 return 0; } 二./dev目录与文件系统 2./dev是根文件系统下

字符设备驱动、平台设备驱动、设备驱动模型、sysfs的关系

Linux驱动开发的童鞋们来膜拜吧:-)  学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析.对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给