您的位置:首页 > 移动开发

应用netlink的内核模块和应用程序Makefile编写

2014-02-25 15:24 555 查看
1. 概述介绍在linux环境下编写内核模块Makefile和应用程序Makefile的方法2. 环境linux-2.4内核Makefile文件内容:########################################################################KDIR = /usr/src/linuxLIB = -I$(KDIR)/includeCFLAGS = -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer $(LIB)MOD = -D__KERNEL__ -DMODULEall:    netlink_service.c        gcc $(CFLAGS) $(MOD) -o netlink_service.o  -c netlink_service.c        gcc $(CFLAGS) -o netlink_clinet.o netlink_client.cclean:        $(RM) -f *.o########################################################################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表示如果所依赖的文件netlink_service.c有更新的话,再次编译时就重编,如果没有更新,不重新编译gcc $(CFLAGS) $(MOD) -o netlink_service.o  -c netlink_service.c用以上设置的条件编译内核模块netlink_service.c,生成内核模块netlink_service.ogcc $(CFLAGS) -o netlink_clinet.o netlink_client.c用以上设置的条件编译应用程序netlink_client.c,生成应用程序netlink_client.oclean:        $(RM) -f *.o表示运行命令make clean时,删除所有的.o文件3. 环境linux-2.6内核linux-2.6内核下编译内核模块,需要内核源码树的支持,而且是编译过的。先下载linux-2.6.26内核源码,解压缩后编译,目录在/usr/local/x86/linux/Makefile文件内容:########################################################################ARCH ?= i386ifeq ("$(ARCH)", "i386")KDIR := /usr/local/x86/linux/elseKDIR := ../../linuxendififneq ($(KERNELRELEASE),)obj-m := sys_reset.osys_reset-objs := sys_reset26.oelsePWD:= $(shell pwd)default:        $(MAKE) -C $(KDIR) M=$(PWD) modulesclean:        rm -f *.o *.ko .*.mod.c .*.cmd *.mod.c *.o.p        rm -rf .tmp_versionsinstall:        cp *.ko /tftpboot/endif########################################################################有些部分与linux-2.4内核相同ARCH ?= i386ifeq ("$(ARCH)", "i386")KDIR := /usr/local/x86/linux/elseKDIR := ../../linuxendif指定宏KDIR,指向内核源码树ifneq ($(KERNELRELEASE),)elseendif两次编译,首先进行的else部分default:        $(MAKE) -C $(KDIR) M=$(PWD) modules这时make命令会再次使用这个Makefile文件进行编译。再次编译时,就会进入if部分obj-m := sys_reset.o指定要编译的内核模块,sys_reset.osys_reset-objs := sys_reset26.o指定内核模块sys_reset.o所依赖的文件sys_reset26.o过程就是sys_reset26.c -> sys_reset26.o -> sys_reset.o这里可以依赖多个文件install:        cp *.ko /tftpboot/运行命令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 22struct 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);
4.2 netlink_client.c
#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 22struct 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 21static 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 registerstatic int read_w83627_reg(int LDN, int reg){entry_config();outb(0x07, INDEX_PORT); //LDN registermdelay(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 registermdelay(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 functionwrite_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 GPIO33outb(aaa, GPIO_PORT + 0x30);aaa = inb(GPIO_PORT + 0x34);  //; GPIO33 set as GPI33aaa = 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 GPI25temp &= 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方面的,均经过调试。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Makefile netlink module app