Fork Me on GitHub

源码开放学ARM

LASO - Learn ARM with Source Open

首页         目录索引         资料下载         代码下载         联系作者        
下载PDF打印版本

内核模块驱动代码实现

write led.c

#include <linux/module.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("limingth");
MODULE_DESCRIPTION("led module driver");
MODULE_VERSION("version1.0");
MODULE_ALIAS("myled test");

static int * vmem;
static int led_no = 0;
module_param(led_no, int, 0);

static __init int led_init(void)
{
	printk("led init ok!\n");

//	*(int *)0xe0200284 = 0x0;
	vmem = ioremap(0xe0200284, 4);
	printk("vmem = %p\n", vmem);
//	*vmem = 0x0;
	*vmem &= ~(1 << led_no);

	return 0;
}

static __exit void led_exit(void)
{
	printk("led exit ok!\n");

//	*(int *)0xe0200284 = 0xf;
	*vmem = 0xf;

	return;
}

module_init(led_init);
module_exit(led_exit);

write a Makefile to compile

obj-m := led.o

KDIR := /home/akaedu/teacher_li/linux-2.6.35.7

all:
	make modules -C $(KDIR) SUBDIRS=$(PWD)

clean:
	-rm *.ko *.o *.order *.mod.c *.symvers

第 1 行
定义生成模块的名称。没有特殊约定时,hello.c 将会成为编译成 hello.c 的源代码文件。

第 3 行
指定内核源代码的位置

第 4 行
指定编译对象模块源代码所在位置的当前目录。

第 7 行
指定编译模块的命令。

第 8 行
利用编译结果清除所有的生成文件。

编译后,会生成许多文件,2.6 内核中生成的模块实际名称为 hello.ko , 也可以使用 hello.o 。

compile and test it

make 
make V=1 (verbose)
insmod led.ko led_no=3
rmmod led

GPIO

/* gpio_drv.c */
#include <linux/module.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");

static int * vmem_led;
static int * vmem_buzzer_con;
static int * vmem_buzzer;
static int * vmem_btn;

void delay(void)
{
	/* tell compiler: do not optimize */
	volatile int i;

	for (i = 0; i < 10000000; i++)
		;
}

void led_blink(int n)
{
	int i;

	for (i = 0; i < n; i++)
	{
		*vmem_led = 0xF;
		delay();
		
		*vmem_led = 0x0;
		delay();
	}
}

void buzzer_beep(int n)
{
	int i;

	for (i = 0; i < n; i++)
	{
		*vmem_buzzer = 0x1;
		delay();
		
		*vmem_buzzer = 0x0;
		delay();
	}
}

int btn_get_id(void)
{
	int i;

	for (i = 0; i < 4; i++)
	{
		if ((*vmem_btn & (1<<i)) == 0)
			return i+1;
	}
		
	return 0; 
}

void init_all(void)
{
	vmem_led = ioremap(0xe0200284, 4);
	vmem_buzzer_con = ioremap(0xe02000A0, 4);
	vmem_buzzer = ioremap(0xe02000A4, 4);
	vmem_btn = ioremap(0xe0200C44, 4);

	/* set GPIO CON = output 0001 */
	*vmem_buzzer_con = 0x1;
}

EXPORT_SYMBOL(init_all);
EXPORT_SYMBOL(led_blink);
EXPORT_SYMBOL(buzzer_beep);
EXPORT_SYMBOL(btn_get_id);

/* gpio_test.c */
#include <linux/module.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("limingth");
MODULE_DESCRIPTION("led module driver");
MODULE_VERSION("version1.0");
MODULE_ALIAS("myled test");

#if 1
extern void led_blink(int n);
extern void buzzer_beep(int n);
extern int btn_get_id(void);
extern void init_all(void);
#endif

static __init int gpio_init(void)
{
	int btn_id;

	printk("gpio init ok!\n");

	init_all();

	while (1)
	{
		btn_id = btn_get_id();

		led_blink(btn_id);

		buzzer_beep(btn_id);
	
		if (btn_id == 4)
			break;
	}

	printk("finished!\n");

	return 0;
}

static __exit void gpio_exit(void)
{
	printk("gpio exit ok!\n");

	return;
}

module_init(gpio_init);
module_exit(gpio_exit);

compile

$ make obj-m=gpio_test.o 
$ make obj-m=gpio_drv.o

Exercise

/* uart.c */
	
#include <linux/module.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("limingth");
MODULE_DESCRIPTION("uart module driver");
MODULE_VERSION("version1.0");
MODULE_ALIAS("myuart test");

struct uart_sfr
{
	int ulcon;
	int ucon;
	int ufcon;
	int umcon;
	int utrstat;
	int uerstat;
	int ufstat;
	int umstat;
	int utxh;
	int urxh;
	int ubrdiv;
	int udivslot;
};

typedef struct uart_sfr USFR;

static volatile USFR *puart;

int uart_putchar(char c)
{
	while ((puart->utrstat & (1<<2)) == 0)
		;

	puart->utxh = c;

	return 0;
}

char uart_getchar(void)
{
	char c;

	while ((puart->utrstat & (1<<0)) == 0)
		;

	c = puart->urxh;

	return c;
}

void uart_init(void)
{
	puart = ioremap(0xe2900c00, sizeof(USFR));
	puart->ulcon = 0x3;
	puart->ucon = 0x7c5;
	puart->ubrdiv = 0x23;
	puart->udivslot = 0x808;
}

static __init int uart_mod_init(void)
{
	printk("uart module init ok!\n");

	uart_init();

	while (1)
	{
		char ch;
		
		ch = uart_getchar();

		uart_putchar(ch);

		if (ch == 'q')
			break;
	}

	printk("finished!\n");

	return 0;
}

static __exit void uart_mod_exit(void)
{
	printk("uart module exit ok!\n");

	return;
}

module_init(uart_mod_init);
module_exit(uart_mod_exit);

上一节 | 目录索引 | 下一节

blog comments powered by Disqus