Android平台的驱动编译跟普通的linux驱动编写有一点区别,主要区别在Makefile文件(需要交叉编译),这里以hello.c文件为例
#include <linux/module.h>
static int __init hello_init(void)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
如果是普通的linux驱动,Makefile的写法为
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /usr/src/linux-headers-4.4.0-24-generic/
PWD :=$(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers
.PHONY: modules modules_install clean
else
obj-m:= hello.o
endif
对于Android平台,Makefile的内容为
ifeq ($(KERNELRELEASE),)
KERNELDIR_OUT ?= Android源码路径/kernel
CROSS_COMPILE ?= Android源码路径/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
PWD :=$(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR_OUT) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers
.PHONY: modules modules_install clean
else
obj-m:= hello.o
endif
对于某些平台(qcom或者mtk),所有的生成文件都放在了Android源码的out目录下,所有内核源码路径要改成( Android源码根路径/out/target/product/具体cpu/obj/KERNEL_OBJ),对于64系统,要将ARCH=arm改成ARCH=arm64。其实,路径具体怎么填,参考编译源码时的打印信息即可,如
make -C kernel-3.18 O=/Android源码根路径/out/target/product/xxxx/obj/KERNEL_OBJ
ARCH=arm64 CROSS_COMPILE=/Android源码根路径/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-
ROOTDIR=/home/w/xxx modules
或者在device目录下找下KERNEL_CROSS_COMPILE的定义,如
ifeq ($(TARGET_KERNEL_ARCH), arm64)
KERNEL_CROSS_COMPILE = $(ANDROID_BUILD_TOP)/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-
endif
ifeq ($(TARGET_KERNEL_ARCH), arm)
KERNEL_CROSS_COMPILE = $(ANDROID_BUILD_TOP)/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
endif
如果驱动模块由多个c文件组成,Makefile的编写如下
ifeq ($(KERNELRELEASE),)
KERNELDIR_OUT ?= /home/w/M8974AAAAANLYD4275/out/target/product/msm8974/obj/KERNEL_OBJ
CROSS_COMPILE ?= /home/w/M8974AAAAANLYD4275/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
PWD := $(shell pwd)
modules: #编译为驱动模块
$(MAKE) -C $(KERNELDIR_OUT) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
modules_install:
$(MAKE) -C $(KERNELDIR_OUT) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers
.PHONY: modules modules_install clean
else
GT9xx_CORE_OBJS := gt9xx.o #指定驱动模块的核心文件(有init 和 exit)
GT9xx_OTHER_OBJS := goodix_tool.o gt9xx_update.o #依赖文件
touchscreen-objs := $(GT9xx_CORE_OBJS) $(GT9xx_OTHER_OBJS) #xxx-objs := 指定驱动模块的所有依赖文件
obj-m := touchscreen.o #最终由xxx-objs链接生成touchscreen.o,再生成touchscreen.ko
endif
如果要多个c文件分别编译成相应的驱动,Makefile的编写如下
ifeq ($(KERNELRELEASE),)
KERNELDIR_OUT ?= /home/w/M8974AAAAANLYD4275/out/target/product/msm8974/obj/KERNEL_OBJ
CROSS_COMPILE ?= /home/w/M8974AAAAANLYD4275/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
PWD :=$(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR_OUT) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers app
.PHONY: modules modules_install clean
else
obj-m+= notifier_chain.o
obj-m+= consumer.o
obj-m+= producer.o
endif