2023.2.8---ioctl函数

该示例展示了如何通过用户空间的应用程序使用ioctl函数与内核模块交互,控制GPIO端口来开关6盏灯、蜂鸣器、风扇和马达。内核模块实现了设备驱动,包括初始化GPIO,以及处理来自用户空间的打开、关闭和状态切换请求。

通过ioctl函数实现6盏灯的亮灭,蜂鸣器、风扇、马达的开关

应用层代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "device.h"

int main(int argc,const char * argv[])
{
    int fd=open("/dev/mydevice0",O_RDONLY);
    if(fd<0)
    {
        perror("open");
        return -1;
    }
    int device,status;
    while (1)
    {
        printf("1-(top_led1),2-(top_led2),3-(top_led3)\n");
        printf("4-(bot_led1),5-(bot_led2),6-(bot_led3)\n");
        printf("7-(beep),8-(fan),9-(motor)\n");
        printf("请选择要操作的设备>>");
        scanf("%d",&device);
        printf("请选择该设备的状态:1-(开),0-(关)>>");
        scanf("%d",&status);
        switch (device)
        {
        case 1:
            if(status == 1){
                ioctl(fd,DEVICE_ON,&device);
            }else{
                ioctl(fd,DEVICE_OFF,&device);
            }
            break;
        case 2:
            if(status == 1){
                ioctl(fd,DEVICE_ON,&device);
            }else{
                ioctl(fd,DEVICE_OFF,&device);
            }
            break;
        case 3:
            if(status == 1){
                ioctl(fd,DEVICE_ON,&device);
            }else{
                ioctl(fd,DEVICE_OFF,&device);
            }
            break;
        case 4:
            if(status == 1){
                ioctl(fd,DEVICE_ON,&device);
            }else{
                ioctl(fd,DEVICE_OFF,&device);
            }
            break;
        case 5:
            if(status == 1){
                ioctl(fd,DEVICE_ON,&device);
            }else{
                ioctl(fd,DEVICE_OFF,&device);
            }
            break;
        case 6:
            if(status == 1){
                ioctl(fd,DEVICE_ON,&device);
            }else{
                ioctl(fd,DEVICE_OFF,&device);
            }
            break;
        case 7:
            if(status == 1){
                ioctl(fd,DEVICE_ON,&device);
            }else{
                ioctl(fd,DEVICE_OFF,&device);
            }
            break;
        case 8:
            if(status == 1){
                ioctl(fd,DEVICE_ON,&device);
            }else{
                ioctl(fd,DEVICE_OFF,&device);
            }
            break;
        case 9:
            if(status == 1){
                ioctl(fd,DEVICE_ON,&device);
            }else{
                ioctl(fd,DEVICE_OFF,&device);
            }
            break;
        default:
            break;
        }
    }
    
    return 0;
}

 内核层代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include "device.h"

struct cdev *cdev;
int res,i;
int major=0;
int minor=0;
dev_t devnum;
struct class *cls;
struct device *dev;
gpio_t *top_led1;
gpio_t *top_led2;
gpio_t *top_led3;
gpio_t *bot_led1;
gpio_t *bot_led2;
gpio_t *bot_led3;
gpio_t *beep;
gpio_t *fan;
gpio_t *motor;
unsigned int *rcc_ahb4;
unsigned int *rcc_ahb5;
unsigned int *rcc_apb2;

//定义自己的open,read,write,close,ioctl函数
int my_open(struct inode *inode,struct file *file)
{
    return 0;
}
ssize_t my_read(struct file *file,char *user,size_t size,loff_t *loff)
{
    return 0;
}
ssize_t my_write(struct file *file,const char *user,size_t size,loff_t *loff)
{
    return 0;
}
long my_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
    int device;
    //接收来自于用户空间的数据
    res=copy_from_user(&device,(void *)arg,sizeof(int));
    switch (device)
    {
    case 1:
        if(cmd==DEVICE_ON){
            top_led1->ODR |= (1<<10);
        }else{
            top_led1->ODR &= (~(1<<10));
        }
        break;
    case 2:
        if(cmd==DEVICE_ON){
            top_led2->ODR |= (1<<10);
        }else{
            top_led2->ODR &= (~(1<<10));
        }
        break;
    case 3:
        if(cmd==DEVICE_ON){
            top_led3->ODR |= (1<<8);
        }else{
            top_led3->ODR &= (~(1<<8));
        }
        break;
    case 4:
        if(cmd==DEVICE_ON){
            bot_led1->ODR |= (1<<5);
        }else{
            bot_led1->ODR &= (~(1<<5));
        }
        break;
    case 5:
        if(cmd==DEVICE_ON){
            bot_led2->ODR |= (1<<6);
        }else{
            bot_led2->ODR &= (~(1<<6));
        }
        break;
    case 6:
        if(cmd==DEVICE_ON){
            bot_led3->ODR |= (1<<7);
        }else{
            bot_led3->ODR &= (~(1<<7));
        }
        break;
    case 7:
        if(cmd==DEVICE_ON){
            beep->ODR |= (1<<6);
        }else{
            beep->ODR &= (~(1<<6));
        }
        break;
    case 8:
        if(cmd==DEVICE_ON){
            fan->ODR |= (1<<9);
        }else{
            fan->ODR &= (~(1<<9));
        }
        break;
    case 9:
        if(cmd==DEVICE_ON){
            motor->ODR |= (1<<6);
        }else{
            motor->ODR &= (~(1<<6));
        }
        break;
    default:
        break;
    }
    return 0;
}
int my_close(struct inode *inode,struct file *file)
{
    return 0;
}
//初始化硬件设备
void device_init(void)
{
    //映射扩展板led物理地址
    rcc_ahb4=ioremap(RCC_AHB4,4);
    if(rcc_ahb4==NULL)
    {
        printk("rcc寄存器地址映射失败\n");
    }
    top_led1=ioremap(GPIOE,sizeof(gpio_t));
    if(top_led1==NULL)
    {
        printk("led1相关寄存器地址映射失败\n");
    }
    top_led2=ioremap(GPIOF,sizeof(gpio_t));
    if(top_led2==NULL)
    {
        printk("led2相关寄存器地址映射失败\n");
    }
    top_led3=ioremap(GPIOE,sizeof(gpio_t));
    if(top_led3==NULL)
    {
        printk("led3相关寄存器地址映射失败\n");
    }
    //初始化扩展板led,pe10,pf10,pe8
    *rcc_ahb4 |= (3<<4);
    top_led1->MODER &= (~(3<<20));
    top_led1->MODER |= (1<<20);
    top_led2->MODER &= (~(3<<20));
    top_led2->MODER |= (1<<20);
    top_led3->MODER &= (~(3<<16));
    top_led3->MODER |= (1<<16);

    //映射主板led物理地址
    rcc_ahb5=ioremap(RCC_AHB5,4);
    if(rcc_ahb5==NULL)
    {
        printk("rcc寄存器地址映射失败\n");
    }
    bot_led1=ioremap(GPIOZ,sizeof(gpio_t));
    if(bot_led1==NULL)
    {
        printk("led1相关寄存器地址映射失败\n");
    }
    bot_led2=ioremap(GPIOZ,sizeof(gpio_t));
    if(bot_led2==NULL)
    {
        printk("led2相关寄存器地址映射失败\n");
    }
    bot_led3=ioremap(GPIOZ,sizeof(gpio_t));
    if(bot_led3==NULL)
    {
        printk("led3相关寄存器地址映射失败\n");
    }
    //初始化主板led,pz5,pz6,pz7
    *rcc_ahb5 |= 1;
    bot_led1->MODER &= (~(3<<10));
    bot_led1->MODER |= (1<<10);
    bot_led2->MODER &= (~(3<<12));
    bot_led2->MODER |= (1<<12);
    bot_led3->MODER &= (~(3<<14));
    bot_led3->MODER |= (1<<14);

    //映射蜂鸣器,风扇,马达物理地址
    beep=ioremap(GPIOB,sizeof(gpio_t));
    if(beep==NULL)
    {
        printk("fan相关寄存器地址映射失败\n");
    }
    fan=ioremap(GPIOE,sizeof(gpio_t));
    if(fan==NULL)
    {
        printk("fan相关寄存器地址映射失败\n");
    }
    motor=ioremap(GPIOF,sizeof(gpio_t));
    if(motor==NULL)
    {
        printk("fan相关寄存器地址映射失败\n");
    }
    //初始化beep-pb6,fan-pe9,motor-pf6,
    beep->MODER &= (~(3<<12));
    beep->MODER |= (1<<12);
    fan->MODER &= (~(3<<18));
    fan->MODER |= (1<<18);
    motor->MODER &= (~(3<<12));
    motor->MODER |= (1<<12);
}

//定义操作方法结构体并初始化
struct file_operations fops=
{
    .open=my_open,
    .read=my_read,
    .write=my_write,
    .unlocked_ioctl=my_ioctl,
    .release=my_close,
};

//入口函数
static int __init mycdev_init(void)
{
    //给字符设备驱动变量申请空间
    cdev=cdev_alloc();
    if(cdev==NULL)
    {
        printk("申请空间失败\n");
        res=-ENOMEM;
        goto ERR1;
    }
    //初始化字符设备驱动
    cdev_init(cdev,&fops);
    //动态申请字符设备号
    res=alloc_chrdev_region(&devnum,minor,9,"mydevice");
    {
        if(res)
        {
            printk("动态申请设备号失败\n");
            res=-ENOMEM;
            goto ERR2;
        }
        major=MAJOR(devnum);
        minor=MINOR(devnum);
    }
    //将字符设备驱动注册到内核中
    res=cdev_add(cdev,devnum,9);
    if(res)
    {
        printk("添加字符设备到内核失败\n");
        res=-ENOMEM;
        goto ERR3;
    }
    printk("字符设备驱动注册成功\n");
    //向上提交目录
    cls=class_create(THIS_MODULE,"mydevice");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        res=PTR_ERR(cls);
        goto ERR4;
    }
    printk("向上提交目录成功\n");
    //向上提交设备节点
    for(i=0;i<9;i++)
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mydevice%d",i);
        if(IS_ERR(dev))
        {
            printk("向上提交节点信息失败\n");
            res=PTR_ERR(dev);
            goto ERR5;
        }
    }
    printk("向上提交节点信息成功\n");
    device_init();
    return 0;
ERR5:
    for(--i;i>=0;i--)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    class_destroy(cls);
ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(devnum,9);
ERR2:
    kfree(cdev);
ERR1:
    return res;
}
//出口函数
static void __exit mycdev_exit(void)
{
    //取消映射
    iounmap(rcc_ahb4);
    iounmap(top_led1);
    iounmap(top_led2);
    iounmap(top_led3);
    iounmap(rcc_ahb5);
    iounmap(bot_led1);
    iounmap(bot_led2);
    iounmap(bot_led3);
    iounmap(beep);
    iounmap(fan);
    iounmap(motor);
    //销毁设备节点
    for (i = 0; i < 9; i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //销毁目录
    class_destroy(cls);
    //注销字符设备驱动
    cdev_del(cdev);
    //释放设备号
    unregister_chrdev_region(MKDEV(major,minor),9);
    //释放内存空间
    kfree(cdev);

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

头文件 

#ifndef __DEVICE_H__
#define __DEVICE_H__

typedef struct
{
    volatile unsigned int MODER;
    volatile unsigned int OTYPER;
    volatile unsigned int OSPEEDR;
    volatile unsigned int PUPDR;
    volatile unsigned int IDR;
    volatile unsigned int ODR;
}gpio_t;

#define RCC_AHB4 0x50000a28
#define RCC_AHB5 0x54000210
#define GPIOB 0x50003000
#define GPIOE 0x50006000
#define GPIOF 0x50007000
#define GPIOZ 0x54004000

#define DEVICE_ON _IOW('a',1,int)
#define DEVICE_OFF _IOW('a',0,int)

#endif

Makefile

file ?= demo
arch ?= arm
ifeq ($(arch),arm)
KERNELDIR := /home/ubuntu/fsmp1a/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
else
KERNELDIR := /lib/modules/$(shell uname -r)/build/
endif
PWD := $(shell pwd)

all:
	make -C $(KERNELDIR) M=$(PWD) modules
clean:
	make -C $(KERNELDIR) M=$(PWD) clean

obj-m := $(file).o

解释一下下面的代码// vim: set et sw=4 sts=4 cindent: /* * @File: driver_defs.h * * @Abstract: Qualcomm Technologies Inc proprietary driver dependent components * * @Notes: This header is included to remove Qualcomm Technologies Inc driver dependency * to support ath10k driver * * @@-COPYRIGHT-START-@@ * * Copyright (c) 2017 Qualcomm Technologies, Inc. * All Rights Reserved. * Confidential and Proprietary - Qualcomm Technologies, Inc. * * @@-COPYRIGHT-END-@@ */ #ifndef wlanif_driver__h #define wlanif_driver__h #define IEEE80211_NWID_LEN 32 #define IEEE80211_BSTEERING_RRM_NUM_BCNRPT_MAX 8 #define BSTEERING_INVALID_RSSI 0 #define NETLINK_BAND_STEERING_EVENT 21 #define IEEE80211_ADDR_LEN 6 #define BSTEERING_MAX_PEERS_PER_EVENT 3 #define IEEE80211_RRM_MEASRPT_MODE_SUCCESS 0x00 #define MAC_ADDR_LEN 6 #define LTEU_MAX_BINS 10 #define MAX_SCAN_CHANS 32 #define IEEE80211_RATE_MAXSIZE 44 #define MAX_CHAINS 4 #define WME_NUM_AC 4 #define IEEE80211_RRM_NUM_CHANREQ_MAX 5 #define IEEE80211_RRM_NUM_CHANREP_MAX 3 #define IEEE80211_IOCTL_SETPARAM (SIOCIWFIRSTPRIV+0) #define IEEE80211_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+1) #define IEEE80211_IOCTL_SETKEY (SIOCIWFIRSTPRIV+2) #define IEEE80211_IOCTL_SETWMMPARAMS (SIOCIWFIRSTPRIV+3) #define IEEE80211_IOCTL_DELKEY (SIOCIWFIRSTPRIV+4) #define IEEE80211_IOCTL_GETWMMPARAMS (SIOCIWFIRSTPRIV+5) #define IEEE80211_IOCTL_SETMLME (SIOCIWFIRSTPRIV+6) #define IEEE80211_IOCTL_GETCHANINFO (SIOCIWFIRSTPRIV+7) #define IEEE80211_IOCTL_SETOPTIE (SIOCIWFIRSTPRIV+8) #define IEEE80211_IOCTL_GETOPTIE (SIOCIWFIRSTPRIV+9) #define IEEE80211_IOCTL_ADDMAC (SIOCIWFIRSTPRIV+10) /* Add ACL MAC Address */ #define IEEE80211_IOCTL_DELMAC (SIOCIWFIRSTPRIV+12) /* Del ACL MAC Address */
09-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值