当前位置: 首页 > news >正文

电力建设科学技术进步申报网站wordpress怎么修改代码

电力建设科学技术进步申报网站,wordpress怎么修改代码,海外代理ip,北京有哪些电商平台公司学习交流加 个人qq#xff1a; 1126137994个人微信#xff1a; liu1126137994学习交流资源分享qq群#xff1a; 962535112 因为做的项目需要用到ethercat主站#xff0c;而用ethercat主站#xff0c;标准的网卡网络协议栈性能就无法达到要求#xff0c;需要根据ethercat官… 学习交流加 个人qq 1126137994个人微信 liu1126137994学习交流资源分享qq群 962535112 因为做的项目需要用到ethercat主站而用ethercat主站标准的网卡网络协议栈性能就无法达到要求需要根据ethercat官方提供的文档修改网卡驱动程序的网络协议栈。那么在做正式的工作之前呢我们先来分析i.MX6的网卡驱动程序的整体框架弄懂后再去修改。 参考资料 《Linux network driver development Training lab book》是一本很好的讲述网卡驱动是如何从无到有的编写过程。下载地址点击下载 参考文章点击查看参考的文章 我们的网卡驱动程序的位置位于drviers/net/fec.c对应还有一个fec.h作头文件。 分析内核的驱动程序必须用source insight阅读代码或者其他类似的代码阅读工具方便代码的查找与跳跃不然很难分析。 首先是驱动程序的入口 static int __init fec_enet_module_init(void) {printk(KERN_INFO FEC Ethernet Driver\n);return platform_driver_register(fec_driver); }static void __exit fec_enet_cleanup(void) {platform_driver_unregister(fec_driver); }module_exit(fec_enet_cleanup); module_init(fec_enet_module_init);MODULE_LICENSE(GPL); 接着是上面的设置从uboot获取网卡地址信息的函数fec_mac_addr_setup static int fec_mac_addr_setup(char *mac_addr) {char *ptr, *p mac_addr;unsigned long tmp;int i 0, ret 0;while (p (*p) i 6) {ptr strchr(p, :);if (ptr)*ptr \0;if (strlen(p)) {ret strict_strtoul(p, 16, tmp);if (ret 0 || tmp 0xff)break;macaddr[i] tmp;}p ptr;}return 0; }/* 从uboot传给内核的启动参数中捕获fec_mac即mac地址参数并将该参数传递给fec_mac_addr_setup */ __setup(fec_mac, fec_mac_addr_setup);接下来是fec_driver结构体 static struct platform_driver fec_driver {.driver {.name DRIVER_NAME,.owner THIS_MODULE, #ifdef CONFIG_PM.pm fec_pm_ops, #endif},.id_table fec_devtype,.probe fec_probe,.remove __devexit_p(fec_drv_remove), };这里面都是我们所熟悉的nameownerprobeidtable等有一个不熟悉.pm这个参数我们看看这是什么通过source insight查看发现这个pm所需要的宏并没有被定义所以这个参数暂时没有用到暂时不分析。 那么接下来分析id_table字段对应的函数为 static struct platform_device_id fec_devtype[] {{.name enet,.driver_data FEC_QUIRK_ENET_MAC | FEC_QUIRK_BUG_TKT168103,},{.name fec,.driver_data 0,},{.name imx28-fec,.driver_data FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |FEC_QUIRK_BUG_TKT168103,},{ } }; 这里的fec_devtype[]数组主要是用来进行device与driver的匹配。默认的匹配函数内核代码中有drivers/baseplatform.c中 static int platform_match(struct device *dev, struct device_driver *drv) {struct platform_device *pdev to_platform_device(dev);struct platform_driver *pdrv to_platform_driver(drv);/* Attempt an OF style match first */if (of_driver_match_device(dev, drv))return 1;/* Then try to match against the id table */if (pdrv-id_table)return platform_match_id(pdrv-id_table, pdev) ! NULL;/* fall-back to driver name match */return (strcmp(pdev-name, drv-name) 0); }可以看到匹配的三个选择 1.如果存在设备树机制则优先匹配设备树这种情况下内核会寻找.driver 中的.of_match_table匹配。 2.使用驱动中的.id_table列表匹配在id_table数组中寻找与device的名字相匹配的成员。 3.最后单纯地比较device的名字和driver的名字是否相同是则匹配成功返回。 看完driver与device接下来先看一下板级信息是在哪里添加的吧。 在arch/arm/mach-mx6/board-mx6q_sabresd.c文件中可以找到函数mx6_sabresd_board_init这里面是一些设备的初始化我们找到了函数imx6_init_fec(fec_data);这个函数是添加以太网device设备的函数。 而mx6_sabresd_board_init这个函数在MACHINE_START里中被初始化 /** initialize __mach_desc_MX6Q_SABRESD data structure.*/ MACHINE_START(MX6Q_SABRESD, Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board)/* Maintainer: Freescale Semiconductor, Inc. */.boot_params MX6_PHYS_OFFSET 0x100,.fixup fixup_mxc_board,.map_io mx6_map_io,.init_irq mx6_init_irq,.init_machine mx6_sabresd_board_init,.timer mx6_sabresd_timer,.reserve mx6q_sabresd_reserve, MACHINE_END下面我们主要分析添加以太网设备的函数imx6_init_fec(fec_data)从而扩散到驱动程序的整个架构。这个函数被定义在arch/arm/mach-mx6/mx6_fec.c中如下 void __init imx6_init_fec(struct fec_platform_data fec_data) {fec_get_mac_addr(fec_data.mac);if (!is_valid_ether_addr(fec_data.mac))random_ether_addr(fec_data.mac);if (cpu_is_mx6sl())imx6sl_add_fec(fec_data);elseimx6q_add_fec(fec_data); }这里的参数struct fec_platform_data fec_data是设备的私有数据被定义在include/linux/fec.h中 struct fec_platform_data {int (*init) (struct phy_device *);int (*power_hibernate) (struct phy_device *);phy_interface_t phy;unsigned char mac[ETH_ALEN];int gpio_irq; };而这个参数fec_data已经在board-mx6q_sabresd.c中静态初始化好的如下 static struct fec_platform_data fec_data __initdata {.init mx6q_sabresd_fec_phy_init,.phy PHY_INTERFACE_MODE_RGMII,//.gpio_irq MX6_ENET_IRQ, };而函数imx6_init_fec最终是执行函数imx6q_add_fec(fec_data)进行添加设备arch/arm/mach-mx6/devices-imx6q.h中 extern const struct imx_fec_data imx6q_fec_data __initconst; #define imx6q_add_fec(pdata) \imx_add_fec(imx6q_fec_data, pdata)这里引入了外部的函数imx6q_fec_data这个函数定义在arch/arm/plat-mxc/devices/platform-fec.c中如下 #ifdef CONFIG_SOC_IMX6Q const struct imx_fec_data imx6q_fec_data __initconst imx_fec_data_entry_single(MX6Q, enet);const struct imx_fec_data imx6sl_fec_data __initconst imx_fec_data_entry_single(MX6DL, fec); #endif我们看到了“enet”“fec”这是设备的name找到这里就找到了设备的name。 而imx_fec_data_entry_single这个函数也是定义在上相同的文件中如下 #define imx_fec_data_entry_single(soc, _devid) \{ \.iobase soc ## _FEC_BASE_ADDR, \.irq soc ## _INT_FEC, \.devid _devid, \}这个函数的参数soc后面的两个 ## 号代表把前后两个字符串连接成为一个变量## 左右的空格会被忽略。那么上面的函数把传进来的参数展开后就等同于下面的代码 #define imx_fec_data_entry_single(soc, _devid) \{ \.iobase MX6Q_FEC_BASE_ADDR, \.irq MX6Q_INT_FEC, \.devid _devid, \}MX6Q_FEC_BASE_ADDRMX6Q_INT_FEC这两个值被定义在arch/arm/plat-mxc/include/mach/mx6.h通过宏展开可以查到这两个值。 下面继续分析函数imx_add_fec(imx6q_fec_data, pdata)它定义在arch/arm/plat-mxc/devices/platform-fec.c中如下 struct platform_device *__init imx_add_fec(const struct imx_fec_data *data,const struct fec_platform_data *pdata) {struct resource res[] {{.start data-iobase,.end data-iobase SZ_4K - 1,.flags IORESOURCE_MEM,}, {.start data-irq,.end data-irq,.flags IORESOURCE_IRQ,},};if (!fuse_dev_is_available(MXC_DEV_ENET))return ERR_PTR(-ENODEV);return imx_add_platform_device_dmamask(data-devid, 0,res, ARRAY_SIZE(res),pdata, sizeof(*pdata), DMA_BIT_MASK(32)); } 从上面的函数得知imx_fec_data最终被传送给了resource结构体。然后通过函数imx_add_platform_device_dmamask将resource和额外的pdata数据添加到device中最后在driver中再来获取device的这些信息。 以上是device的添加和driver的加载过程当device与driver匹配之后就进入驱动的probe入口函数。 static int __devinit fec_probe(struct platform_device *pdev) { 。。。。。。函数太长不全部复制了下面部分分析复制 }probe函数传进来的参数是刚刚分析过的imx_add_fec也就是将resource和额外的pdata数据传进来。先获得resource资源属性然后申请内存资源空间。代码如下 r platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!r)return -ENXIO;r request_mem_region(r-start, resource_size(r), pdev-name);if (!r)return -EBUSY;然后申请net_device结构体初始化网络设备传进来driver的私有数据的尺寸代码如下 /* Init network device */ndev alloc_etherdev(sizeof(struct fec_enet_private));if (!ndev) {ret -ENOMEM;goto failed_alloc_etherdev;}然后告诉内核我们的设备属于网络设备由于net_device不属于char和block设备因此不能用常规的方法来设计驱动。 SET_NETDEV_DEV(ndev, pdev-dev);定义如下 /* Set the sysfs physical device reference for the network logical device* if set prior to registration will cause a symlink during initialization.*/ #define SET_NETDEV_DEV(net, pdev) ((net)-dev.parent (pdev))分配完net_device结构体之后接下来需要用下面的函数获取分配所得的私有数据的指针 fep netdev_priv(ndev);然后用ioremap函数将网卡的寄存器的物理地址映射到内核空间并且给获取得到的私有数据指针赋值。代码如下 fep-hwp ioremap(r-start, resource_size(r));fep-pdev pdev;if (!fep-hwp) {ret -ENOMEM;goto failed_ioremap;}然后下面的代码是用来设置平台driver的数据以及接收之前在板级文件中设置的platform_data platform_set_drvdata(pdev, ndev);//pdev-dev-p-driver_data ndevpdata pdev-dev.platform_data;//接收之前在板级文件下静态添加device的platform_data接下来是对接收到的数据进行判断解析。这里的pdata-phy用来判断MAC物理层和以太网物理层的的接口的从之前的fec_data里获取的数据得知我们的iMX6q用的接口是PHY_INTERFACE_MODE_RGMII。 if (pdata)fep-phy_interface pdata-phy;接下来是关于中断的相关判断代码如下 if (pdata-gpio_irq 0) {gpio_request(pdata-gpio_irq, gpio_enet_irq);gpio_direction_input(pdata-gpio_irq);irq gpio_to_irq(pdata-gpio_irq);ret request_irq(irq, fec_enet_interrupt,IRQF_TRIGGER_RISING,pdev-name, ndev);if (ret)goto failed_irq;} else {/* This device has up to three irqs on some platforms */for (i 0; i 3; i) {irq platform_get_irq(pdev, i);if (i irq 0)break;ret request_irq(irq, fec_enet_interrupt,IRQF_DISABLED, pdev-name, ndev);if (ret) {while (--i 0) {irq platform_get_irq(pdev, i);free_irq(irq, ndev);}goto failed_irq;}}}由之前在平台层静态设置的fec_data结构中 static struct fec_platform_data fec_data __initdata {.init mx6q_sabresd_fec_phy_init,.phy PHY_INTERFACE_MODE_RGMII,//.gpio_irq MX6_ENET_IRQ, };这一行//.gpio_irq MX6_ENET_IRQ,已经被屏蔽掉了得知上面的代码是执行else分支。 现在我们来分析一下如果上面那行代码没有被屏蔽掉那么我们该如何判断出上面的代码到底要执行哪一个分支呢 分析我们这里的MX6_ENET_IRQ的值是6我们可以知道在添加私有数据之前有如下代码 if (enet_to_gpio_6)// Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. mxc_iomux_set_specialbits_register(IOMUX_OBSRV_MUX1_OFFSET,OBSRV_MUX1_ENET_IRQ,OBSRV_MUX1_MASK);elsefec_data.gpio_irq -1;imx6_init_fec(fec_data); 它用来判断是否对fec_data的gpio_irq赋值为-1而我们的enet_to_gpio_6是一个被定义在arch/arm/mach-mx6/cpu.c中的全局变量默认值为0同样在该文件可以找到下面的代码 static int __init set_enet_irq_to_gpio(char *p) {enet_to_gpio_6 true;return 0; }early_param(enet_gpio_6, set_enet_irq_to_gpio); early_param用来解析uboot传递给内核的参数只有当uboot参数中带有enet_gpio_6这个参数时参会执行set_enet_irq_to_gpio所以上面的enet_to_gpio_6得值就为默认值0所以会执行上面的这一行语句fec_data.gpio_irq -1;那么pdata-gpio_irq0所以刚才的代码就不会执行if (pdata-gpio_irq 0)语句而会执行else分支分支。 即上面的代码是从platform_device 的resource获取中断号的。由上面的分析我们知道imx_fec_data_entry_single这个宏展开后是如下代码 #define imx_fec_data_entry_single(soc, _devid) \{ \.iobase MX6Q_FEC_BASE_ADDR, \.irq MX6Q_INT_FEC, \.devid _devid, \}得知我们的中断号是MX6Q_INT_FEC它的值为150.对应的中断注册函数为fec_enet_interrupt。 中断的注册分析完了后接下来是时钟了linux内核有一组专门的clock api用来处理时钟简单点来说就只要知道首先clk_get()然后再clk_enable()就可以了driver remove的时候反之即clk_disable()再clk_put()即可。 代码如下 fep-clk clk_get(pdev-dev, fec_clk);if (IS_ERR(fep-clk)) {ret PTR_ERR(fep-clk);goto failed_clk;}fep-mdc_clk clk_get(pdev-dev, fec_mdc_clk);if (IS_ERR(fep-mdc_clk)) {ret PTR_ERR(fep-mdc_clk);goto failed_clk;}clk_enable(fep-clk);这里的fec_clk是Ethernet控制器的clockfec_mdc_clk是MAC层与物理层接口MDIO的Clock。 接下来是MAC层的初始化函数代码如下 ret fec_enet_init(ndev); 比较重要后面具体函数再分析if (ret)goto failed_init;再接着就是MAC层与物理层接口的初始化函数 ret fec_enet_mii_init(pdev); 比较重要后面具体函数再分析if (ret)goto failed_mii_init;再接着就是对IEEE 1588 时钟同步协议的初始化 if (fec_ptp_malloc_priv((fep-ptp_priv))) {if (fep-ptp_priv) {fep-ptp_priv-hwp fep-hwp;ret fec_ptp_init(fep-ptp_priv, pdev-id);if (ret)printk(KERN_WARNING IEEE1588: ptp-timer is unavailable\n);elsefep-ptimer_present 1;} elseprintk(KERN_ERR IEEE1588: failed to malloc memory\n);}然后把内核网络层的传输队列关闭即禁止发送关闭时钟等一些列辅助操作 /* Carrier starts down, phylib will bring it up */netif_carrier_off(ndev);clk_disable(fep-clk);INIT_DELAYED_WORK(fep-fixup_trigger_tx, fixup_trigger_tx_func);最后就是我们再熟悉不过的将前面分配的net_device结构体注册进内核 ret register_netdev(ndev);if (ret)goto failed_register; 接下来我将详细讲述MAC层物理层接口以及1588协议支持的代码从而用ethercat的协议进行网卡协议的修改。放到下一篇文章分析点击链接查看下一篇文章 想一起探讨以及获得各种学习资源加我有我博客中写的代码的原稿 qq1126137994 微信liu1126137994 可以共同交流关于嵌入式操作系统C语言C语言数据结构等技术问题。
http://www.pierceye.com/news/67806/

相关文章:

  • 网站常用字体大小影楼修图
  • 金融网站建设公司排名松江叶榭网站建设
  • 罗湖做网站联系电话网站优化+山东
  • 网站建设要什么营销传播的服务商
  • 自贡制作网站wordpress git page
  • 五指山住房建设局网站包头网站制作公司
  • 合肥专业网站制作团队网站制作报价优惠
  • 河南高端网站建设公司网站建设 服务流程
  • 马鞍山网站制作公司中国电子商务网站建设
  • 佛山免费建站怎样百度百度一下你就知道主页
  • 广州建站优化公司网站页面模板页面布局
  • 商城购物网站设计内容网站微信认证费用多少钱
  • 怎样建设网站最好上海公司章程在哪里下载
  • 厦门哪家做网站好网站建设三网合一指的是什么
  • 2023免费网站推广免费一键生成个人网站
  • wordpress站点实例网站关键词优化公司
  • vue可以做pc的网站广州哪家做网站好
  • 专门制作网站建网站的流程和费用
  • 网站推广的方法有哪些?最基础的编程代码
  • php做的卖水果网站网站友链查询
  • cn免费域名注册网站价格网app下载
  • 湖南3合1网站建设电话网站页面关键词优化
  • 设计师投稿网站不会编程如何做自己的网站
  • 上海设计网站开发一个备案号可以用几个网站
  • 网站建设一个月做十单上海网站建设中小型企业
  • 网站建站要多少钱单位做网站有哪些
  • 2015网站建设html网页设计实例范例带代码
  • 深圳网站seo外包公司哪家好商务网站建设平台
  • 网站的开发与建设项目快速网页制作工具
  • 网站建设费记账WordPress开cdn支付