内核模块化风扇蜂鸣器等代码实现

#include <linux/init.h>

#include <linux/module.h>

#include <linux/fs.h>

#include <linux/io.h>

#include <linux/uaccess.h>

#include <linux/device.h>

#include <linux/ioctl.h>

#include "myled.h"

#define CNAME "myled"

int major;           //定义变量接收主设备号

char kbuf[128] = {}; //定义数组用于存放和用户之间拷贝的数据

gpio_t *vir_led1;

gpio_t *vir_led2;

gpio_t *vir_led3;

gpio_t *vir_fan1;

gpio_t *vir_sp1;

gpio_t *vir_m1;

unsigned int *vir_rcc_apb1;

unsigned int *vir_rcc_apb2;

unsigned int *vir_rcc;

struct class *cls; //句柄

struct device *dev;

//对应的是open()

int mycdev_open(struct inode *inode, struct file *file)

{

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

    return 0;

}

// read()

ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)

{

    // size参数是用户期待读到的字节长度

    int ret;

    if (size > sizeof(kbuf))

        size = sizeof(kbuf);

    ret = copy_to_user(ubuf, kbuf, size);

    if (ret)

    {

        printk("数据从内核向用户拷贝失败\n");

        return -EIO;

    }

    return size;

}

// write()

ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)

{

    int ret;

    if (size > sizeof(kbuf))

        size = sizeof(kbuf);

    ret = copy_from_user(kbuf, ubuf, size);

    if (ret)

    {

        printk("数据从内核向用户拷贝失败\n");

        return -EIO;

    }

    /*if(kbuf[0]=='1')//开灯

        vir_led1->ODR |= (1<<10);

    else if(kbuf[0]=='2')

        vir_led2->ODR |= (1 << 10);

    else if(kbuf[0]=='3')

       vir_led3->ODR |= (1 << 8);

    else//关灯

    {

        vir_led1->ODR &= ~(1<<10);

        vir_led2->ODR&= ~(1 << 10);

       vir_led3->ODR &= ~(1 << 8);

    }*/

    return size;

}

// close()

long ioctl(struct file *file, unsigned int cmd, unsigned long arg)

{

    // cmd是传输过来的功能模块,arg是传递过来的第三个参数,选择是哪个灯的

    // file对应着文件描述符文件

    int which, ret;

    switch (cmd)

    {

    case led_ON:

    {

        ret = copy_from_user(&which, (void *)arg, sizeof(int)); //获取发送的数据是否成功

        if (ret)

        {

            printk("数据向内核拷贝失败\n");

            return -EIO;

        }

        switch (which)

        {

        case LED1:

            vir_led1->ODR |= (1 << 10);

            break;

        case LED2:

            vir_led2->ODR |= (1 << 10);

            break;

        case LED3:

            vir_led3->ODR |= (1 << 8);

            break;

        case M1:

            vir_m1->ODR |= (1 << 6);

            break;

        case FAN1:

            vir_fan1->ODR |= (1 << 9);

            break;

        case SP1:

            vir_sp1->ODR |= (1 << 6);

            break;

        }

        break;

    }

    case led_OFF:

    {

        ret = copy_from_user(&which, (void *)arg, sizeof(int));

        if (ret)

        {

            printk("用户向内核拷贝数据失败\n");

            return -EIO;

        }

        switch (which)

        {

        case LED1:

            vir_led1->ODR &= ~(1 << 10);

            break;

        case LED2:

            vir_led2->ODR &= ~(1 << 10);

            break;

        case LED3:

            vir_led3->ODR &= ~(1 << 8);

            break;

        case M1:

            vir_m1->ODR &= ~(1 << 6);

            break;

        case FAN1:

            vir_fan1->ODR &= ~(1 << 9);

            break;

        case SP1:

            vir_sp1->ODR &= ~(1 << 6);

            break;

        }

        break;

    }

    default:

        printk("功能码错误\n");

        break;

    }

    return 0;

}

int mycdev_close(struct inode *inode, struct file *file)

{

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

    return 0;

}

//操作方法结构体的初始化

struct file_operations fops =

    {

        .open = mycdev_open,

        .read = mycdev_read,

        .write = mycdev_write,

        .unlocked_ioctl = ioctl,

        .release = mycdev_close,

};

int all_led_init(void)

{

    //进行物理地址的映射

    vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));

    if (vir_led1 == NULL)

    {

        printk("vir_led1 映射失败\n");

        return -ENOMEM;

    }

    printk("vir_led1 映射成功\n");

    vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));

    if (vir_led2 == NULL)

    {

        printk("vir_led2 映射失败\n");

        return -ENOMEM;

    }

    printk("vir_led2 映射成功\n");

    vir_led3 = ioremap(PHY_LED3_ADDR, sizeof(gpio_t));

    if (vir_led3 == NULL)

    {

        printk("vir_led3 映射失败\n");

        return -ENOMEM;

    }

    printk("vir_led3 映射成功\n");

    vir_rcc = ioremap(PHY_RCC_ADDR, 4);

    if (vir_rcc == NULL)

    {

        printk("vir_rcc 映射失败\n");

        return -ENOMEM;

    }

    //apb1

    vir_rcc_apb1 = ioremap(PHY_RCC_APB1, 4);

    if (vir_rcc_apb1 == NULL)

    {

        printk("vir_rcc_apb1 映射失败\n");

        return -ENOMEM;

    }

    printk("vir_rcc_apb1 映射成功\n");

    //apb2

    vir_rcc_apb2 = ioremap(PHY_RCC_APB2, 4);

    if (vir_rcc_apb2 == NULL)

    {

        printk("vir_rcc_apb2 映射失败\n");

        return -ENOMEM;

    }

    printk("vir_rcc_apb2 映射成功\n");

    //风扇

    vir_fan1 = ioremap(PHY_FAN1_ADDR, sizeof(gpio_t));

    if (vir_fan1 == NULL)

    {

        printk("vir_fan1 映射失败\n");

        return -ENOMEM;

    }

    printk("vir_fan1 映射成功\n");

    // m1

    vir_m1 = ioremap(PHY_M1_ADDR, sizeof(gpio_t));

    if (vir_m1 == NULL)

    {

        printk("vir_m1 映射失败\n");

        return -ENOMEM;

    }

    printk("vir_m1 映射成功\n");

    // sp1

    vir_sp1 = ioremap(PHY_SP1_ADDR, sizeof(gpio_t));

    if (vir_sp1 == NULL)

    {

        printk("vir_sp1 映射失败\n");

        return -ENOMEM;

    }

    printk("vir_sp1 映射成功\n");

    //寄存器的初始化

    // 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);

    // fan1

    vir_fan1->MODER &= ~(3 << 18);

    vir_fan1->MODER |= (1 << 18);

    vir_fan1->ODR &= ~(1 << 9);

    // sp1

    vir_sp1->MODER &= ~(3 << 12);

    vir_sp1->MODER |= (1 << 12);

    vir_sp1->ODR &= ~(1 << 6);

    // m1

    vir_m1->MODER &= ~(3 << 12);

    vir_m1->MODER |= (1 << 12);

    vir_m1->ODR &= ~(1 << 6);

    //使能TIM寄存器

    (*vir_rcc) |= (3 << 4);

    (*vir_rcc_apb1) |= (1 << 2); //使能TIM4

    (*vir_rcc_apb2) |= (1 << 0); //使能TIM1

    (*vir_rcc_apb2) |= (1 << 3); //使能TIM16

    (*vir_rcc) |= (1 << 1);      //使能gpiob

    return 0;

}

//入口函数,当驱动安装的时候执行

static int __init demo_init(void)

{

    //动态注册字符设备驱动

    major = register_chrdev(0, CNAME, &fops);

    if (major < 0)

    {

        printk("字符设备驱动注册失败\n");

        return major;

    }

    printk("字符设备驱动注册成功major=%d\n", major);

    //寄存器的初始化

    all_led_init();

    return 0;

}

//出口函数,卸载驱动的时候执行

static void __exit demo_exit(void)

{

    //销毁节点

    device_destroy(cls, MKDEV(major, 0));

    //销毁目录

    class_destroy(cls);

    //取消映射

    iounmap(vir_led1);

    iounmap(vir_led2);

    iounmap(vir_led3);

    iounmap(vir_rcc);

    iounmap(vir_m1);

    iounmap(vir_fan1);

    iounmap(vir_sp1);

    iounmap(vir_rcc_apb1);

    iounmap(vir_rcc_apb2);

    //注销字符设备驱动

    unregister_chrdev(major, CNAME);

}

module_init(demo_init);

module_exit(demo_exit);

MODULE_LICENSE("GPL");

myled.h文件

#ifndef __MYLED_H_

#define __MYLED_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;

#define PHY_LED1_ADDR 0X50006000//e10

#define PHY_LED2_ADDR 0X50007000//f10

#define PHY_LED3_ADDR 0X50006000//e8

#define PHY_RCC_ADDR 0X50000A28

#define PHY_RCC_APB1 0X50000A00//TIM4(2)使能

#define PHY_RCC_APB2 0x50000A08//TIM1(0)和TIM16(3)使能,

#define PHY_M1_ADDR  0x50003000//GPIOB,b6,APB1总线上的TIM4,sp1,AF2

#define PHY_FAN1_ADDR 0X50006000//e9,APB2总线,TIM1,fan1,AF1

#define PHY_SP1_ADDR 0X50007000//f6,APB1总线上的TIM16,m1,AF1

 enum LED

    {

        LED1=1,

        LED2,

        LED3,

        M1,

        FAN1,

        SP1

    };

#define LED_ON _IO('a', 1)

#define LED_OFF _IO('a', 0)

#define led_ON _IOW('a', 1,int)

#define led_OFF _IOW('a', 0,int)

#endif

test.c文件

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include "myled.h"
#include <string.h>
int main(int argc, char const *argv[])
{
    char buf[128] = {};
    int which;
    int fd = open("/dev/myled", O_RDWR);
    if (fd < 0)
    {

        printf("打开设备文件失败\n");
        exit(-1);
    }
    printf("打开设备成功\n"); //在终端输入
    //在终端输入
    while (1)
    {
        printf("请输入控制命令 1开灯 0:关灯\n");
        fgets(buf, sizeof(buf), stdin);
        //吃掉换行符
        buf[strlen(buf) - 1] = '\0';
        printf("请输入要操作的灯1-->led1,2-->led2,3-->led3\n");
        scanf("%d", &which);
        getchar();
        if (buf[0] == '1')
            ioctl(fd, led_ON,&which);
        else
            ioctl(fd, led_OFF,&which);
    }
    close(fd);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值