first linux kernel driver
Reference:
preparation
- get kernel version from
uname -r
. - find real KERNELDIR (in Makefile), for kernel module programming.
- if
/lib/module/build
doesn't exist, look for/usr/src/linux-*
- files may not be ready from board
apt-get install linux-source
apt-get install linux-headers
development
- Kirin 620 SoC uses address-select to enable pin.
- write 0xF to GPIODIR to confirm 4-pin output mode.
- modify Makefile according to environment
- after successfully generate *.ko, look for the device in
/dev
, and its privileges if complaining "can't find device",sudo chmod 777 device
. - "MODULE_LICENSE("GPL");" the different license may differ the compilation result.
demo:
#define BASE_ADDR 0xF7020000
#define OFFSET 0x03FC (to enable GPIO4_0 to GPIO 4_7)
unsigned long *paddr = NULL;
unsigned long *vaddr = NULL;
paddr = (unsigned long*)BASE_ADDR + OFFSET;
vaddr = (long *)(volatile unsigned long *)ioremap(paddr, 0x10);
int temp = 0xF;(to pull GPIO4_0 to GPIO4_3 to HIGH)
iowrite32(vaddr, temp);
/*
* *vaddr = temp might be complained "segmentation fault" in ARMv8 64bit compiler.
* to be safe, use I/O function instead.
*/
source code
hikey_led(.ko)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
static struct class *sun8i_opizero_led_class;
//STATUS-LED:LED901-904, USER_LED4_GPIO4_0 to GPIO4_3
#define PIO_BASE 0xF7020000
#define PIO_OFFSET 0x3FC
#define PIO_DIR 0xF7020400
volatile unsigned long *pacfg[2] = {NULL};
static int sun8i_opizero_led_open(struct inode *inode, struct file *file)
{
//configure GPIO4_0 to GPIO4_3 to output mode
*pacfg[1] |= 0xF;
return 0;
}
static ssize_t sun8i_opizero_led_write(struct file *file, const int __user *buf, size_t count, loff_t *ppos)
{
int val = 0;
unsigned int temp = 0;
//get user input
copy_from_user(&val, buf, count);
if (val == 1) {
//*pacfg[0] |= 0xF;
temp = ioread32(pacfg[0]);
temp |= 0xF;
iowrite32(temp, pacfg[0]);
}
else {
//*pacfg[0] &= 0;
temp = ioread32(pacfg[0]);
temp &= 0xF0;
iowrite32(temp, pacfg[0]);
}
return 0;
}
static struct file_operations sun8i_opizero_led_fops = {
.owner = THIS_MODULE,
.open = sun8i_opizero_led_open,
.write = sun8i_opizero_led_write,
};
int major;
int sun8i_opizero_led_init(void)
{
major = register_chrdev(0, "hikey_led_4_3", &sun8i_opizero_led_fops);
sun8i_opizero_led_class = class_create(THIS_MODULE, "hikey_led_4_3");
device_create(sun8i_opizero_led_class, NULL, MKDEV(major, 0), NULL, "hikey_led_4_3");
pacfg[0] = (volatile unsigned long *)ioremap(PIO_BASE+PIO_OFFSET, 0x10);
pacfg[1] = (volatile unsigned long *)ioremap(PIO_DIR, 0x10);
printk(KERN_ALERT "HELLO LOADED!\n");
return 0;
}
static void sun8i_opizero_led_exit(void)
{
unregister_chrdev(major, "hikey_led_4_3");
device_destroy(sun8i_opizero_led_class, MKDEV(major, 0));
class_destroy(sun8i_opizero_led_class);
iounmap(pacfg[0]);
iounmap(pacfg[1]);
printk(KERN_ALERT "BYE MODULE!\n");
}
module_init(sun8i_opizero_led_init);
module_exit(sun8i_opizero_led_exit);
MODULE_DESCRIPTION("LED driver");
MODULE_AUTHOR("Anonymous");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:hikey-620");
led_test
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int fd, val = 1;
fd = open("/dev/hikey_led_4_3", O_RDWR);
if (fd < 0)
printf("can't open led device\n");
if (argc != 2) {
printf("Usage:\n");
printf("%s <on|off>\n", argv[0]);
return 1;
}
if (strcmp(argv[1], "on") == 0)
val = 1;
else
val = 0;
write(fd, &val, 4);
return 0;
}
Makefile
obj-m := hikey_led.o #编译进模块
#KERNELDIR := /lib/modules/3.18.0-linaro-hikey/build #此处为linux内核库目录
KERNELDIR := /usr/src/linux-headers-3.18.0-linaro-hikey
PWD := $(shell pwd) #获取当前目录
OUTPUT := $(obj-m) $(obj-m:.o=.ko) $(obj-m:.o=.mod.o) $(obj-m:.o=.mod.c) modules.order Module.symvers
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf $(OUTPUT)
environment
- Hikey 620 board
- Linaro Debian image (hikey-jessie_alip_20151130-387-8g.emmc.img), kernel: 3.18.0
- on-board compile and program
- A53 power is great but the board sucks (HDMI unstable, wifi unstable)
原作者的四空格缩进好痛苦然而我又懒得改...
Comments