一 添加驱动
petalinux-create -t modules --name ps-led --enable
lkmao@ubuntu:~/peta_prj/linuxPsBase/petalinux_bsp$ petalinux-create -t modules --name ps-led --enable
INFO: Create modules: ps-led
INFO: New modules successfully created in /home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/project-spec/meta-user/recipes-modules/ps-led
INFO: Enabling created component...
INFO: sourcing build environment
INFO: silentconfig rootfs
INFO: ps-led has been enabled
lkmao@ubuntu:~/peta_prj/linuxPsBase/petalinux_bsp$
cd project-spec/meta-user/recipes-modules/
lkmao@ubuntu:~/peta_prj/linuxPsBase/petalinux_bsp$ cd project-spec/meta-user/recipes-modules/
lkmao@ubuntu:~/peta_prj/linuxPsBase/petalinux_bsp/project-spec/meta-user/recipes-modules$ tree
.
└── ps-led
├── files
│ ├── COPYING
│ ├── Makefile
│ └── ps-led.c
├── ps-led.bb
└── README
2 directories, 5 files
lkmao@ubuntu:~/peta_prj/linuxPsBase/petalinux_bsp/project-spec/meta-user/recipes-modules$
当前ps-led.c的代码如下:
/* ps-led.c - The simplest kernel module.
* Copyright (C) 2013 - 2016 Xilinx, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
/* Standard module information, edit as appropriate */
MODULE_LICENSE("GPL");
MODULE_AUTHOR
("Xilinx Inc.");
MODULE_DESCRIPTION
("ps-led - loadable module template generated by petalinux-create -t modules");
#define DRIVER_NAME "ps-led"
/* Simple example of how to receive command line parameters to your module.
Delete if you don't need them */
unsigned myint = 0xdeadbeef;
char *mystr = "default";
module_param(myint, int, S_IRUGO);
module_param(mystr, charp, S_IRUGO);
struct ps_led_local {
int irq;
unsigned long mem_start;
unsigned long mem_end;
void __iomem *base_addr;
};
static irqreturn_t ps_led_irq(int irq, void *lp)
{
printk("ps-led interrupt\n");
return IRQ_HANDLED;
}
static int ps_led_probe(struct platform_device *pdev)
{
struct resource *r_irq; /* Interrupt resources */
struct resource *r_mem; /* IO mem resources */
struct device *dev = &pdev->dev;
struct ps_led_local *lp = NULL;
int rc = 0;
dev_info(dev, "Device Tree Probing\n");
/* Get iospace for the device */
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r_mem) {
dev_err(dev, "invalid address\n");
return -ENODEV;
}
lp = (struct ps_led_local *) kmalloc(sizeof(struct ps_led_local), GFP_KERNEL);
if (!lp) {
dev_err(dev, "Cound not allocate ps-led device\n");
return -ENOMEM;
}
dev_set_drvdata(dev, lp);
lp->mem_start = r_mem->start;
lp->mem_end = r_mem->end;
if (!request_mem_region(lp->mem_start,
lp->mem_end - lp->mem_start + 1,
DRIVER_NAME)) {
dev_err(dev, "Couldn't lock memory region at %p\n",
(void *)lp->mem_start);
rc = -EBUSY;
goto error1;
}
lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
if (!lp->base_addr) {
dev_err(dev, "ps-led: Could not allocate iomem\n");
rc = -EIO;
goto error2;
}
/* Get IRQ for the device */
r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!r_irq) {
dev_info(dev, "no IRQ found\n");
dev_info(dev, "ps-led at 0x%08x mapped to 0x%08x\n",
(unsigned int __force)lp->mem_start,
(unsigned int __force)lp->base_addr);
return 0;
}
lp->irq = r_irq->start;
rc = request_irq(lp->irq, &ps_led_irq, 0, DRIVER_NAME, lp);
if (rc) {
dev_err(dev, "testmodule: Could not allocate interrupt %d.\n",
lp->irq);
goto error3;
}
dev_info(dev,"ps-led at 0x%08x mapped to 0x%08x, irq=%d\n",
(unsigned int __force)lp->mem_start,
(unsigned int __force)lp->base_addr,
lp->irq);
return 0;
error3:
free_irq(lp->irq, lp);
error2:
release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
error1:
kfree(lp);
dev_set_drvdata(dev, NULL);
return rc;
}
static int ps_led_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ps_led_local *lp = dev_get_drvdata(dev);
free_irq(lp->irq, lp);
iounmap(lp->base_addr);
release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
kfree(lp);
dev_set_drvdata(dev, NULL);
return 0;
}
#ifdef CONFIG_OF
static struct of_device_id ps_led_of_match[] = {
{ .compatible = "vendor,ps-led", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, ps_led_of_match);
#else
# define ps_led_of_match
#endif
static struct platform_driver ps_led_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = ps_led_of_match,
},
.probe = ps_led_probe,
.remove = ps_led_remove,
};
static int __init ps_led_init(void)
{
printk("<1>Hello module world.\n");
printk("<1>Module parameters were (0x%08x) and \"%s\"\n", myint,
mystr);
return platform_driver_register(&ps_led_driver);
}
static void __exit ps_led_exit(void)
{
platform_driver_unregister(&ps_led_driver);
printk(KERN_ALERT "Goodbye module world.\n");
}
module_init(ps_led_init);
module_exit(ps_led_exit);
Makefile的代码:
obj-m := ps-led.o
MY_CFLAGS += -g -DDEBUG
ccflags-y += ${MY_CFLAGS}
SRC := $(shell pwd)
all:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC)
modules_install:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
clean:
rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
rm -f Module.markers Module.symvers modules.order
rm -rf .tmp_versions Modules.symvers
修改ps-led.c文件的代码如下:这是一个最简单的驱动代码,且是平台无关的。
#include <linux/module.h>
#include <linux/init.h>
#define DEBUG_INFO(format,...) printk(KERN_ERR"%s:%d"format"\n",\
__func__,__LINE__,##__VA_ARGS__)
static int __init ps_led_init(void)
{
DEBUG_INFO("init");
printk(KERN_NOTICE"KERN_NOTICE\n");
printk(KERN_WARNING"KERN_WARNING\n");
return 0;
}
static int __exit ps_led_exit(void)
{
DEBUG_INFO("init");
}
module_init(ps_led_init);
module_exit(ps_led_exit);
MODULE_LICENSE("GPL");
在工程目录执行petalinux-build:
lkmao@ubuntu:~/peta_prj/linuxPsBase/petalinux_bsp$ petalinux-build
INFO: sourcing build tools
[INFO] building project
[INFO] sourcing build environment
[INFO] generating user layers
[INFO] generating workspace directory
INFO: bitbake petalinux-image-minimal
Loading cache: 100% |#############################################################################################| Time: 0:00:00
Loaded 4228 entries from dependency cache.
Parsing recipes: 100% |###########################################################################################| Time: 0:00:04
Parsing of 2962 .bb files complete (2959 cached, 3 parsed). 4231 targets, 168 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
Initialising tasks: 100% |########################################################################################| Time: 0:00:04
Checking sstate mirror object availability: 100% |################################################################| Time: 0:00:00
Sstate summary: Wanted 149 Found 9 Missed 140 Current 864 (6% match, 86% complete)
NOTE: Executing Tasks
NOTE: Setscene tasks completed
WARNING: device-tree-xilinx-v2020.1+gitAUTOINC+bc84458333-r0 do_package: device-tree: NOT adding alternative provide /boot/device-tree.dtb: /boot/device-tree-999.dtb does not exist
NOTE: u-boot-xlnx: compiling from external source tree /home/lkmao/Downloads/petalinux_offline_pkg/u-boot-xlnx-xilinx-v2020.1
NOTE: Tasks Summary: Attempted 3640 tasks of which 3427 didn't need to be rerun and all succeeded.
Summary: There was 1 WARNING message shown.
INFO: Failed to copy built images to tftp dir: /tftpboot
[INFO] successfully built project
lkmao@ubuntu:~/peta_prj/linuxPsBase/petalinux_bsp$
编译完成后搜索ps-led.ko文件
lkmao@ubuntu:~/peta_prj/linuxPsBase/petalinux_bsp$ find . -name "ps-led.ko"
./build/tmp/sysroots-components/zynqmp_generic/ps-led/lib/modules/5.4.0/extra/ps-led.ko
lkmao@ubuntu:~/peta_prj/linuxPsBase/petalinux_bsp$
使用 makefile 单独编译驱动
使用petalinux-build编译驱动,很慢,效率很低,常规操作,使用Makefile单独编译驱动:
单独创建一个drivers目录,其中创建ps-led目录,将ps-led.c文件放进去,添加新的Makefile文件,内容如下
modname:=ps-led
obj-m:=$(modname).o
PWD :=$(shell pwd)
MAKE :=make
KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
CROSS_COMPILE=aarch64-linux-gnu-
ARCH=arm64
all:
$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
.PHONY: all clean
然后使用make编译:
lkmao@ubuntu:~/peta_prj/linuxPsBase/drivers/ps-led$ make
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -C /home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts M=/home/lkmao/peta_prj/linuxPsBase/drivers/ps-led modules
make[1]: Entering directory '/home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts'
CC [M] /home/lkmao/peta_prj/linuxPsBase/drivers/ps-led/ps-led.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] /home/lkmao/peta_prj/linuxPsBase/drivers/ps-led/ps-led.mod.o
LD [M] /home/lkmao/peta_prj/linuxPsBase/drivers/ps-led/ps-led.ko
make[1]: Leaving directory '/home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts'
lkmao@ubuntu:~/peta_prj/linuxPsBase/drivers/ps-led$ ls
Makefile modules.order Module.symvers ps-led.c ps-led.ko ps-led.mod ps-led.mod.c ps-led.mod.o ps-led.o
lkmao@ubuntu:~/peta_prj/linuxPsBase/drivers/ps-led$
编译后,看到生成了ps-led.ko文件。
确定内核路径
如何确定内核的路径:petalinux工程中创建一个驱动模块:
petalinux-create -t modules --name ps-led --enable
然后生成的ps-led.c中添加一些错误。使用petalinux-build编译工程,查看报错信息,如下所示,
测试驱动
创建本地挂载目录,配置IP地址,测试网络,挂载NFS服务。
root@petalinux:~# mkdir server
root@petalinux:~# ifconfig eth0 192.168.0.3
root@petalinux:~# ping 192.168.0.111
PING 192.168.0.111 (192.168.0.111): 56 data bytes
64 bytes from 192.168.0.111: seq=0 ttl=64 time=1.028 ms
64 bytes from 192.168.0.111: seq=1 ttl=64 time=0.399 ms
^C
--- 192.168.0.111 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.399/0.713/1.028 ms
root@petalinux:~#
root@petalinux:~# mount -t nfs -o nolock 192.168.0.111:/home/lkmao/work/nfsroot ./server
root@petalinux:~#
在虚拟机中,将ko文件复制到nfs目录
lkmao@ubuntu:~/peta_prj/linuxPsBase/drivers/ps-led$ cp ps-led.ko ~/work/nfsroot/
lkmao@ubuntu:~/peta_prj/linuxPsBase/drivers/ps-led$
复制完毕后,开发板中就可以看到ko文件了:
root@petalinux:~/server# ls
hello.txt ps-led.ko
root@petalinux:~/server#
insmod加载模块:
root@petalinux:~/server# insmod ps-led.ko
[ 8549.734998] ps_led: loading out-of-tree module taints kernel.
[ 8549.741658] ps_led_init:9init
[ 8549.744631] KERN_NOTICE
[ 8549.747074] KERN_WARNING
root@petalinux:~/server#
lsmod查看模块:
root@petalinux:~/server# lsmod
Tainted: G
ps_led 16384 0 - Live 0xffffffc008b75000 (O)
uio_pdrv_genirq 16384 0 - Live 0xffffffc008b70000
root@petalinux:~/server#
卸载模块:
root@petalinux:~/server# rmmod ps-led.ko
[ 8674.676105] ps_led_exit:17init
root@petalinux:~/server#