这里编写一个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