驱动开发LED灯绑定设备文件

头文件

cs 复制代码
#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_LED1_ADDR 0x50006000
#define PHY_LED2_ADDR 0x50007000
#define PHY_LED3_ADDR 0x50006000
#define PHY_RCC_ADDR 0x50000A28
#define LED_ON _IOW('l',1,int)
#define LED_OFF _IOW('l',0,int)

#endif

应用程序

cs 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "head.h"
int main(int argc,char const *argv[])
{
    char buf[128]={0};
    int a,b;
    int fd=open("/dev/demo0",O_RDWR);
    if(fd<0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    while(1)
    {
        //从终端读取
        printf("请输入要实现的功能 ");
        printf("0(关灯) 1(开灯)\n");
        printf("请输入>");
        scanf("%d",&a);
        printf("请选择要控制的灯:1(LED1)2(LED2) 3(LED3)\n");
        printf("请输入>");
        scanf("%d",&b);
        switch(a)
        {
            case 1:
                ioctl(fd,LED_ON,&b);
                break;
            case 0:
                ioctl(fd,LED_OFF,&b);
                break;
        }
    }

    
    close(fd);

    return 0;
}

驱动程序

cs 复制代码
#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 "head.h"
unsigned int major=0;
unsigned int minor=0;
char kbuf[128]={};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;
struct cdev *cdev;
dev_t devno;
struct class *cls;
struct device *dev;

int mycdev_open(struct inode *inode, struct file *file)
{
    int min=MINOR(inode->i_rdev);
    file->private_data=(void *)min;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}

long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
    int min=(int)file->private_data;
    switch (min)
    {
    case 0: // 操作LED1
        switch (cmd)
        {
        case LED_ON: //开灯
            vir_led1->ODR |= (0x1<<10);
            break;
        case LED_OFF://关灯
            vir_led1->ODR &= (~(0x1<<10));
            break;
        }
        break;
    case 1: // 操作LED2
        switch (cmd)
        {
        case LED_ON: //开灯
            vir_led2->ODR |= (0x1<<10);
            break;
        case LED_OFF://关灯
            vir_led2->ODR &= (~(0x1<<10));
            break;
        }
        break;
    case 2: // 操作LED3
        switch (cmd)
        {
        case LED_ON: //开灯
            vir_led3->ODR |= (0x1<<8);
            break;
        case LED_OFF://关灯
            vir_led3->ODR &= (~(0x1<<8));
            break;
        }
        break;
    }
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    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,
    .unlocked_ioctl=mycdev_ioctl,
    .release=mycdev_close,
};

int all_led_init(void)
{
    //寄存器地址的映射
    vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t));
    if(vir_led1==NULL)
    {
        printk("ioremap filed:%d\n",__LINE__);
        return -ENOMEM;
    }
     vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
    if(vir_led2==NULL)
    {
        printk("ioremap filed:%d\n",__LINE__);
        return -ENOMEM;
    }
     vir_led3=vir_led1;
    vir_rcc=ioremap(PHY_RCC_ADDR,4);
    if(vir_rcc==NULL)
    {
        printk("ioremap filed:%d\n",__LINE__);
        return -ENOMEM;
    }
    printk("物理地址映射成功\n");
    //寄存器的初始化
    //rcc
    (*vir_rcc) |= (3<<4);
    //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_led1->MODER |= (1<<16);
    vir_led1->ODR &= (~(1<<8));
    printk("寄存器初始化成功\n");

    return 0;
}

static int __init mycdev_init(void)
{
        //1.申请一个对象空间cdev_alloc
    int ret;
    cdev= cdev_alloc();
    if(cdev==NULL)
    {
        printk("申请字符设备驱动对象失败\n");
        ret=-EFAULT;
        goto out1;

    }
    printk("字符设备驱动对象申请成功\n");
    //2.初始化对象cdev_init
    cdev_init(cdev,&fops);
    //3.申请设备号  register_chrdev_region()/alloc_chrdev_region()
    if(major==0)//动态申请
    {
        ret=alloc_chrdev_region(&devno,minor,3,"demo");
        if(ret)
        {
            printk("动态申请设备号失败\n");
            goto out2;
        }
        major=MAJOR(devno);//根据设备号获取主设备号
        minor=MINOR(devno);//根据设备号获取次设备号
    }
    else
    {
        ret=register_chrdev_region(MKDEV(major,minor),3,"demo");
        if(ret)
        {
            printk("静态指定设备号失败\n");
            goto out2;
        }
    }
    printk("设备号申请成功\n");
    //4.注册驱动对象  cdev_add
    ret=cdev_add(cdev,MKDEV(major,minor),3);
    if(ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto out3;
    }
    printk("注册字符设备驱动对象成功\n");
    //5.向上提交目录  class_create
    cls=class_create(THIS_MODULE,"demo");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        goto out4;
    }
    printk("向上提交目录成功\n");
    //6.向上提交设备节点信息  device_create
    int i;
    for(i=0;i<3;i++)
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"demo%d",i);
        if(IS_ERR(dev))
        {
            printk("向上提交设备节点失败\n");
            goto out5;
        }
    }
    printk("向上提交设备节点信息成功\n");
    
    all_led_init();
    return 0;
out5:
//将提交成功的节点信息释放
    for(--i;i>=0;i--)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //销毁目录
    class_destroy(cls);
out4:
    cdev_del(cdev);
out3:
    unregister_chrdev_region(MKDEV(major,minor),3);
out2:
    kfree(cdev);
out1:
    return ret;

}
static void __exit mycdev_exit(void)
{
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_rcc);

//1.销毁设备节点信息
    int i;
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //2.销毁目录
    class_destroy(cls);
    //3.注销字符设备驱动对象
    cdev_del(cdev);
    //4.释放设备号
    unregister_chrdev_region(MKDEV(major,minor),3);
    //5.释放申请到的字符设备驱动对象空间
    kfree(cdev);
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
相关推荐
dlz08363 小时前
POE驱动开发流程
驱动开发
嵌入式-老费5 小时前
Linux camera驱动开发(DVP接口的camera sensor)
驱动开发
VernonJsn19 小时前
visual studio 2022的windows驱动开发
ide·驱动开发·visual studio
嵌入式郑工1 天前
RK3566 LubanCat 开发板 USB Gadget 配置完整复盘
linux·驱动开发·ubuntu
雾削木2 天前
树莓派 ESPHome 固件编译与烧录全攻略(解决超时与串口识别问题)
驱动开发
春日见3 天前
win11 分屏设置
java·开发语言·驱动开发·docker·单例模式·计算机外设
DarkAthena3 天前
【GaussDB】手动编译不同python版本的psycopg2驱动以适配airflow
驱动开发·python·gaussdb
松涛和鸣4 天前
DAY66 SPI Driver for ADXL345 Accelerometer
linux·网络·arm开发·数据库·驱动开发
嵌入式郑工4 天前
# RK3576 平台 RTC 时钟调试全过程
linux·驱动开发·ubuntu
GS8FG4 天前
针对Linux,RK3568平台下,I2C驱动的一点小小的领悟
linux·驱动开发