Last active
April 27, 2022 18:08
-
-
Save Jamlee/c34af3b7874f5a947407c5bb4f54d922 to your computer and use it in GitHub Desktop.
Linux 系统内核例子
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/errno.h> | |
#include <linux/init.h> | |
#include <linux/netdevice.h> | |
#include <linux/etherdevice.h> | |
#include <linux/ethtool.h> | |
#include <linux/skbuff.h> | |
#include <linux/slab.h> | |
#include <linux/of.h> | |
#include <linux/platform_device.h> | |
////////////////////////////////////////////////////////////////////////////////// | |
// | |
// 这里为了感知新PlatformDevice时,创建 1 个网络设备的代码。和Platform总线代码无关 | |
// | |
////////////////////////////////////////////////////////////////////////////////// | |
struct eth_struct { | |
int bar; | |
int foo; | |
struct net_device *dummy_ndev; | |
}; | |
static int fake_eth_open(struct net_device *dev) { | |
printk("%s\n", __FUNCTION__); | |
/* We are now ready to accept transmit request from | |
* the queueing layer of the networking. */ | |
netif_start_queue(dev); | |
return 0; | |
} | |
static int fake_eth_release(struct net_device *dev) { | |
pr_info("%s\n", __FUNCTION__); | |
netif_stop_queue(dev); | |
return 0; | |
} | |
static int fake_eth_xmit(struct sk_buff *skb, struct net_device *dev) { | |
pr_info("%s\n", __FUNCTION__); | |
dev->stats.tx_bytes +=skb->len; | |
dev->stats.tx_packets++; | |
skb_tx_timestamp(skb); | |
dev_kfree_skb(skb); | |
return NETDEV_TX_OK; | |
} | |
static int fake_eth_init(struct net_device *dev) { | |
pr_info("%s is inited \n", __FUNCTION__); | |
return 0; | |
} | |
// 网卡设备操作函数 | |
static const struct net_device_ops my_netdev_ops = { | |
.ndo_init = fake_eth_init, | |
.ndo_open = fake_eth_open, | |
.ndo_stop = fake_eth_release, | |
.ndo_start_xmit = fake_eth_xmit, | |
.ndo_validate_addr = eth_validate_addr, | |
}; | |
////////////////////////////////////////////////////////////////////////////////// | |
// | |
// 这里为了注册 1 个网络设备。和平台代码无关 | |
// | |
////////////////////////////////////////////////////////////////////////////////// | |
static const struct of_device_id fake_eth_dt_ids[] = { | |
{ .compatible = "packt,fake-eth", }, | |
{ /* */ } | |
}; | |
static int fake_eth_probe(struct platform_device *pdev) { | |
int ret; | |
struct eth_struct *priv; | |
struct net_device *dummy_ndev; | |
priv = devm_kzalloc(&pdev->dev,sizeof(*priv), GFP_KERNEL); | |
if (!priv) | |
return -ENOMEM; | |
// 分配 1 个网络设备 | |
dummy_ndev = alloc_etherdev(sizeof(struct eth_struct)); | |
dummy_ndev->if_port = IF_PORT_10BASET; | |
dummy_ndev->netdev_ops = &my_netdev_ops; | |
// 注册网络设备 | |
ret = register_netdev(dummy_ndev); | |
if(ret) { | |
pr_info("dummy net dev: Error %d initializaing card...", ret); | |
return ret; | |
} | |
priv -> dummy_ndev = dummy_ndev; | |
platform_set_drvdata(pdev,priv); | |
return 0; | |
} | |
static int fake_eth_remove(struct platform_device *pdev) { | |
struct eth_struct *priv; | |
priv = platform_get_drvdata(pdev); | |
pr_info("Cleaning UP the Module\n"); | |
unregister_netdev(priv->dummy_ndev); | |
free_netdev(priv->dummy_ndev); | |
return 0; | |
} | |
// https://blog.csdn.net/weixin_43790707/article/details/104900370 | |
// 定义1个 platform 驱动,注册在 platform 总线上。简单来说,我们在编写驱动时指定的 struct platform_device_id *id_table | |
// const char *name、const struct of_device_id *of_match_table 将是判断我们的驱动和设备是否能匹配的依据 | |
// 我们可以看到匹配的顺序: | |
// 1、先用设备树中的 compatible 属性和 platform_drive r中的 driver 中的 of_match_table 来匹配 | |
// 2、再用 platform_driver 中的 id_table 中的 name 和 platform_device 中的 nam e来匹配 | |
// 3、最后用 platform_devic e中的 name 和 platform_driver 中的 driver 中的 nam e来匹配 | |
static struct platform_driver mypdrv = { | |
.probe = fake_eth_probe, // 驱动和设备匹配成功之后调用 | |
.remove = fake_eth_remove, // 卸载驱动时调用 | |
.driver = { | |
.name = "fake-eth", // 与设备匹配时会用到的驱动名,一样就匹配成 | |
.of_match_table = of_match_ptr(fake_eth_dt_ids), // 与设备树匹配,名称一样就匹配成功 | |
.owner = THIS_MODULE, | |
}, | |
}; | |
// 注册驱动到 platfrom 总线上 | |
module_platform_driver(mypdrv); | |
MODULE_LICENSE("GPL"); | |
MODULE_AUTHOR("John Madieu <[email protected]"); | |
MODULE_DESCRIPTION("Fake Ethernet driver"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CONFIG_MODULE_SIG=n | |
CONFIG_MODULE_SIG_ALL=n | |
# If KERNELRELEASE is defined, we've been invoked from the | |
# kernel build system and can use its language. | |
ifneq ($(KERNELRELEASE),) | |
obj-m := fake_driver.o | |
# Otherwise we were called directly from the command | |
# line; invoke the kernel build system. | |
else | |
KERNELDIR ?= /lib/modules/$(shell uname -r)/build | |
PWD := $(shell pwd) | |
default: | |
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules | |
rm -f fake_driver.mod* .fake_driver* fake_driver.o Module.symvers modules.order | |
endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://tldp.org/LDP/lkmpg/2.6/html/hello2.html | |
#include <linux/module.h> // Needed by all modules | |
#include <linux/kernel.h> // Needed for KERN_ALERT | |
static int hello_init(void) | |
{ | |
printk(KERN_ALERT "Hello, world\n"); | |
return 0; | |
} | |
static void hello_exit(void) | |
{ | |
printk(KERN_ALERT "Goodbye, world\n"); | |
} | |
module_init(hello_init); | |
module_exit(hello_exit); | |
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CONFIG_MODULE_SIG=n | |
CONFIG_MODULE_SIG_ALL=n | |
# If KERNELRELEASE is defined, we've been invoked from the | |
# kernel build system and can use its language. | |
ifneq ($(KERNELRELEASE),) | |
obj-m := hello.o | |
# Otherwise we were called directly from the command | |
# line; invoke the kernel build system. | |
else | |
KERNELDIR ?= /lib/modules/$(shell uname -r)/build | |
PWD := $(shell pwd) | |
default: | |
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules | |
endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1 个假的 platform device | |
#include <linux/module.h> | |
#include <linux/init.h> | |
#include <linux/kernel.h> // Needed for KERN_ALERT | |
#include <linux/platform_device.h> | |
#define MY_DUMMY_PLATFORM_DEV_NAME "fake-eth" | |
static struct platform_device MY_DUMMY_device = { | |
.name = MY_DUMMY_PLATFORM_DEV_NAME, | |
.id = 100, //when .name is same, using .id to distgunish | |
}; | |
// -- Module INIT | |
static int __init MY_DUMMY_init(void) | |
{ | |
return platform_device_register(&MY_DUMMY_device); | |
} | |
static void __exit MY_DUMMY_exit(void) | |
{ | |
platform_device_del(&MY_DUMMY_device); | |
} | |
module_init(MY_DUMMY_init); | |
module_exit(MY_DUMMY_exit); | |
//MODULE_DESCRIPTION("Platform device and driver example"); | |
//MODULE_AUTHOR("ITTraining"); | |
MODULE_LICENSE("GPL v2"); | |
//MODULE_ALIAS("platform:" MY_DUMMY_PLATFORM_DEV_NAME); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CONFIG_MODULE_SIG=n | |
CONFIG_MODULE_SIG_ALL=n | |
# If KERNELRELEASE is defined, we've been invoked from the | |
# kernel build system and can use its language. | |
ifneq ($(KERNELRELEASE),) | |
obj-m := platform_device.o | |
# Otherwise we were called directly from the command | |
# line; invoke the kernel build system. | |
else | |
KERNELDIR ?= /lib/modules/$(shell uname -r)/build | |
PWD := $(shell pwd) | |
default: | |
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules | |
rm -f platform_device.mod* .platform_device* platform_device.o Module.symvers modules.order | |
endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ sudo insmod eth-skel.ko # rmmod | |
$ ls /sys/bus/platform/drivers/fake-eth/ | |
bind module uevent unbind | |
$ make && sudo rmmod fake_driver.ko; sudo insmod fake_driver.ko; dmesg |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment