linux_driver_day03

该代码段展示了如何使用ioctl函数在Linux内核中编写驱动程序,以控制LED、蜂鸣器和马达风扇。通过ioremap进行硬件寄存器映射,初始化GPIO,然后通过设备节点进行交互,实现硬件的开启和关闭功能。
摘要由CSDN通过智能技术生成

作业1

题目:

通过ioctl函数选择不同硬件的控制,LED 蜂鸣器 马达 风扇
通过ioctl函数选择不同硬件的控制,LED  蜂鸣器  马达  风扇
代码:

代码太多只展示 led 部分,点击查看完整代码

led.c

#include "led.h"
#include "head.h"

static void all_led_init(void);

static int major; // 保存主设备号
static char kbuf[128] = { 0 }; // 缓冲区

// 虚拟地址
static gpio_t *vir_led1;
static gpio_t *vir_led2;
static gpio_t *vir_led3;
static unsigned int *vir_rcc;

// 目录、设备信息
static struct class *cls;
static struct device *dev;

/**
 * @brief    初始化
 */
static int __init my_led_init(void)
{
    int i;

    // 注册驱动
    major = register_chrdev(0, "my_led", &fops);
    if (major < 0) {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功%d\n", major);

    // 映射寄存器
    vir_led1 = ioremap(PHY_GPIOE, sizeof(gpio_t));
    if (!vir_led1) {
        printk("LED1 地址映射失败\n");
        return -EFAULT;
    }

    vir_led2 = ioremap(PHY_GPIOF, sizeof(gpio_t));
    if (!vir_led2) {
        printk("LED2 地址映射失败\n");
        return -EFAULT;
    }

    vir_led3 = vir_led1;
    if (!vir_led3) {
        printk("LED3 地址映射失败\n");
        return -EFAULT;
    }

    vir_rcc = ioremap(PHY_RCC, 4);
    if (vir_rcc == NULL) {
        printk("RCC 寄存器地址映射失败\n");
        return -EFAULT;
    }
    printk("寄存器地址映射成功\n");

    // 初始化湖村桥
    all_led_init();
    printk("寄存器初始化成功\n");

    // 自动注册设备
    cls = class_create(THIS_MODULE, "my_led");
    if (!cls) {
        printk("向上提交目录失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交目录成功\n");

    for (i = 0; i < 3; i++) {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "my_led%d", i);
        if (IS_ERR(dev)) {
            printk("向上设备节点失败\n");
            return -PTR_ERR(dev);
        }
    }
    printk("向上设备节点成功\n");

    printk(KERN_ALERT "led mod installed\n");
    return 0;
}

/**
 * @brief    卸载
 */
static void __exit my_led_exit(void)
{
    int i;

    // 注销驱动
    unregister_chrdev(major, "my_led");
    printk("字符设备驱动 %d 注销成功\n", major);

    // 取消映射
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_rcc);
    printk("寄存器取消映射成功\n");

    // 自动卸载设备
    for (i = 0; i < 3; i++)
        device_destroy(cls, MKDEV(major, i));
    class_destroy(cls);

    printk(KERN_ALERT "led mod removed\n");
}

/**
 * @brief    开
 */
int my_led_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

/**
 * @brief    关
 */
int my_led_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

/**
 * @brief    读
 */
ssize_t my_led_read(struct file *file, char __user *ubuf, size_t size, loff_t *lof)
{
    // 拷贝内核缓冲区 到 用户空间缓冲区
    int ret;
    if (sizeof(kbuf) < size) // 同步内核的缓冲区大小
        size = sizeof(kbuf);
    ret = copy_to_user(ubuf, kbuf, size);

    if (ret) {
        printk("copy_to_user filed\n");
        return -EIO;
    }

    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

/**
 * @brief    写
 */
ssize_t my_led_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lof)
{
    // 拷贝用户空间缓冲区 到 内核空间
    int ret;
    if (sizeof(kbuf) < size)
        size = sizeof(kbuf);
    ret = copy_from_user(kbuf, ubuf, size);

    if (ret) {
        printk("copy_to_user filed\n");
        return -EIO;
    }
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);

    // // LED亮灭逻辑
    // if (kbuf[0] == '1') // led1
    //     (*vir_led1).odr ^= (0x1 << 10);
    // else if (kbuf[0] == '2') // led2
    //     (*vir_led2).odr ^= (0x1 << 10);
    // else if (kbuf[0] == '3') // led3
    //     (*vir_led1).odr ^= (0x1 << 8);

    return 0;
}

/**
 * @brief    GPIO控制
 */
long my_led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd) {
    case LED_ON: // 开灯
        switch (arg) {
        case 1: // led1
            (*vir_led1).odr |= (0x1 << 10);
            break;
        case 2: // led2
            (*vir_led2).odr |= (0x1 << 10);
            break;
        case 3: // led3
            (*vir_led3).odr |= (0x1 << 8);
            break;
        }
        break;
    case LED_OFF: // 关灯
        (*vir_led1).odr &= (~(0x1 << 10));
        (*vir_led2).odr &= (~(0x1 << 10));
        (*vir_led3).odr &= (~(0x1 << 8));
        break;
    }

    return 0;
}

/**
 * @brief    led初始化
 */
static void all_led_init(void)
{
    // RCC初始化
    (*vir_rcc) |= (0x3 << 4);

    // led1
    (*vir_led1).moder &= (~(0X3 << 20));
    (*vir_led1).moder |= (0X1 << 20);
    (*vir_led1).otyper &= (~(0X1 << 10));
    (*vir_led1).ospeedr &= (~(0X3 << 20));
    (*vir_led1).pupdr &= (~(0X3 << 20));

    // led2
    (*vir_led2).moder &= (~(0X3 << 20));
    (*vir_led2).moder |= (0X1 << 20);
    (*vir_led2).otyper &= (~(0X1 << 10));
    (*vir_led2).ospeedr &= (~(0X3 << 20));
    (*vir_led2).pupdr &= (~(0X3 << 20));

    // led3
    (*vir_led3).moder &= (~(0X3 << 16));
    (*vir_led3).moder |= (0X1 << 16);
    (*vir_led3).otyper &= (~(0X1 << 8));
    (*vir_led3).ospeedr &= (~(0X3 << 16));
    (*vir_led3).pupdr &= (~(0X3 << 16));
}

module_init(my_led_init);
module_exit(my_led_exit);
MODULE_LICENSE("GPL");

#ifndef _my_led_H_
#define _my_led_H_

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/ioctl.h>

// 开
int my_led_open(struct inode *inode, struct file *file);
// 关
int my_led_close(struct inode *inode, struct file *file);
// 读
ssize_t my_led_read(struct file *file, char __user *ubuf, size_t size, loff_t *lof);
// 写
ssize_t my_led_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lof);
// GPIO控制
long my_led_ioctl (struct file *file, unsigned int cmd, unsigned long arg);

// 重写文件操作结构体
struct file_operations fops = {
    .open = my_led_open,
    .release = my_led_close,
    .read = my_led_read,
    .write = my_led_write,
    .unlocked_ioctl = my_led_ioctl,
};

#endif //_my_led_H_

head.h

#ifndef _HEAD_H_
#define _HEAD_H_

// 定义寄存器组织结构体
typedef struct {
    unsigned int moder;
    unsigned int otyper;
    unsigned int ospeedr;
    unsigned int pupdr;
    unsigned int idr;
    unsigned int odr;
} gpio_t;

// 物理基地址
#define PHY_RCC        0x50000A28
#define PHY_LED1_ADDR  0x50006000 // PE10
#define PHY_LED2_ADDR  0x50007000 // PF10
#define PHY_LED3_ADDR  0x50006000 // PE8
#define PHY_FAN_ADDR   0x50006000 // PE9
#define PHY_MOTOR_ADDR 0x50007000 // PF6
#define PHY_BEEP_ADDR  0x50003000 // PB6

// GPIO控制
#define LED_ON    _IO('1', 1) // 1开 2关
#define LED_OFF   _IO('1', 2)
#define FAN_ON    _IO('1', 1)
#define FAN_OFF   _IO('1', 2)
#define MOTOR_ON  _IO('1', 1)
#define MOTOR_OFF _IO('1', 2)
#define BEEP_ON   _IO('1', 1)
#define BEEP_OFF  _IO('1', 2)

#define PHY_GPIOE 0X50006000
#define PHY_GPIOF 0X50007000
#endif //_HEAD_H_
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值