原创(虚拟网卡驱动加载失败怎么解决)虚拟网卡驱动未正常安装怎么回事,纯干货分享!PCI设备驱动与虚拟网卡驱动源码分析,

交互式存储电子设备驱动力解释器

#include<linux/module.h>#include<linux/sched.h>#include<linux/kernel.h>#include<linux/slab.h>#include<linux/errno.h>#include<linux/types.h>#include<linux/interrupt.h>#include<linux/in.h>#include<linux/netdevice.h>#include<linux/etherdevice.h>#include<linux/ip.h>#include<linux/tcp.h>#include<linux/skbuff.h>#include<linux/if_ether.h>#include<linux/in6.h>#include<asm/uaccess.h>#include<asm/checksum.h>#include<linux/platform_device.h> #define MAC_AUTO static struct net_device *vir_net_devs; struct vir_net_priv { struct net_device_stats stats; //管用的统计统计数据重要信息 int status; //计算机系统的状况重要信息,是到手报文,却是转交到互联网报文 int rx_packetlen; //转交到的报文宽度 u8 *rx_packetdata; //转交到的统计数据 int tx_packetlen; //推送的报文宽度 u8 *tx_packetdata; //推送的统计数据 struct sk_buff *skb; //socket buffer内部结构体,互联网各层间传输统计数据都是透过那个内部结构mammalian同时实现的 spinlock_t lock; //磁矩锁 }; /*计算机系统迈入时能继续执行该表达式*/ int vir_net_open(struct net_device *dev) { #ifndef MAC_AUTO int i; for (i=0; i<6; i++) { dev->dev_addr[i] = 0xaa; } #else random_ether_addr(dev->dev_addr); #endif /*打开传输队列进行统计数据传输*/ netif_start_queue(dev); printk(“vir_net_open\n); return 0; } /*关闭的时候,关闭队列*/ int vir_net_release(struct net_device *dev) { /*停止推送统计数据*/ netif_stop_queue(dev); printk(“vir_net_release\n); return 0; } /*接包表达式,有统计数据过来时,中断继续执行*/ void vir_net_rx(struct net_device *pdev, int len, unsigned char *buf) { struct sk_buff *skb; struct vir_net_priv *priv = (struct vir_net_priv *) pdev->ml_priv; skb = dev_alloc_skb(len+2);//分配一个socket buffer,并且初始化skb->data,skb->tail和skb->head if(!skb) { printk(“gecnet rx: low on mem – packet dropped\n); priv->stats.rx_dropped++; return; } skb_reserve(skb, 2); /* align IP on 16B boundary */ memcpy(skb_put(skb, len), buf, len);//skb_put是把统计数据写入到socket buffer /* Write metadata, and then pass to the receive level */ skb->dev = pdev; skb->protocol = eth_type_trans(skb, pdev);//返回的是协议号 skb->ip_summed = CHECKSUM_UNNECESSARY; //此处不校验 priv->stats.rx_packets++;//转交到包的个数+1 priv->stats.rx_bytes += len;//转交到包的宽度 printk(“vir_net_rx\n); netif_rx(skb);//通知内核已经转交到包,并且封装成socket buffer传到上层 return; } /*模拟硬件推送统计数据*/ void vir_net_hw_tx(char *buf, int len, struct net_device *dev) { struct net_device *dest;//目标电子设备内部结构体,net_device存储一个互联网接口的重要重要信息,是互联网驱动力程序的核心 struct vir_net_priv *priv; if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { printk(“vir_net: packet too short (%i octets)\n, len); return; } dest = vir_net_devs; priv = (struct vir_net_priv *)dest->ml_priv; priv->rx_packetlen = len; priv->rx_packetdata = buf; printk(“vir_net_hw_tx\n); dev_kfree_skb(priv->skb); } /*发包表达式, 上层有统计数据推送时,该表达式会被调用*/ int vir_net_tx(struct sk_buff *skb, struct net_device *pdev) { int len; char *data; struct vir_net_priv *priv = (struct vir_net_priv *)pdev->ml_priv; if(skb == NULL) { printk(“net_device = %p, skb = %p\n, pdev, skb); return 0; } /*ETH_ZLEN是所发的最小报文的宽度*/ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; /*将要推送的报文中统计数据部分*/ data = skb->data; priv->skb = skb; /*调用硬件接口进行统计数据的推送*/ vir_net_hw_tx(data, len, pdev); printk(“vir_net_tx, pdev = %p\n, pdev); return 0; } /*电子设备初始化表达式*/ int vir_net_device_init(struct net_device *pdev) { /*填充一些以太网中的电子设备内部结构体的项*/ ether_setup(pdev); /*keep the default flags, just add NOARP */ pdev->flags |= IFF_NOARP; /*为priv分配内存*/ pdev->ml_priv = kmalloc(sizeof(struct vir_net_priv), GFP_KERNEL); if (pdev->ml_priv == NULL){ return ENOMEM; } memset(pdev->ml_priv, 0, sizeof(struct vir_net_priv)); spin_lock_init(&((struct vir_net_priv *)pdev->ml_priv)->lock); printk(“vir_net_device_init, pdev = %p\n, pdev); return 0; } /*内部结构体填充*/ static const struct net_device_ops vir_net_netdev_ops = { .ndo_open = vir_net_open, //打开存储电子设备 对应ifconfig xx up .ndo_stop = vir_net_release, //关闭存储电子设备 对应ifconfig xx down .ndo_start_xmit = vir_net_tx, //迈入报文传输(对应上层要推送统计数据时) .ndo_init = vir_net_device_init, //初始化存储电子设备硬件 }; /**/ static void vir_plat_net_release(struct device *pdev) { printk(“vir_plat_net_release, pdev = %p\n, pdev); } /*匹配*/ static int vir_net_probe(struct platform_device *pdev) { int result = 0; /*vir_net_devs内部结构体相当于一个交互式的计算机系统*/ vir_net_devs = alloc_etherdev(sizeof(struct net_device)); vir_net_devs->netdev_ops = &vir_net_netdev_ops; strcpy(vir_net_devs->name, “net_0”); /*上面填充了3项,如果是真实的存储电子设备会填充更多,然后 使用register_netdev进行注册,net/core,注册好了以后 内核当中就会有那个电子设备了,当那个计算机系统up以后就会进入open表达式*/ if ((result = register_netdev(vir_net_devs))) { printk(“vir_net: error %i registering device \”%s\”\n, result, vir_net_devs->name); } printk(“vir_net_probe, pdev = %p\n, pdev); return 0; } /*电子设备移除表达式*/ static int vir_net_remove(struct platform_device *pdev) { kfree(vir_net_devs->ml_priv); unregister_netdev(vir_net_devs); return 0; } /*内部结构体填充*/ static struct platform_device vir_net= { .name = “vir_net”, .id = 1, .dev = { .release = vir_plat_net_release, }, }; /*内部结构体填充*/ static struct platform_driver vir_net_driver = { .probe = vir_net_probe, .remove = vir_net_remove, .driver = { .name = “vir_net”, /*这里的name和上面那个内部结构体的name如果匹配就会继续执行probe表达式*/ .owner = THIS_MODULE, }, }; /*模块入口表达式*/ static int __init vir_net_init(void) { printk(“vir_net_init\n); platform_device_register(&vir_net); return platform_driver_register(&vir_net_driver); } /*模块退出表达式*/ static void __exit vir_net_exit(void) { printk(“vir_net_exit\n); platform_driver_unregister(&vir_net_driver); platform_device_unregister(&vir_net); } module_init(vir_net_init); module_exit(vir_net_exit); MODULE_LICENSE(“GPL”);
【文章福利】小编推荐自己的Linux内核源代码交流群:【869634926】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!前50名可进群领取!!!并额外赠送一份价值600的内核资料包(含视频教程、电子书、实战项目及代码)!!!

学习直通车:Linux内核源代码/内存调优/文件系统/进程管理/电子设备驱动力/互联网协议栈

Makefile

CONFIG_MODULE_SIG = n objm+=virnet.o all: make C /lib/modules/$(shell uname r)/build/ M=$(PWD) modules clean: make C /lib/modules/$(shell uname r)/build/ M=$(PWD) clean

在使用sudo ifconfig xxx up/down和sudo insmod xxx,sudo rmmod xxx命令时,输出的结果可以透过迈入另外一个终端观察,tail -f /var/log/kern.log,查看内核日志的输出,从而观察到各个命令的继续执行时,他们会去继续执行哪一个表达式。

PCI电子设备驱动力解释器

/*必须包含的两个头文件*/ #include <linux/module.h>#include <linux/pci.h> /*自定义内部结构体,用在中断服务表达式里面*/ struct pci_Card { resource_size_t io; /*端口读写变量*/ long range, flags; /*io地址范围,标志位*/ void __iomem *ioaddr; /*io映射地址*/ int irq; /*中断号*/ }; /*驱动力程序支持的电子设备列表,如果有匹配的电子设备,那么改驱动力程序就会被继续执行*/ static struct pci_device_id ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, /*vendor id, 厂家ID*/ 0x100f) /*device id, 电子设备ID,可以透过lspci或者去相应的目录里面看*/ }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0) }, {0,} /*最后一组为0,表示结束*/ }; /*进行注册,pci总线,ids为上面定义的设置*/ MODULE_DEVICE_TABLE(pci, ids); /*打印配置空间里面的一些重要信息*/ void skel_get_configs(struct pci_dev *dev) { uint8_t revisionId; uint16_t vendorId, deviceId; uint32_t classId; /* 从参数dev里面也是可以打印vendorID等重要信息的, 那个内部结构体里面包含那个成员变量,用下面的API 获取得到的结果也是一致的 */ pci_read_config_word(dev, PCI_VENDOR_ID, &vendorId); printk(“vendorID = %x”, vendorId); pci_read_config_word(dev, PCI_DEVICE_ID, &deviceId); printk(“deviceID = %x”, deviceId); pci_read_config_byte(dev, PCI_REVISION_ID, &revisionId); printk(“revisionID = %x”,revisionId); pci_read_config_dword(dev, PCI_CLASS_REVISION, &classId); printk(“classID = %x”,classId); } /*电子设备中断服务表达式*/ static irqreturn_t pci_Mcard_interrupt(int irq, void *dev_id) { struct pci_Card *pci_Mcard = (struct pci_Card *)dev_id; /*中断表达式里面打印中断号*/ printk(“irq = %d, pci_Mcard_irq = %d\n, irq, pci_Mcard->irq); return IRQ_HANDLED; } /*有匹配的电子设备,那个表达式会继续执行*/ static int probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval = 0; struct pci_Card *pci_Mcard; printk(“probe func\n); /*电子设备使能*/ if(pci_enable_device(dev)) { printk (KERN_ERR “IO Error.\n); return EIO; } pci_Mcard = kmalloc(sizeof(struct pci_Card),GFP_KERNEL); if(!pci_Mcard) { printk(“In %s,kmalloc err!”,__func__); return ENOMEM; } /*电子设备中断号*/ pci_Mcard->irq = dev->irq; if(pci_Mcard->irq < 0) { printk(“IRQ is %d, its invalid!\n,pci_Mcard->irq); goto out_pci_Mcard; } /*获取io内存相关重要信息*/ pci_Mcard->io = pci_resource_start(dev, 0); pci_Mcard->range = pci_resource_end(dev, 0) pci_Mcard->io + 1; pci_Mcard->flags = pci_resource_flags(dev,0); printk(“start %llx %lx %lx\n,pci_Mcard->io, pci_Mcard->range, pci_Mcard->flags); printk(“PCI base addr 0 is io%s.\n,(pci_Mcard->flags & IORESOURCE_MEM)? “mem”:“port”); /*防止地址访问冲突,所以这里先申请*/ retval = pci_request_regions(dev,“pci_module”); if(retval) { printk(“PCI request regions err!\n); goto out_pci_Mcard; } /*再进行映射*/ pci_Mcard->ioaddr = pci_ioremap_bar(dev, 0); if(!pci_Mcard->ioaddr) { printk(“ioremap err!\n); retval = ENOMEM; goto out_regions; } /*申请中断IRQ并设定中断服务子表达式*/ retval = request_irq(pci_Mcard->irq, pci_Mcard_interrupt, IRQF_SHARED, “pci_module”, pci_Mcard); if(retval) { printk (KERN_ERR “Cant get assigned IRQ %d.\n,pci_Mcard->irq); goto out_iounmap; } pci_set_drvdata(dev, pci_Mcard); skel_get_configs(dev); return 0; out_iounmap: iounmap(pci_Mcard->ioaddr); out_regions: pci_release_regions(dev); out_pci_Mcard: kfree(pci_Mcard); return retval; } /*移除PCI电子设备*/ static void remove(struct pci_dev *dev) { struct pci_Card *pci_Mcard = pci_get_drvdata(dev); free_irq (pci_Mcard->irq, pci_Mcard); iounmap(pci_Mcard->ioaddr); pci_release_regions(dev); kfree(pci_Mcard); pci_disable_device(dev); printk(“remove pci device ok\n); } /*内部结构体成员变量填充*/ static struct pci_driver pci_driver = { .name = “pci_module”, .id_table = ids, .probe = probe, .remove = remove, }; /*模块入口表达式*/ static int __init pci_module_init(void) { printk(“pci module entry function\n); return pci_register_driver(&pci_driver); } /*模块退出表达式*/ static void __exit pci_module_exit(void) { printk(“pci module exit function\n); pci_unregister_driver(&pci_driver); } MODULE_LICENSE(“GPL”); module_init(pci_module_init); module_exit(pci_module_exit);

Makefile

objm := pci_module.o KERNELDIR ?= /lib/modules/$(shell uname r)/build PWD := $(shell pwd) all: $(MAKE) C $(KERNELDIR) M=$(PWD) clean:

继续执行前先把e1000卸载了

sudo rmmod e1000

然后,继续执行

sudo insmod pci_module.ko dmesg

内核技术中文网 – 构建全国最权威的内核技术交流撷取论坛

原文参考:PCI驱动力与交互式存储电子设备驱动力解释器

(版权归原作者所有,侵删)

相关文章&视频推荐:

浅谈一下LINUX驱动力开发中的红外(IRDA)程序如何编写嵌入式LINUX LED驱动力程序?具体预测Linux内核驱动力移植的过程与原理深度解析Linux下VLAN功能的同时实现原理Linux内核5.0版本五大模块及内核书籍推荐