//注釋者: zl
//注釋格式: //注釋內容
//blog: blog.sina.com.cn/foreveralbum
//date:08.5.3
//說明:對代碼的幾個關鍵函數進行了注釋,包括初始化,收發(fā)包等
//函數運行順序:加載模塊->b44_init()->b44_init_one()->register_netdev()
//注冊完后就可以調用驅動程序操作設備了
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//此驅動用到了ssb 代碼在/driver/ssb
#include
#include
#include
#include
#include "b44.h"
#define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "2.0"
#define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \
NETIF_MSG_LINK | \
NETIF_MSG_TIMER | \
NETIF_MSG_IFDOWN | \
NETIF_MSG_IFUP | \
NETIF_MSG_RX_ERR | \
NETIF_MSG_TX_ERR)
#define B44_TX_TIMEOUT (5 * HZ)
#define B44_MIN_MTU 60
#define B44_MAX_MTU 1500
#define B44_RX_RING_SIZE 512
#define B44_DEF_RX_RING_PENDING 200
#define B44_RX_RING_BYTES (sizeof(struct dma_desc) * \
B44_RX_RING_SIZE)
#define B44_TX_RING_SIZE 512
#define B44_DEF_TX_RING_PENDING (B44_TX_RING_SIZE - 1)
#define B44_TX_RING_BYTES (sizeof(struct dma_desc) * \
B44_TX_RING_SIZE)
#define TX_RING_GAP(BP) \
(B44_TX_RING_SIZE - (BP)->tx_pending)
#define TX_BUFFS_AVAIL(BP) \
(((BP)->tx_cons <= (BP)->tx_prod) ? \
(BP)->tx_cons + (BP)->tx_pending - (BP)->tx_prod : \
(BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP))
#define NEXT_TX(N) (((N) + 1) & (B44_TX_RING_SIZE - 1))
#define RX_PKT_OFFSET 30
#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET + 64)
#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
#define B44_PATTERN_BASE 0x400
#define B44_PATTERN_SIZE 0x80
#define B44_PMASK_BASE 0x600
#define B44_PMASK_SIZE 0x10
#define B44_MAX_PATTERNS 16
#define B44_ETHIPV6UDP_HLEN 62
#define B44_ETHIPV4UDP_HLEN 42
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION "\n";
MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
MODULE_DESCRIPTION("Broadcom 44xx/47xx 10/100 PCI ethernet driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
static int b44_debug = -1;
module_param(b44_debug, int, 0);
MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
#ifdef CONFIG_B44_PCI
static const struct pci_device_id b44_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
static struct pci_driver b44_pci_driver = {
.name = DRV_MODULE_NAME,
.id_table = b44_pci_tbl,
};
#endif
//關于device_id:PCI設備都遵守PCI標準,這個部分所有的PCI設備都是一樣的,每個PCI設備都有一段寄存器存儲著配置空間,這一部分格式是一樣的,
//比如第一個寄存器總是生產商號碼,如Realtek就是10ec,而Intel則是另一個數字,這些都是商家像標準組織申請的,是肯定不同的。
//我就可以通過配置空間來辨別其生產商,設備號,不論你什么平臺,x86也好,ppc也好,他們都是同一的標準格式
//這里b44_ssb_tbl就是用來匹配配置空間的如果b44_ssb_tbl和配置空間中的相同,就表明這個驅動程序就是用來驅動這個設備的
static const struct ssb_device_id b44_ssb_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV),
SSB_DEVTABLE_END
};
。。。。。。。
//超時函數
static void b44_tx_timeout(struct net_device *dev)
{
struct b44 *bp = netdev_priv(dev);
printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
dev->name);
spin_lock_irq(&bp->lock);
b44_halt(bp); //終止網卡
b44_init_rings(bp);
b44_init_hw(bp, B44_FULL_RESET);
spin_unlock_irq(&bp->lock);
b44_enable_ints(bp);
netif_wake_queue(dev); //喚醒網卡等待隊列
}
。。。。。。。。。。。
//打開設備函數
//這個函數一般是用來注冊所有系統(tǒng)資源包括IO端口,IRQ DMA等
static int b44_open(struct net_device *dev)
{
struct b44 *bp = netdev_priv(dev); //獲得網卡私有數據地址
int err;
err = b44_alloc_consistent(bp, GFP_KERNEL);
if (err)
goto out;
napi_enable(&bp->napi); //napi是采用輪詢的方式接受數據包見設備驅動p518
b44_init_rings(bp);
b44_init_hw(bp, B44_FULL_RESET); //做硬件初始化
b44_check_phy(bp);
err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); //注冊中斷
if (unlikely(err < 0)) {
napi_disable(&bp->napi);
b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
b44_free_rings(bp);
b44_free_consistent(bp);
goto out;
}
init_timer(&bp->timer);
bp->timer.expires = jiffies + HZ;
bp->timer.data = (unsigned long) bp;
bp->timer.function = b44_timer;
add_timer(&bp->timer);
b44_enable_ints(bp);
netif_start_queue(dev);
out:
return err;
}
。。。。。。。。。。。。。。。
//此函數初始話和注冊net_device結構體
static int __devinit b44_init_one(struct ssb_device *sdev,
const struct ssb_device_id *ent)
{
static int b44_version_printed = 0;
struct net_device *dev; //net_device指針
struct b44 *bp; //網卡信息結構指針是net_device結構體的一員,就是linux設備驅動里講的那個priv結構體
//它代表著不同網卡的私有數據,比如Intel的網卡和Realtek的網卡在內核中都是以net_device來代表。
//但是他們是有區(qū)別的,比如Intel和Realtek實現同一功能的方法不一樣,這些都是靠著priv來體現。
//所以這里把拿出來同net_device相提并論。分配內存時,net_device中除了priv以外的成員都是固定的,
//而priv的大小是可以任意的,所以分配時要把priv的大小傳過去。
//priv在net_device結構體里是void *priv; void類型指針所以可以指向任何類型的priv結構體
int err;
DECLARE_MAC_BUF(mac);
instance++;
if (b44_version_printed++ == 0)
printk(KERN_INFO "%s", version);
//分配net_device結構體空間,參數是priv的大小
//這個函數是alloc_netdev的封裝,不但分配空間在做些必須的初始化
dev = alloc_etherdev(sizeof(*bp));
if (!dev) {
dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto out;
}
SET_NETDEV_DEV(dev, sdev->dev);
dev->features |= 0;
bp = netdev_priv(dev);
bp->sdev = sdev;
bp->dev = dev;
bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
spin_lock_init(&bp->lock);
bp->rx_pending = B44_DEF_RX_RING_PENDING;
bp->tx_pending = B44_DEF_TX_RING_PENDING;
//一下是給一些函數指針賦值具體可以看設備驅動一書
dev->open = b44_open;
dev->stop = b44_close;
dev->hard_start_xmit = b44_start_xmit;
dev->get_stats = b44_get_stats;
dev->set_multicast_list = b44_set_rx_mode;
dev->set_mac_address = b44_set_mac_addr;
dev->do_ioctl = b44_ioctl;
dev->tx_timeout = b44_tx_timeout;
netif_napi_add(dev, &bp->napi, b44_poll, 64);
dev->watchdog_timeo = B44_TX_TIMEOUT;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = b44_poll_controller;
#endif
dev->change_mtu = b44_change_mtu;
dev->irq = sdev->irq;
SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
netif_carrier_off(dev);
err = ssb_bus_powerup(sdev->bus, 0);
if (err) {
dev_err(sdev->dev,
"Failed to powerup the bus\n");
goto err_out_free_dev;
}
err = ssb_dma_set_mask(sdev, DMA_30BIT_MASK);
if (err) {
dev_err(sdev->dev,
"Required 30BIT DMA mask unsupported by the system.\n");
goto err_out_powerdown;
}
err = b44_get_invariants(bp);
if (err) {
dev_err(sdev->dev,
"Problem fetching invariants of chip, aborting.\n");
goto err_out_powerdown;
}
bp->mii_if.dev = dev;
bp->mii_if.mdio_read = b44_mii_read;
bp->mii_if.mdio_write = b44_mii_write;
bp->mii_if.phy_id = bp->phy_addr;
bp->mii_if.phy_id_mask = 0x1f;
bp->mii_if.reg_num_mask = 0x1f;
bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL |
B44_FLAG_ADV_100HALF | B44_FLAG_ADV_100FULL);
bp->flags |= B44_FLAG_PAUSE_AUTO;
//注冊net_device結構體
err = register_netdev(dev);
if (err) {
dev_err(sdev->dev, "Cannot register net device, aborting.\n");
goto err_out_powerdown;
}
ssb_set_drvdata(sdev, dev);
b44_chip_reset(bp, B44_CHIP_RESET_FULL);
printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n",
dev->name, print_mac(mac, dev->dev_addr));
return 0;
err_out_powerdown:
ssb_bus_may_powerdown(sdev->bus);
err_out_free_dev:
free_netdev(dev);
out:
return err;
}
static void __devexit b44_remove_one(struct ssb_device *sdev)
{
struct net_device *dev = ssb_get_drvdata(sdev);
unregister_netdev(dev);
ssb_bus_may_powerdown(sdev->bus);
free_netdev(dev);
ssb_pcihost_set_power_state(sdev, PCI_D3hot);
ssb_set_drvdata(sdev, NULL);
}
static struct ssb_driver b44_ssb_driver = {
.name = DRV_MODULE_NAME, //模塊名字
.id_table = b44_ssb_tbl, //模塊id表
.probe = b44_init_one, //探針 用來初始化 注冊 netdev結構
.remove = __devexit_p(b44_remove_one),
.suspend = b44_suspend,
.resume = b44_resume,
};
//register pci
static inline int b44_pci_init(void)
{
int err = 0;
#ifdef CONFIG_B44_PCI
err = ssb_pcihost_register(&b44_pci_driver);
#endif
return err;
}
//unregister pci
static inline void b44_pci_exit(void)
{
#ifdef CONFIG_B44_PCI
ssb_pcihost_unregister(&b44_pci_driver);
#endif
}
//初始化函數,用來注冊pci設備和ssb驅動
static int __init b44_init(void)
{
//這里是dma的一些設置,設備驅動一書中有介紹,我本人也還沒看
unsigned int dma_desc_align_size = dma_get_cache_alignment();
int err;
dma_desc_align_mask = ~(dma_desc_align_size - 1);
dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
err = b44_pci_init();
if (err)
return err;
err = ssb_driver_register(&b44_ssb_driver);
if (err)
b44_pci_exit();
return err;
}
static void __exit b44_cleanup(void)
{
ssb_driver_unregister(&b44_ssb_driver);
b44_pci_exit();
}
//設置模塊加載時的初始化函數
module_init(b44_init);
//設置模塊卸載時運行的函數
module_exit(b44_cleanup);