【驱动---ioctl函数使用】

实验要求

通过ioctl函数实现6盏灯的亮灭(区分到底时拓展板还是底板)、蜂鸣器的打开关闭、马达的开关

分析

ioctl

应用层:
    #include <sys/ioctl.h>  
    int which=10;  

   int ioctl(int fd, unsigned long request, ...);
   功能:进行设备的读写控制
   参数:
   fd:设备文件的文件描述符
   request:功能码 
   ...:第三个参数,可以通过这个参数向内核实现数据拷贝,这个参数写要拷贝的数据所在空间首地址   
   返回值:成功返回0、失败返回错误码或者-1
   *******************************************************************
   内核层:
       struct file_operations {
    
    
        long (*unlocked_ioctl) (struct file *file, unsigned int cmd, unsigned long arg);
            cmd:功能码
            arg:用户空间ioctl第三个参数传递的参数
                }

如果想要得到上面的代表特定功能的功能吗,可以通过下面的宏定义实现:

#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)   //ioctl不传递第三个参数时使用
#define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))

copy_from_user


unsigned long 
copy_from_user(void *to, const void __user *from, unsigned long n)
功能:实现用户空间数据拷贝到内核空间
参数:
    to:内核空间存放数据的首地址
    from:用户空间存放数据的首地址
    n:大小(字节)
返回值:成功返回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 "test.h"
int major;
char kbuf[128] = {
    
    0};
struct class *cls;
struct device *dev;
unsigned int *vir_rcc;
unsigned int *vir_m_rcc;
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
gpio_t *vir_m_led1;
gpio_t *vir_m_led2;
gpio_t *vir_m_led3;
gpio_t *vir_beep;
gpio_t *vir_motor;
int mycdev_open(struct inode *inode, struct file *file)
{
    
    
    return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *off)
{
    
    
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *off)
{
    
    

    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    
    
    return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    
    
    int ret;
    devices_t devs;

    ret = copy_from_user((void *)&devs, (void *)arg, sizeof(struct devices)); // 把ioctl第三个参数的数值获取到
    if (ret)
    {
    
    
        printk("copy_from_user err\n");
        return -ENOMEM;
    }
    switch (cmd)
    {
    
    
    case MAIN_DEVICE:
        switch (devs.which)
        {
    
    
        case 1:
            if (devs.state == 1)
            {
    
    
                vir_m_led1->ODR |= (1 << 5);
            }
            else
            {
    
    
                vir_m_led1->ODR &= (~(1 << 5));
            }
            break;
        case 2:
            if (devs.state == 1)
            {
    
    
                vir_m_led2->ODR |= (1 << 6);
            }
            else
            {
    
    
                vir_m_led2->ODR &= (~(1 << 6));
            }
            break;
        case 3:
            if (devs.state == 1)
            {
    
    
                vir_m_led3->ODR |= (1 << 7);
            }
            else
            {
    
    
                vir_m_led3->ODR &= (~(1 << 7));
            }
            break;
        }
        break;
    case OTHER_DEVICE:
        if (devs.device == 0)
        {
    
    
            switch (devs.which)
            {
    
    
            case 1:
                if (devs.state == 1)
                {
    
    
                    vir_led1->ODR |= (1 << 10);
                }
                else
                {
    
    
                    vir_led1->ODR &= (~(1 << 10));
                }
                break;
            case 2:
                if (devs.state == 1)
                {
    
    
                    vir_led2->ODR |= (1 << 10);
                }
                else
                {
    
    
                    vir_led2->ODR &= (~(1 << 10));
                }
                break;
            case 3:
                if (devs.state == 1)
                {
    
    
                    vir_led3->ODR |= (1 << 8);
                }
                else
                {
    
    
                    vir_led3->ODR &= (~(1 << 8));
                }
                break;
            }
        }
        else if (devs.device == 1)
        {
    
    
            if (devs.state == 1)
            {
    
    
                vir_beep->ODR |= (1 << 6);
            }
            else
            {
    
    
                vir_beep->ODR &= (~(1 << 6));
            }
        }
        else if (devs.device == 2)
        {
    
    
            if (devs.state == 1)
            {
    
    
                vir_motor->ODR |= (1 << 6);
            }
            else
            {
    
    
                vir_motor->ODR &= (~(1 << 6));
            }
        }
    }
    
    return 0;
}
struct file_operations fops =
    {
    
    
        .open = mycdev_open,
        .write = mycdev_write,
        .read = mycdev_read,
        .release = mycdev_close,
        .unlocked_ioctl = mycdev_ioctl,
};

int all_leds_init(void)
{
    
    
    // 进行物理地址映射
    vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));
    if (vir_led1 == NULL)
    {
    
    
        printk("LED1寄存器映射失败\n");
        return -ENOMEM;
    }
    vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));
    if (vir_led2 == NULL)
    {
    
    
        printk("LED2寄存器映射失败\n");
        return -ENOMEM;
    }
    vir_led3 = ioremap(PHY_LED3_ADDR, sizeof(gpio_t));
    if (vir_led3 == NULL)
    {
    
    
        printk("LED3寄存器映射失败\n");
        return -ENOMEM;
    }
    vir_rcc = ioremap(PHY_RCC_ADDR, 4);
    if (vir_rcc == NULL)
    {
    
    
        printk("RCC寄存器映射失败\n");
        return -ENOMEM;
    }
    // 主板LED地址映射
    vir_m_led1 = ioremap(MAIN_LED_ADDR, sizeof(gpio_t));
    if (vir_m_led1 == NULL)
    {
    
    
        printk("LED1寄存器映射失败\n");
        return -ENOMEM;
    }
    vir_m_led2 = ioremap(MAIN_LED_ADDR, sizeof(gpio_t));
    if (vir_m_led2 == NULL)
    {
    
    
        printk("LED2寄存器映射失败\n");
        return -ENOMEM;
    }
    vir_m_led3 = ioremap(MAIN_LED_ADDR, sizeof(gpio_t));
    if (vir_m_led3 == NULL)
    {
    
    
        printk("LED3寄存器映射失败\n");
        return -ENOMEM;
    }
    vir_m_rcc = ioremap(RCC_AHB5_ADDR, 4);
    if (vir_m_rcc == NULL)
    {
    
    
        printk("RCC寄存器映射失败\n");
        return -ENOMEM;
    }

    printk("寄存器物理地址映射成功\n");
    // rcc初始化
    (*vir_rcc) |= (3 << 4); // rcc使能
    (*vir_m_rcc) |= 0;      // gpioz rcc使能
    // LED1初始化
    vir_led1->MODER &= (~(3 << 20)); // 设置为输出模式
    vir_led1->MODER |= (1 << 20);
    vir_led1->ODR &= (~(1 << 10)); // 输出低电平
    // LED2初始化
    vir_led2->MODER &= (~(3 << 20)); // 设置为输出模式
    vir_led2->MODER |= (1 << 20);
    vir_led2->ODR &= (~(1 << 10)); // 输出低电平
    // LED3初始化
    vir_led3->MODER &= (~(3 << 16)); // 设置为输出模式
    vir_led3->MODER |= (1 << 16);
    vir_led3->ODR &= (~(1 << 8)); // 输出低电平
    // 主板LED的LED灯初始化
    //  LED1初始化
    vir_m_led1->MODER &= (~(3 << 10)); // 设置为输出模式
    vir_m_led1->MODER |= (1 << 10);
    vir_m_led1->ODR &= (~(1 << 5)); // 输出低电平
    // LED2初始化
    vir_m_led2->MODER &= (~(3 << 12)); // 设置为输出模式
    vir_m_led2->MODER |= (1 << 12);
    vir_m_led2->ODR &= (~(1 << 6)); // 输出低电平
    // LED3初始化
    vir_m_led3->MODER &= (~(3 << 14)); // 设置为输出模式
    vir_m_led3->MODER |= (1 << 14);
    vir_m_led3->ODR &= (~(1 << 7)); // 输出低电平
    printk("寄存器初始化成功\n");
    return 0;
}
int beep_init(void)
{
    
    
    // 内存映射
    vir_beep = ioremap(PHY_BEEP_ADDR, sizeof(gpio_t));
    if (vir_beep == NULL)
    {
    
    
        printk("LED1寄存器映射失败\n");
        return -ENOMEM;
    }
    *vir_rcc |= (0x1 << 1);          // GPIOB使能
    vir_beep->MODER &= (~(3 << 12)); // 设置为输出模式
    vir_beep->MODER |= (1 << 12);
    vir_beep->ODR &= (~(1 << 6)); // 输出低电平
    return 0;
}
int motor_init(void)
{
    
    
    vir_motor = ioremap(PHY_MOTOR_ADDR, sizeof(gpio_t));
    if (vir_motor == NULL)
    {
    
    
        printk("LED1寄存器映射失败\n");
        return -ENOMEM;
    }
    vir_motor->MODER &= (~(3 << 12)); // 设置为输出模式
    vir_motor->MODER |= (1 << 12);
    vir_motor->ODR &= (~(1 << 6)); // 输出低电平
    return 0;
}
static int __init mycdev_init(void)
{
    
    
    int i;
    major = register_chrdev(0, "mycdev", &fops);
    if (major < 0)
    {
    
    
        printk("字符驱动注册失败\n");
        return major;
    }
    else
    {
    
    
        printk("字符设备注册成功 major = %d\n", major);
    }
    // 向上提交目录
    cls = class_create(THIS_MODULE, "mycdev");
    if (IS_ERR(cls))
    {
    
    
        printk("向上提交目录失败\n");
        return PTR_ERR(cls);
    }
    // 向上提交设备信息
    for (i = 0; i < 3; i++)
    {
    
    
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);
        if (IS_ERR(dev))
        {
    
    
            printk("向上提交设备结点失败\n");
            return PTR_ERR(dev);
        }
    }
    printk("向上提交设备结点成功\n");
    // 初始化
    all_leds_init();
    beep_init();
    motor_init();
    return 0;
}
static void __exit mycdev_exit(void)
{
    
    
    int i;
    // 取消物理内存的映射
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_led3);
    iounmap(vir_rcc);
    iounmap(vir_m_led1);
    iounmap(vir_m_led2);
    iounmap(vir_m_led3);
    iounmap(vir_m_rcc);
    iounmap(vir_beep);
    iounmap(vir_motor);
    // 删除结点信息
    for (i = 0; i < 3; i++)
    {
    
    
        device_destroy(cls, MKDEV(major, i));
    }
    // 删除目录信息
    class_destroy(cls);

    // 注销驱动
    unregister_chrdev(major, "mycdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");


测试代码

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include "test.h"
int main(int argc, const char *argv[])
{
    
    
    int chose;
    devices_t dev;
    int fd = open("/dev/mycdev1", O_RDWR);
    if (fd < 0)
    {
    
    
        printf("文件打开失败\n");
        exit(-1);
    }
    while (1)
    {
    
    
        printf("-----------------------------功能菜单------------------------------\n");
        printf("\t\t\t0.开拓展板LED1灯\n");
        printf("\t\t\t1.关拓展板LED1灯\n");
        printf("\t\t\t2.开拓展板LED2灯\n");
        printf("\t\t\t3.关拓展板LED2灯\n");
        printf("\t\t\t4.开拓展板LED3灯\n");
        printf("\t\t\t5.关拓展板LED3灯\n");
        printf("\t\t\t6.开主板LED1灯\n");
        printf("\t\t\t7.关主板LED1灯\n");
        printf("\t\t\t8.开主板LED2灯\n");
        printf("\t\t\t9.关主板LED2灯\n");
        printf("\t\t\t10.开主板LED3灯\n");
        printf("\t\t\t11.关主板LED3灯\n");
        printf("\t\t\t12.开蜂鸣器\n");
        printf("\t\t\t13.关蜂鸣器\n");
        printf("\t\t\t14.开马达\n");
        printf("\t\t\t15.关马达\n");
        printf("------------------------------------------------------------------\n");
        scanf("%d", &chose);
        switch (chose)
        {
    
    
        case 0:
            dev.device = 0;
            dev.state = 1;
            dev.which = 1;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        case 1:
            dev.device = 0;
            dev.state = 0;
            dev.which = 1;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        case 2:;
            dev.device = 0;
            dev.state = 1;
            dev.which = 2;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        case 3:
            dev.device = 0;
            dev.state = 0;
            dev.which = 2;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        case 4:
            dev.device = 0;
            dev.state = 1;
            dev.which = 3;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        case 5:
            dev.device = 0;
            dev.state = 0;
            dev.which = 3;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        case 6:
            dev.device = 0;
            dev.state = 1;
            dev.which = 1;
            ioctl(fd, MAIN_DEVICE, &dev);
            break;
        case 7:
            dev.device = 0;
            dev.state = 0;
            dev.which = 1;
            ioctl(fd, MAIN_DEVICE, &dev);
            break;
        case 8:
            dev.device = 0;
            dev.state = 1;
            dev.which = 2;
            ioctl(fd, MAIN_DEVICE, &dev);
            break;
        case 9:
            dev.device = 0;
            dev.state = 0;
            dev.which = 2;
            ioctl(fd, MAIN_DEVICE, &dev);
            break;
        case 10:
            dev.device = 0;
            dev.state = 1;
            dev.which = 3;
            ioctl(fd, MAIN_DEVICE, &dev);
            break;
        case 11:
            dev.device = 0;
            dev.state = 0;
            dev.which = 3;
            ioctl(fd, MAIN_DEVICE, &dev);
            break;
        case 12:
            dev.device = 1;
            dev.state = 1;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        case 13:
            dev.device = 1;
            dev.state = 0;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        case 14:
            dev.device = 2;
            dev.state = 1;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        case 15:
            dev.device = 2;
            dev.state = 0;
            ioctl(fd, OTHER_DEVICE, &dev);
            break;
        default:
            break;
        }
    }
    close(fd);
    return 0;
}

头文件

#ifndef __TEST_H__
#define __TEST_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;
    volatile unsigned int BSRR;
} gpio_t;

typedef struct devices
{
    
    
    int device; //对应哪一个设备;0:LED灯  1:蜂鸣器   2:马达
    int state;  //0:关  1:开
    int which;  //对应哪盏灯;
}devices_t;


#define PHY_RCC_ADDR 0X50000A28
#define RCC_AHB5_ADDR 0x50000210
#define PHY_LED1_ADDR 0X50006000
#define PHY_LED2_ADDR 0X50007000
#define PHY_LED3_ADDR 0X50006000
#define MAIN_LED_ADDR 0x54004000
#define PHY_BEEP_ADDR 0x50003000
#define PHY_MOTOR_ADDR 0x50007000

#define MAIN_DEVICE _IOW('l',1,devices_t)    //主板
#define OTHER_DEVICE _IOW('l',0,devices_t)    //拓展板
#endif

猜你喜欢

转载自blog.csdn.net/a1379292747/article/details/128943372
今日推荐