1. 概述
介绍在linux环境下编写内核模块Makefile和应用程序Makefile的方法
2. 环境linux-2.4内核
Makefile文件内容:
########################################################################
KDIR = /usr/src/linux
LIB = -I$(KDIR)/include
CFLAGS = -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer $(LIB)
MOD = -D__KERNEL__ -DMODULE
all:
clean:
########################################################################
KDIR = /usr/src/linux
定义宏,指定linux源码目录
LIB = -I$(KDIR)/include
-I表示依赖的宏定义文件,$(KDIR)调用了KDIR这个宏
CFLAGS = -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer $(LIB)
定义了编译变量
MOD = -D__KERNEL__ -DMODULE
编译内核模块时需要加入的编译变量
all:
表示如果所依赖的文件netlink_service.c有更新的话,再次编译时就重编,如果没有更新,不重新编译
gcc $(CFLAGS) $(MOD) -o netlink_service.o
用以上设置的条件编译内核模块netlink_service.c,生成内核模块netlink_service.o
gcc $(CFLAGS) -o netlink_clinet.o netlink_client.c
用以上设置的条件编译应用程序netlink_client.c,生成应用程序netlink_client.o
clean:
表示运行命令make clean时,删除所有的.o文件
3. 环境linux-2.6内核
linux-2.6内核下编译内核模块,需要内核源码树的支持,而且是编译过的。
先下载linux-2.6.26内核源码,解压缩后编译,目录在/usr/local/x86/linux/
Makefile文件内容:
########################################################################
ARCH ?= i386
ifeq ("$(ARCH)", "i386")
KDIR := /usr/local/x86/linux/
else
KDIR := ../../linux
endif
ifneq ($(KERNELRELEASE),)
obj-m := sys_reset.o
sys_reset-objs := sys_reset26.o
else
PWD:= $(shell pwd)
default:
clean:
install:
endif
########################################################################
有些部分与linux-2.4内核相同
ARCH ?= i386
ifeq ("$(ARCH)", "i386")
KDIR := /usr/local/x86/linux/
else
KDIR := ../../linux
endif
指定宏KDIR,指向内核源码树
ifneq ($(KERNELRELEASE),)
else
endif
两次编译,首先进行的else部分
default:
这时make命令会再次使用这个Makefile文件进行编译。
再次编译时,就会进入if部分
obj-m := sys_reset.o
指定要编译的内核模块,sys_reset.o
sys_reset-objs := sys_reset26.o
指定内核模块sys_reset.o所依赖的文件sys_reset26.o
过程就是sys_reset26.c -> sys_reset26.o -> sys_reset.o
这里可以依赖多个文件
install:
运行命令make install时所做的操作
2.6内核的应用程序编译和2.4基本一样,不再赘述。
4. 试验文件源代码
4.1 netlink_service.c
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/mii.h>
#include <linux/socket.h>
#include <linux/cache.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <linux/netlink.h>
#include <linux/sched.h>
#include <net/sock.h>
#define NETLINK_TEST 22
struct sock *nl_sk = NULL;
static void nl_data_ready (struct sock *sk, int len)
{
wake_up_interruptible(sk->sleep);
}
static void netlink_test(void)
{
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh = NULL;
int err;
u32 pid;
nl_sk = netlink_kernel_create(NETLINK_TEST, nl_data_ready);
skb = skb_recv_datagram(nl_sk, 0, 0, &err);
nlh = (struct nlmsghdr *)skb->data;
printk("%s: received netlink message payload:%s ", __FUNCTION__, (char *)NLMSG_DATA(nlh));
pid = nlh->nlmsg_pid;
NETLINK_CB(skb).groups = 0;
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_pid = pid;
NETLINK_CB(skb).dst_groups = 0;
netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
sock_release(nl_sk->socket);
}
int __init reset_module_init(void)
{
netlink_test();
}
void __exit reset_module_clearnup(void)
{
if (nl_sk != NULL) {
sock_release(nl_sk->socket);
}
printk("net_link: remove ok.\n");
}
MODULE_LICENSE("GPL");
module_init(reset_module_init);
module_exit(reset_module_clearnup);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/netlink.h>
#define MAX_PAYLOAD 1024
#define NETLINK_TEST 22
struct sockaddr_nl src_addr, dest_addr;
struct msghdr msg;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
int main(void)
{
sock_fd = socket(PF_NETLINK, SOCK_RAW,NETLINK_TEST);
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups = 0;
bind(sock_fd, (struct sockaddr*)&src_addr,sizeof(src_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0;
dest_addr.nl_groups = 0;
nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid();
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), "Hello you!");
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("sendmsg ...\n");
sendmsg(sock_fd, &msg, 0);
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
printf("recvmsg ...\n");
recvmsg(sock_fd, &msg, 0);
printf(" Received message payload: %s ", (char *)NLMSG_DATA(nlh));
close(sock_fd);
return 0;
}
4.3 sys_reset26.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <linux/pci.h>
#define GPIO_PORT 0x480//ICH GPIO base address
#define INDEX_PORT 0x2e
#define DATA_PORT 0x2f
#define BANK_REG 0x07
#define LDN8 0x08
#define LDN9 0x09
#define NETLINK_TEST 21
static unsigned long timestamp1, timestamp2;
static struct timer_list timer;
static DECLARE_WAIT_QUEUE_HEAD (reset_wait);
static int board_num = 0;
struct sock *nl_sk = NULL;
EXPORT_SYMBOL_GPL(nl_sk);
static void nl_data_ready (struct sk_buff *__skb)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
u32 pid;
int rc;
if (__skb->len < sizeof(*nlh))
return;
skb = skb_get(__skb);
nlh = nlmsg_hdr(skb);
pid = nlh->nlmsg_pid;
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_group = 0;
while(1) {
interruptible_sleep_on(&reset_wait);
if((timestamp2 - timestamp1) < 2*HZ) {
strcpy(NLMSG_DATA(nlh), "reset0");
}
else if((timestamp2 - timestamp1) < 5*HZ) {
strcpy(NLMSG_DATA(nlh), "reset2");
}
else {
strcpy(NLMSG_DATA(nlh), "reset5");
}
rc = netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
if (rc < 0) {
printk(KERN_ERR "net_link: can not unicast skb (%d)\n", rc);
}
}
return;
}
static void entry_config(void)
{
outb(0x87, INDEX_PORT);
mdelay(1);
outb(0x87, INDEX_PORT); //Entering W83627HF Configuration
}
static void exit_config(void)
{
outb(0xAA, INDEX_PORT); //exit config
}
//;Write SuperIO register
static int read_w83627_reg(int LDN, int reg)
{
entry_config();
outb(0x07, INDEX_PORT); //LDN register
mdelay(1);
outb(LDN, DATA_PORT);
mdelay(1);
outb(reg, INDEX_PORT);
mdelay(1);
return inb(DATA_PORT);
exit_config();
}
static void write_w83627_reg(int LDN, int reg, int value)
{
entry_config();
outb(0x07, INDEX_PORT); //LDN register
mdelay(1);
outb(LDN, DATA_PORT);
mdelay(1);
outb(reg, INDEX_PORT);
mdelay(1);
outb(value, DATA_PORT);
exit_config();
}
static void init_gpio25(void)
{
write_w83627_reg(LDN9,0x30, 0x02); //enable function
write_w83627_reg(LDN9,0xE4,(read_w83627_reg(LDN9,0xE4) | (0x20))); // set GPOIO 25 = input // //enable function
}
static void initial_gpio(void)
{
int aaa;
aaa = inb(GPIO_PORT + 0x30);
aaa = aaa | 0x2; //;enable GPIO33
outb(aaa, GPIO_PORT + 0x30);
aaa = inb(GPIO_PORT + 0x34); //; GPIO33 set as GPI33
aaa = aaa | 0x2;
outb(aaa, GPIO_PORT + 0x34);
}
static int get_gpio_input_value(void)//Read GPI33 value
{
int temp;
if (board_num == 1)
{
temp = inb(GPIO_PORT + 0x38);
temp &= 0x2;
}
else if (board_num == 2)
{
temp = read_w83627_reg(LDN9,0xE5); //;read 0xf1[6] for GPI25
temp &= 0x20;
}
else
{
printk("can not support this board!\n");
return -1;
}
return temp;
}
static int get_board_num(void)
{
if( pci_find_device(0x8086, 0x2590, NULL) && pci_find_device(0x8086, 0x2591, NULL) && pci_find_device(0x8086, 0x2592, NULL) && pci_find_device(0x8086, 0x10D3, NULL))
return 1;
if( pci_find_device(0x8086, 0x27ac, NULL) && pci_find_device(0x8086, 0x27b9, NULL) && pci_find_device(0x8086, 0x27c9, NULL) && pci_find_device(0x8086, 0x27da, NULL))
return 2;
return -1;
}
static void timer_get_gpio_state(unsigned long p)
{
int input_value;
if (board_num == 1)
{
initial_gpio();
}
else if (board_num == 2)
{
init_gpio25();
}
timestamp1 = jiffies;
while ((input_value = get_gpio_input_value()) == 0x0);
timestamp2 = jiffies;
if((timestamp2 - timestamp1) < 2*HZ);
else if((timestamp2 - timestamp1) < 5*HZ)
{
printk("reset = 2\n");
}
else
{
printk("reset = 5\n");
}
mod_timer(&timer, jiffies + HZ/10);
wake_up_interruptible(&reset_wait);
}
static int reset_netlink_startup(void)
{
board_num = get_board_num();
if (board_num == 1) {
printk("this is board A\n");
}
else if (board_num == 2) {
printk("this is board B\n");
}
else {
printk("can not support this board!\n");
return -1;
}
init_timer(&timer);
timer.data = 1;
timer.expires = jiffies + HZ/10;
timer.function = (void (*)(unsigned long)) timer_get_gpio_state;
add_timer(&timer);
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 0, nl_data_ready, NULL, THIS_MODULE);
if (!nl_sk) {
printk(KERN_ERR "net_link: Cannot create netlink socket.\n");
goto err;
}
printk("net_link: create socket ok.\n");
return 0;
err:
del_timer(&timer);
if(nl_sk)
sock_release(nl_sk->sk_socket);
return -1;
}
int __init reset_module_init(void)
{
int res;
res = reset_netlink_startup();
return res;
}
void __exit reset_module_clearnup(void)
{
if (nl_sk != NULL) {
sock_release(nl_sk->sk_socket);
}
printk("net_link: remove ok.\n");
}
MODULE_LICENSE("GPL");
module_init(reset_module_init);
module_exit(reset_module_clearnup);PS: Makefile中可以使用正则表达式来简化和提高通用性,本文中的代码都是关于netlink方面的,均经过调试。
原文:http://blog.csdn.net/moon146/article/details/19915881