小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

broadcom網卡驅動 代碼分析注釋

 jijo 2008-05-20
broadcom網卡驅動 代碼分析注釋 (2008-05-03 21:11:08)

 //注釋者: 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);

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多