最简单的LED驱动程序

具体框图

在这里插入图片描述
应用层使用 open write 函数,驱动层提供自己的 open write 即可

  1. 便于管理,使用 file_operations 来管理相关函数
  2. 通过 register_chrdev 通知内核
  3. 入口
  4. 出口
    在这里插入图片描述

具体代码如下

驱动代码(led_drv.c)
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>

static int major = 0;
static struct class *led_class;

// registers
// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3; 

// GPIO5_GDIR 地址:0x020AC004
static volatile unsigned int *GPIO5_GDIR;

//GPIO5_DR 地址:0x020AC000
static volatile unsigned int *GPIO5_DR;

static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
    char val;
    int ret;
    // copy_from_user : get data from app
    ret = copy_from_user(&val, buf, 1);

    // to set gpio register: out 1/0
    if (val)
    {
        /* set gpio to let led on */
        *GPIO5_DR &= ~(1<<3);
    }
    else
    {
        /* set gpio to let led off */
        *GPIO5_DR |= (1<<3);
    }
    return 1;
}

static int led_open(struct inode *inode, struct file *filp)
{
    /* enable gpio5
	 * configure gpio5_io3 as gpio
	 * configure gpio5_io3 as output 
	 */
    *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;
    *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;
    *GPIO5_GDIR |= (1<<3);

    return 0;
}

static struct file_operations led_fops = {
    .owner		= THIS_MODULE,
	.write		= led_write,
	.open		= led_open,
};

// 入口函数
static int __init led_init(void)
{
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	major = register_chrdev(0, "xiaodengled", &led_fops);

    // ioremap 不能直接使用寄存器的物理地址,必须使用ioremap 映射得到一个虚拟地址
    // registers
    // IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
    IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14, 4);

    // GPIO5_GDIR 地址:0x020AC004
    GPIO5_GDIR = ioremap(0x020AC004, 4);

    //GPIO5_DR 地址:0x020AC000
    GPIO5_DR = ioremap(0x020AC000, 4);

    led_class = class_create(THIS_MODULE, "myled");
    device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); // /dev/myled

	return 0;
}

// 出口函数
static void __exit led_exit(void)
{
    iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
    iounmap(GPIO5_GDIR);
    iounmap(GPIO5_DR);

    device_destroy(led_class, MKDEV(major, 0));
    class_destroy(led_class);
	unregister_chrdev(major, "xiaodengled");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
测试代码(ledtest.c)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

// ledtest /dev/myled on
// ledtest /dev/myled off

int main(int argc, char **argv)
{
    int fd;
    char status = 0;
    if(argc != 3)
    {
        printf("Usage: %s <dev> <on|off>\n", argv[0]);
		printf("  eg: %s /dev/myled on\n", argv[0]);
		printf("  eg: %s /dev/myled off\n", argv[0]);
        return -1;
    }
    // open
    fd = open(argv[1], O_RDWR);
    if (fd < 0)
    {
        printf("can not open %s\n", argv[0]);
		return -1;
    }

    // write
    if(strcmp(argv[2], "on") == 0)
    {
        status = 1;
    }
    write(fd, &status, 1);
    return 0;
}
编译后的具体操作
  1. insmod led_drv.ko
  2. cat /proc/devices
  3. lsmod
  4. ls /dev/myled -l
  5. dmesg | grep led_drv.c
应用程序的用法

板子没有操作 led 的效果图
在这里插入图片描述
点灯:./ledtest /dev/myled on
在这里插入图片描述
熄灯:./ledtest /dev/myled off
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值