【发布时间】:2014-03-07 23:20:40
【问题描述】:
我有一个自定义的 FPGA 逻辑,我已经为它实现了一个功能性的 char 驱动程序,我现在正试图让它作为一个网络驱动程序工作。我将尽我所能使用 LDD book、snull 代码和 loopback.c、dummy.c 以及内核中的其他驱动程序作为示例。
我下面的代码(显然是从较大的文件中提取的)是我目前拥有的网络驱动程序代码;我可以成功地 insmod,并且“ifconfigoptical0”显示我的 MTU 和标志是正确的,所以我知道至少它正在被注册。
现在我正在尝试实现 struct net_device 的私有字段 (void* priv) 来存储统计信息和其他内容,这会导致段错误。到目前为止的代码如下:
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 设备分配空间并初始化我的 serdes 设备(我知道它可以用作 char 驱动程序)。然后我调用optical_init 来分配、注册和配置serdes_dev->netdev。 alloc_netdev 也应该为 (void *)priv 字段分配空间,这就是传入 sizeof(structoptical_priv) 的原因。
其中两个打印语句的 insmod 之后的输出如下所示:
priv is at address 0xdd2de500
priv is at 0x00000500
Done probing.
并且显然在此之后尝试以任何方式访问 priv 会导致段错误。我认为我的困惑是为什么 netdev_priv() 在从两个不同的函数调用时返回两个不同的值——不应该在 alloc_netdev 之后的任何时候分配和更正吗?
e:我想我也在寻找太多驱动程序中的示例,来自太多时代,沉浸在过去的硬件和内核 API 的历史中......如果有人对我有很好的基本驱动程序推荐首先,我非常乐意阅读代码来学习。
【问题讨论】:
标签: c linux-kernel network-programming linux-device-driver