petalinux驱动实践:起步篇

 一 添加驱动

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#

小结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千册

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值