<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > ARM-Linux驅動--DM9000網(wǎng)卡驅動分析(三)

          ARM-Linux驅動--DM9000網(wǎng)卡驅動分析(三)

          作者: 時間:2016-11-20 來源:網(wǎng)絡 收藏
          ARM-Linux驅動--DM9000網(wǎng)卡驅動分析(二)硬件平臺:FL2440(s3c2440
          內核版本:2.6.35
          主機平臺:Ubuntu11.04
          內核版本:2.6.39
          交叉編譯器:arm-linuc-gcc4.3.2
          原創(chuàng)作品,轉載請標明出處http://blog.csdn.net/yming0221/article/details/6615027
          本文接上文
          ARM-Linux驅動--DM9000網(wǎng)卡驅動分析(一)
          ARM-Linux驅動--DM9000網(wǎng)卡驅動分析(二)
          下面開始看網(wǎng)卡設備的打開、關閉函數(shù)和操作函數(shù)
          view plainprint?
          static const struct net_device_ops dm9000_netdev_ops = {
          .ndo_open = dm9000_open,
          .ndo_stop = dm9000_stop,
          .ndo_start_xmit = dm9000_start_xmit,
          .ndo_tx_timeout = dm9000_timeout,
          .ndo_set_multicast_list = dm9000_hash_table,
          .ndo_do_ioctl = dm9000_ioctl,
          .ndo_change_mtu = eth_change_mtu,
          .ndo_validate_addr = eth_validate_addr,
          .ndo_set_mac_address = eth_mac_addr,
          #ifdef CONFIG_NET_POLL_CONTROLLER
          .ndo_poll_controller = dm9000_poll_controller,
          #endif
          };
          1、DM9000的打開函數(shù)
          由于在函數(shù)alloc_netdev_mq()中分配net_device和網(wǎng)卡的私有數(shù)據(jù)是一起分配的,詳見函數(shù)的實現(xiàn)
          view plainprint?
          struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
          void (*setup)(struct net_device *), unsigned int queue_count)
          {
          ...................
          alloc_size = sizeof(struct net_device);
          if (sizeof_priv) {
          alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
          alloc_size += sizeof_priv;
          }
          alloc_size += NETDEV_ALIGN - 1;
          p = kzalloc(alloc_size, GFP_KERNEL);
          if (!p) {
          printk(KERN_ERR "alloc_netdev: Unable to allocate device.n");
          return NULL;
          }
          tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL);
          if (!tx) {
          printk(KERN_ERR "alloc_netdev: Unable to allocate "
          "tx qdiscs.n");
          goto free_p;
          }
          #ifdef CONFIG_RPS
          rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);
          if (!rx) {
          printk(KERN_ERR "alloc_netdev: Unable to allocate "
          "rx queues.n");
          goto free_tx;
          }
          ..............
          }
          所以使用函數(shù)netdev_priv()函數(shù)返回的是網(wǎng)卡的私有數(shù)據(jù)的地址,函數(shù)的實現(xiàn)如下:
          view plainprint?
          static inline void *netdev_priv(const struct net_device *dev)
          {
          return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
          }
          這樣兩者會同時生存和消失。
          dm9000_open()函數(shù)
          view plainprint?
          static int
          dm9000_open(struct net_device *dev)
          {
          board_info_t *db = netdev_priv(dev);
          unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
          if (netif_msg_ifup(db))
          dev_dbg(db->dev, "enabling %sn", dev->name);
          if (irqflags == IRQF_TRIGGER_NONE)
          dev_warn(db->dev, "WARNING: no IRQ resource flags set.n");
          irqflags |= IRQF_SHARED;
          if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
          return -EAGAIN;
          dm9000_reset(db);
          dm9000_init_dm9000(dev);
          db->dbug_cnt = 0;
          mii_check_media(&db->mii, netif_msg_link(db), 1);
          netif_start_queue(dev);
          dm9000_schedule_poll(db);
          return 0;
          }
          2、網(wǎng)卡關閉函數(shù)
          view plainprint?
          static int
          dm9000_stop(struct net_device *ndev)
          {
          board_info_t *db = netdev_priv(ndev);
          if (netif_msg_ifdown(db))
          dev_dbg(db->dev, "shutting down %sn", ndev->name);
          cancel_delayed_work_sync(&db->phy_poll);
          netif_stop_queue(ndev);
          netif_carrier_off(ndev);
          free_irq(ndev->irq, ndev);
          dm9000_shutdown(ndev);
          return 0;
          }
          下面是調用的dm9000_shutdown(ndev)函數(shù),該函數(shù)的功能是復位phy,配置寄存器GPR位0為1,關閉dm9000電源,配置寄存器IMR位7為1,disable中斷,配置寄存器RCR,disable接收
          函數(shù)如下:
          view plainprint?
          static void
          dm9000_shutdown(struct net_device *dev)
          {
          board_info_t *db = netdev_priv(dev);
          dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);
          iow(db, DM9000_GPR, 0x01);
          iow(db, DM9000_IMR, IMR_PAR);
          iow(db, DM9000_RCR, 0x00);
          }
          3、接下來了解一下數(shù)據(jù)的發(fā)送函數(shù)dm9000_start_xmit
          上圖可以看出DM9000的SRAM中地址0x0000到0x0BFF是TXBuffer,從0x0C00到0x3FFF是RXBuffer,包的有效數(shù)據(jù)必須提前放到TXBuffer緩沖區(qū),使用端口命令來選擇MWCMD寄存器。最后設置TXCR寄存器的bit[0]TXREQ來自動發(fā)送包。
          發(fā)送包的步驟如下:
          (1)檢查存儲器寬度,通過讀取ISR的bit[7:6]來確定位數(shù)
          (2)寫數(shù)據(jù)到TXSRAM
          (3)寫傳輸長度到TXPLL和TXPLH寄存器
          (4)設置TXCR的bit[0]TXREQ來發(fā)送包
          view plainprint?
          static int
          dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
          {
          unsigned long flags;
          board_info_t *db = netdev_priv(dev);
          dm9000_dbg(db, 3, "%s:n", __func__);
          if (db->tx_pkt_cnt > 1)
          return NETDEV_TX_BUSY;
          spin_lock_irqsave(&db->lock, flags);
          writeb(DM9000_MWCMD, db->io_addr);
          (db->outblk)(db->io_data, skb->data, skb->len);
          dev->stats.tx_bytes += skb->len;
          db->tx_pkt_cnt++;
          if (db->tx_pkt_cnt == 1) {
          dm9000_send_packet(dev, skb->ip_summed, skb->len);
          } else {
          db->queue_pkt_len = skb->len;
          db->queue_ip_summed = skb->ip_summed;
          netif_stop_queue(dev);
          }
          spin_unlock_irqrestore(&db->lock, flags);
          dev_kfree_skb(skb);
          return NETDEV_TX_OK;
          }
          上面函數(shù)調用下面的函數(shù) dm9000_send_packet來發(fā)送數(shù)據(jù)
          view plainprint?
          static void dm9000_send_packet(struct net_device *dev,
          int ip_summed,
          u16 pkt_len)
          {
          board_info_t *dm = to_dm9000_board(dev);
          if (dm->ip_summed != ip_summed) {
          if (ip_summed == CHECKSUM_NONE)
          iow(dm, DM9000_TCCR, 0);
          else
          iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
          dm->ip_summed = ip_summed;
          }
          iow(dm, DM9000_TXPLL, pkt_len);
          iow(dm, DM9000_TXPLH, pkt_len >> 8);
          iow(dm, DM9000_TCR, TCR_TXREQ);
          }
          5、下面看一下當一個數(shù)據(jù)包發(fā)送完成后的中斷處理函數(shù)dm9000_tx_done
          view plainprint?
          static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
          {
          int tx_status = ior(db, DM9000_NSR);
          if (tx_status & (NSR_TX2END | NSR_TX1END)) {
          db->tx_pkt_cnt--;
          dev->stats.tx_packets++;
          if (netif_msg_tx_done(db))
          dev_dbg(db->dev, "tx done, NSR xn", tx_status);
          if (db->tx_pkt_cnt > 0)
          dm9000_send_packet(dev, db->queue_ip_summed,
          db->queue_pkt_len);
          netif_wake_queue(dev);
          }
          }


          評論


          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();