LINUX学习笔记:(2)编写驱动模块
宿主机 : 虚拟机 Ubuntu 16.04 LTS / X64
目标板[底板]: Tiny4412SDK - 1506
目标板[核心板]: Tiny4412 - 1412
LINUX内核: 4.12.0
交叉编译器: arm-none-linux-gnueabi-gcc(gcc version 4.8.3 20140320)
日期: 2018-2-28 19:35:35
作者: SY
简介
本章节主要介绍如何编写驱动模块运行在基于 ARM
的 Linux
上。模块可以在运行期间手动安装、卸载,具有即插即用的好处!
APP
led.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
/* 平台头文件 */
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#define DEVICE_NAME "LED"
/* 配置IO端口 */
static unsigned int gpio_table[] = {
EXYNOS4X12_GPM4(0),
EXYNOS4X12_GPM4(1),
EXYNOS4X12_GPM4(2),
EXYNOS4X12_GPM4(3),
};
#define LED_NUMS ARRAY_SIZE(gpio_table)
/* LED操作方法 */
#define CMD_LED_OPEN (0)
#define CMD_LED_CLOSE (1)
static long led_device_ioctl( struct file *filp, unsigned int cmd,
unsigned long arg )
{
if (arg >= LED_NUMS)
{
return -EINVAL;
}
switch ( cmd )
{
case CMD_LED_OPEN:
gpio_set_value(gpio_table[arg], CMD_LED_OPEN);
break;
case CMD_LED_CLOSE:
gpio_set_value(gpio_table[arg], CMD_LED_CLOSE);
break;
default:
return -EINVAL;
}
return 0;
}
static struct file_operations led_device_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = &led_device_ioctl,
};
/**
* 模块归属为misc设备,所有的misc设备共享同一个主设备号
* 次设备号为MISC_DYNAMIC_MINOR,表示由系统自动分配
*/
static struct miscdevice led_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &led_device_fops,
};
static int __init led_device_init( void )
{
int ret,i;
printk("led register!\n");
for (i=0; i<LED_NUMS; ++i)
{
/**
* 由于开发板已经配置过GPIO,因此不能再请求该端口
*/
/*
ret = gpio_request(gpio_table[i], "led");
if (ret)
{
printk("请求gpio端口失败!\n");
return ret;
}
*/
s3c_gpio_cfgpin(gpio_table[i], S3C_GPIO_OUTPUT);
gpio_set_value(gpio_table[i], CMD_LED_CLOSE);
}
ret = misc_register(&led_dev);
return ret;
}
module_init(led_device_init);
static void __exit led_device_exit( void )
{
//int i;
printk("led deregister!\n");
/*
for (i=0; i<LED_NUMS; ++i)
{
gpio_free(gpio_table[i]);
}
*/
misc_deregister(&led_dev);
}
module_exit(led_device_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SY");
MODULE_DESCRIPTION("LED Module");
MODULE_VERSION("1.0.0.0");
Makefile
Makefile
CROSS := arm-linux-
obj-m := bsp_led.o
KDIR := /lib/modules/3.5.0-FriendlyARM/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o *.ko *.mod.c *.temp_versions *.symvers *.order
编译
在驱动模块当前文件夹中执行:
$ make
即可生成内核模块 led.ko
。
模块加载
将模块拷贝到开发板中,加载模块:
$ insmod led.ko
$ led register!
列举模块
$ lsmod
删除模块
$ rmmod led.ko
$ led deregister!