我有一个自定义的FPGA逻辑器,我已经为它实现了一个正常运行的char驱动程序,我现在也试图让它作为网络驱动程序工作。我正在尽可能地使用LDD书籍,snull代码和loopback.c,dummy.c以及内核中的其他驱动程序作为示例。
我下面的代码(显然是从较大的文件中删除)是我到目前为止的网络驱动程序代码;我可以成功insmod,“ifconfig optical0”显示我的MTU&标志是正确的所以我知道至少它已被注册。
现在我正在尝试实现struct net_device的私有字段(void * priv)来存储统计信息和其他内容,这导致了segfaults。这是迄今为止的代码:
struct serdes_device {
struct serdes_regs __iomem *regs;
struct serdes_dma *tx_dma,
*rx_dma;
struct device *dev;
struct net_device *netdev;
struct resource serdes_res;
struct cdev cdev;
int major, minor;
int tx_kbps;
int rx_kbps;
};
struct optical_priv {
struct serdes_device *serdes_dev;
struct net_device_stats stats;
};
static const struct net_device_ops optical_netdev_ops = {
.ndo_get_stats = optical_stats,
.ndo_start_xmit = optical_xmit,
/* and so on, not including the ops functions for brevity */
};
void optical_setup(struct net_device *dev)
{
dev->netdev_ops = &optical_netdev_ops;
dev->destructor = free_netdev;
dev->tx_queue_len = 1;
dev->type = ARPHRD_NONE;
dev->hard_header_len = SERDES_FRAME_HEADER_LENGTH;
dev->mtu = SERDES_FRAME_TOTAL_LENGTH;
dev->addr_len = 0;
dev->flags &= ~IFF_BROADCAST;
/* more flags & features cut */
}
static int optical_init(struct net_device *netdev)
{
int err;
struct optical_priv *priv;
netdev = alloc_netdev(sizeof(struct optical_priv), "optical%d", optical_setup);
if (!netdev)
return -ENOMEM;
err = register_netdev(netdev);
if (err < 0)
goto err;
priv = netdev_priv(netdev);
printk(KERN_WARNING "priv is at address 0x%p\n", priv);
return 0;
err:
free_netdev(netdev);
return err;
}
static int serdes_of_probe(struct platform_device *op)
{
struct serdes_device *serdes_dev;
struct optical_priv *priv;
int err = 0;
serdes_dev = kzalloc(sizeof(struct serdes_device), GFP_KERNEL);
/* A bunch of unrelated openfirmware & cdev code removed. */
err = optical_init(serdes_dev->netdev);
if (err < 0)
dev_err(serdes_dev->dev, "Error %d initing optical link\n", err);
priv = netdev_priv(serdes_dev->netdev);
if (!priv)
dev_err(serdes_dev->dev, "priv is null... \n");
dev_info(serdes_dev->dev, "priv is at 0x%p\n", priv);
dev_info(&op->dev, "Done probing.\n");
return 0;
out_free_serdes:
kfree(serdes_dev);
out_return:
return err;
}
据我了解,我正在分配空间并初始化我的serdes设备(我知道它可以作为一个char驱动程序)。然后我调用optical_init来分配,注册和配置serdes_dev-&gt; netdev。 alloc_netdev应该为(void *)priv字段分配空间,这就是传入sizeof(struct optical_priv)的原因。
两个打印语句的insmod之后的输出如下所示:
priv is at address 0xdd2de500
priv is at 0x00000500
Done probing.
显然尝试以任何方式访问priv会导致段错误。我想我的困惑是为什么netdev_priv()在从两个不同的函数调用时返回两个不同的值 - 在alloc_netdev之后的任何时候都不应该分配和更正吗?
e:我想通过在太多的驱动程序中寻找示例来困惑自己,从太多的时代开始,沉浸在硬件和内核API的历史中......如果有人对我有一个很好的基本驱动程序建议首先,我非常乐意阅读代码来学习。
答案 0 :(得分:0)
我认为问题在于:
err = optical_init(serdes_dev->netdev);
您正在将无效指针传递给netdev结构。然后在optical_init()
中使用以下命令更改指针的本地值:
netdev = alloc_netdev(sizeof(struct optical_priv), "optical%d", optical_setup);
现在你有一个指向struct net_device
的有效指针。但是此指针值不适用于serdes_dev->netdev
变量,而只适用于optical_init()
中的本地。因此,指向priv
的指针也是无效的。这里有一个显示问题的小例子:
#include <stdio.h>
#include <stdlib.h>
struct test {
int first;
int *second;
};
void allocate_memory(int *ptr)
{
ptr = malloc(10);
printf("while allocating %p\n", ptr);
}
int main(void) {
struct test *p1;
p1= malloc(sizeof(struct test));
printf("before %p\n", p1->second);
allocate_memory(p1->second);
printf("after %p\n", p1->second);
free(p1);
free(p2);
return EXIT_SUCCESS;
}
输出结果为:
before (nil)
while allocating 0x23ee030
after (nil)