作业1
题目:
通过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_



















