[Linux字符驱动] LED基于gpio系统点灯

首先聊一下linux中的软件工作岗位,有专门负责BSP的,负责把uboot、kernel、文件系统都搞定,这些都是比较复杂的;打包好了之后,基本万年不动,除非有问题暴露需要解决;内核驱动里面有基于总线架构和一些子系统实现,比如input子系统、pinctrl子系统、i2c、spi总线模型驱动;还有一些块驱动,比如,Nand、EMMC驱动;网络驱动,有网卡芯片、PHY芯片,和spi接口的网卡芯片驱动都算是网络驱动;最后介绍一下字符驱动,这是最常更改的一类驱动,也通常是自己实现的驱动。
驱动的范围包含:LED、DO控制、DI读取、按键读取等;

网上教学的LED字符驱动有很多,大多数从iormap,或者调用底层的地址去点灯,那是想让大家了解与单片机操作地址的区别;那些博主都非常的棒,我现在直接上干货,项目和工作中直接的用法。

关注微信公众号,回复“led字符驱动”,下载源代码。

1、模块驱动的入口函数

module_init(at91_led_init);//加载模块先运行init函数
module_exit(at91_led_cleanup);//卸载模块进入cleanup函数


//符合GPL规范,开源,否则无法加载进内核运行
MODULE_DESCRIPTION ("AT91 led DRIVER"); 
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR ("Jack"); 
MODULE_LICENSE ("GPL");


//驱动模块的描述信息,可帮助使用者了解这个模块的功能
#define DRV_VERSION "1.0.0"

static int led_major;
module_param(led_major, int, 0);
MODULE_PARM_DESC(led_major, "led Major device number");

2、创建init和cleanup函数

定义初始化信息,4个LED灯

struct led_pin
{
   
    ulong led_pin_run;          /* 运行灯 */
    ulong led_pin_fault;        /* 故障灯 */
    ulong led_pin_can5;     /* CAN5 */
    ulong led_pin_can6;     /* CAN6 */
};

struct St_led
{
   
    dev_t dev_major;
    struct led_pin st_pin;
    atomic_t open_count;
    struct mutex led_mudex;//互斥锁
    struct cdev led_dev;//
    struct class *led_class;
    struct device *led_device;
};

注册驱动流程

static int __init at91_led_init(void)
{
    
    int retval = -1;
    dev_t dev_id;

    // 分配一个结构
    pled = (struct St_led *)kzalloc(sizeof (struct St_led),GFP_KERNEL);
    if(!pled)
    {
   
        printk("%s:kzalloc failded from:%s\n", __func__,LED_NAME);
        return -ENOMEM;
    }

    //初始化锁,指定具体的PIN脚,根据数据手册定义的地址自定义宏
    pled->st_pin.led_pin_run = AT91_PIN_PD26;   /* 运行灯 */
    pled->st_pin.led_pin_fault= AT91_PIN_PD27;  /* 故障灯 */
    pled->st_pin.led_pin_can5= AT91_PIN_PA29;   /* CAN5灯 */
    pled->st_pin.led_pin_can6= AT91_PIN_PA6;    /* CAN6灯 */

    //加了互斥锁,只能同时被一个应用程序调用
    //printk("led_pin:green:%d\n",pwdt->wdg_pin);
    mutex_init(&(pled->led_mudex));
    //pwdt->open_count = ATOMIC_INIT(0);//初始化为0

    //分配主设备号,注册字符驱动
    if (led_major) {
   
        dev_id = MKDEV(led_major, 0);
        retval = register_chrdev_region(dev_id, MAX_LED_NB,
                        LED_NAME);
    } else {
   
        retval = alloc_chrdev_region(&dev_id, 0, MAX_LED_NB,
                         LED_NAME);
        led_major = MAJOR(dev_id);
    }
    if(retval<0)
    {
   
        printk("led: register error!\n");
        goto error_malloc;
    }
    else
        printk("led:led_major:%d\n",led_major); 

        //绑定操作方法at91_led_fops
    cdev_init(&(pled->led_dev), &at91_led_fops);
    retval = cdev_add(&(pled->led_dev), dev_id,MAX_LED_NB);
    if(retval<0)
    {
   
        printk("led:cdev_add failed!!!\n");
        goto error_reg;
    }

    //创建类
    pled->led_class = class_create(
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值