Linux字符设备驱动程序开发(4)-LED驱动程序设计

这里编写一个LED内核驱动代码、流程大概如下:

  • 1、实现一个内核模块。
  • 2、添加字符设备驱动框架。
  • 3、在字符设备驱动中实现open和ioctl函数。
  • 4、编写应用程序。
  • led.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/io.h>
#include "led.h"

/* 这里是mini2440板子上led对应io口的寄存器地址 */
#define GPBCON 0x56000010
#define GPBDAT 0x56000014

unsigned int *led_config;
unsigned int *led_data;

struct cdev led_cdev;// 分配cdev
dev_t led_devno;   // led设备号

/*led_open函数*/
int led_open(struct inode *inode, struct file *filp)
{
	//配置led的io口状态
	//如果在逻辑程序中可以直接给寄存器赋值,但是linux内核中不行
	//led_config = GPBCON;
	//*led_config = 0x400;

	led_config = ioremap(GPBCON, 4);  // 先把物理地址映射成虚拟地址
	writel(0x15400, led_config);

	led_data = ioremap(GPBDAT, 4);

	return 0;
}

/*led设备操作函数*/
long led_ioctl(struct file *filp, unsigned int cmd, unsigned int arg)
{
	switch (cmd)
	{
		case LED1_ON:
			writel(0x1c0, led_data);
			return 0;
		case LED2_ON:
			writel(0x1a0, led_data);
			return 0;
		case LED3_ON:
			writel(0x160, led_data);
			return 0;
		case LED4_ON:
			writel(0xe0, led_data);
			return 0;
		case LED_OFF:
			writel(0x1ff, led_data);
			return 0;
		default:
			return -EINVAL;
	}
}
/*文件操作结构体*/
static const struct file_operations led_fops =
{
	.open = led_open,
	.unlocked_ioctl = led_ioctl,
};

static int led_init(void)
{
	//初始化cdev
	cdev_init(&led_cdev, &led_fops);

	//注册cdev
	alloc_chrdev_region(&led_devno, 0, 1, "myled");  // 动态分配主设备号(次设备号从0开始,只有1个设备),设备名称"myled"
	cdev_add(&led_cdev, led_devno, 1);

	//硬件初始化,可以放在这里,也可以放在open函数
	return 0;
}

static void led_exit(void)
{
	cdev_del(&led_cdev); /*注销设备*/
	unregister_chrdev_region(led_devno, 1); /*释放设备号*/
}

MODULE_LICENSE("GPL");

module_init(led_init);
module_exit(led_exit);
  • led.h
#define LED_MAGIC 'M'  // 定义幻数
#define LED1_ON _IO(LED_MAGIC, 0)
#define LED2_ON _IO(LED_MAGIC, 1)
#define LED3_ON _IO(LED_MAGIC, 2)
#define LED4_ON _IO(LED_MAGIC, 3)
#define LED_OFF _IO(LED_MAGIC, 4)
  • led_app.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "led.h"

int main(int argc, char *argv[])
{
    int fd;
    int cmd;
    
    if (argc < 2)
    {
        printf("please enter the second para!\n");
        return 0;
    }
    
    cmd = atoi(argv[1]); //将字符串转化为整数
    
    fd = open("/dev/myled", O_RDWR);	
    
	if (cmd == 1)
		ioctl(fd, LED1_ON);
	else if (cmd == 2)
		ioctl(fd, LED2_ON);
	else if (cmd == 3)
		ioctl(fd, LED3_ON);
	else if (cmd == 4)
		ioctl(fd, LED4_ON);
	else if (cmd == 0)
		ioctl(fd, LED_OFF);
    	
     return 0;
}
  • Makefile
​
obj-m := led.o

KDIR := /home/S4_a/part3/lesson3/lesson-2440/linux-mini2440

all :
	make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm

clean:
	rm -f *.ko *.o *.order *.symvers
  • 编译模块及应用程序:
    • #make
    • #arm-linux-gcc led_app.c -o led_app
    • 把led.ko和led_app拷贝到开发板中
  • 安装模块:
    • #insmod led.ko
  • 查看主设备号:
    • #cat /proc/device
  • 创建设备文件:
    • #mknod  /dev/myled c 253 0
  • 测试led:
    • #./led_app 0
    • #./led_app 1
    • #./led_app 2
    • #./led_app 3
    • #./led_app 4

猜你喜欢

转载自blog.csdn.net/qq_22847457/article/details/91369935