dm9000驅動分析



1.關於write函數條用過程
write
--->sock_aio_write
------>do_sock_write
--------->__sock_sendmsg /*--->協議無關層*/


sock->ops->sendmsg   /*--->協議棧(以udp爲例)*/
--->udp_sendmsg
---->ip_route_output_flow(選擇路由)
----->ip_push_pending_frames
------->ip_local_out
--------->dst_output
---------->skb_dst(skb)->output(skb)
------------>ip_finish_output
--------------->ip_finish_output2
------------------>neigh->ops->queue_xmit(skb)
--------------------->dev_queue_xmit-->dev_hard_start_xmit
------------------------>ops->ndo_start_xmit(skb, dev); /*調用設備驅動中的發送函數(dm9000.c)*/


2.dm9000.c函數分析
--2.1 關於dm9000_probe ()
--{
 /* Init network device */
 ndev = alloc_etherdev(sizeof(struct board_info));
 
 * setup board info structure */
 db = netdev_priv(ndev);
 
 /*映射dm9000 地址端口 和 數據端口 (s3c6410-->io_phyaddr = 1800 0000 ;-->data_phyaddr = 1800 0004*/
 osize = resource_size(db->addr_res);
 db->addr_req = request_mem_region(db->addr_res->start, iosize,
       pdev->name);

 if (db->addr_req == NULL) {
  dev_err(db->dev, "cannot claim address reg area\n");
  ret = -EIO;
  goto out;
 }

 db->io_addr = ioremap(db->addr_res->start, iosize);           /*映射io端口*/

 if (db->io_addr == NULL) {
  dev_err(db->dev, "failed to ioremap address reg\n");
  ret = -EINVAL;
  goto out;
 }

 iosize = resource_size(db->data_res);
 db->data_req = request_mem_region(db->data_res->start, iosize, /*映射data端口*/
       pdev->name);
 
 /*其他設置板級包db(省略...)*/
 
 dm9000_set_io(db, iosize);
 
 dm9000_reset(db);//復位dm9000
 
 /* 設置ndev*/ 
 ether_setup(ndev);
 
 ndev->netdev_ops = &dm9000_netdev_ops;                
 ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
 ndev->ethtool_ops = &dm9000_ethtool_ops;

 /*註冊net_device*/ 
 ret = register_netdev(ndev);   
 
--} 

--2.2 關於dm9000_open( )
--{
 board_info_t *db = netdev_priv(dev);/*取得板級包*/
 
 if(request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) /*註冊中斷*/
  return -EAGAIN;
  
 /* Initialize DM9000 board */
 dm9000_reset(db);
 
 dm9000_init_dm9000(dev);
 
 /*檢查連接狀態,開啓發送隊列*/
 mii_check_media(&db->mii, netif_msg_link(db), 1);
 netif_start_queue(dev);
 
--}

--2.3 關於發送數據包函數--dm9000_start_xmit( )
--{
  /* Move data to DM9000 TX RAM */
  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++;    /*tx_pkt_cnt在ether_setup(ndev)函數中值設爲0*/
  
  /* TX control: First packet immediately send, second packet queue */
  if (db->tx_pkt_cnt == 1) {
   dm9000_send_packet(dev, skb->ip_summed, skb->len);
   {
    /* Set TX length to DM9000 */
    iow(dm, DM9000_TXPLL, pkt_len);
    iow(dm, DM9000_TXPLH, pkt_len >> 8);
   
    /* set  the bit1 of DM9000_TCR before tx data */
    iow(dm, DM9000_TCR, TCR_TXREQ); /*automatic Cleare the bit-TCR_TXREQ  after TX complete */ 
   }
  } else {
   /* Second packet */
   db->queue_pkt_len = skb->len;
   db->queue_ip_summed = skb->ip_summed;
   
   netif_stop_queue(dev);
  }
  
  /* free this SKB */
  dev_kfree_skb(skb);
--}

--當發送數據完了以後,產生髮送中斷(在dm9000_open中註冊)--->dm9000_interrupt
-->dm9000_tx_done
--{ 
 int tx_status = ior(db, DM9000_NSR); /* Got TX status */

 if (tx_status & (NSR_TX2END | NSR_TX1END)) {
  /* One packet sent complete */
  db->tx_pkt_cnt--;
  dev->stats.tx_packets++;

  if (netif_msg_tx_done(db))
   dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);

  /* Queue packet check & send */
  if (db->tx_pkt_cnt > 0)  /*表明還有數據包要發送, 就接着發送*/
   dm9000_send_packet(dev, db->queue_ip_summed, db->queue_pkt_len);
       
  netif_wake_queue(dev);  /*dm9000只能有兩個數據包在發送, 超過兩個。就讓其在隊列裏面等待 netif_stop_queue(dev);*/
--}

2.4.關於數據包接受函數--dm9000_rx( )
 當有數據包產生時,就產生中斷,進入中斷處理函數dm9000_interrupt(), 
-->接着調用dm9000_rx(struct net_device *dev)
--{
 board_info_t *db = netdev_priv(dev);
 struct dm9000_rxhdr rxhdr;
 struct sk_buff *skb;
 u8 rxbyte, *rdptr;
 bool GoodPacket;
 int RxLen;

 /* Check packet ready or not */
 do {
  ior(db, DM9000_MRCMDX); /* Dummy read */

  /* Get most updated data */
  rxbyte = readb(db->io_data);

  /* Status check: this byte must be 0 or 1 */
  if (rxbyte & DM9000_PKT_ERR) {
   dev_warn(db->dev, "status check fail: %d\n", rxbyte);
   iow(db, DM9000_RCR, 0x00); /* Stop Device */
   iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
   return;
  }

  if (!(rxbyte & DM9000_PKT_RDY))
   return;

  /* A packet ready now  & Get status/length (4個字節)*/
  GoodPacket = true;
  writeb(DM9000_MRCMD, db->io_addr);

  (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); 

  RxLen = le16_to_cpu(rxhdr.RxLen);

  if (netif_msg_rx_status(db))
   dev_dbg(db->dev, "RX: status %02x, length %04x\n",
    rxhdr.RxStatus, RxLen);

  /* Packet Status check */
  if (RxLen < 0x40) {
   GoodPacket = false;
   if (netif_msg_rx_err(db))
    dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
  }

  if (RxLen > DM9000_PKT_MAX) {
   dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
  }

  .....................
  /*構造數據包,並將數據包送個上層協議棧*/
  /* Move data from DM9000 */
  if (GoodPacket &&
      ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {
   skb_reserve(skb, 2);         /*ip包4字節對齊 */
   rdptr = (u8 *) skb_put(skb, RxLen - 4);    /*除去cfs*/

   /* Read received packet from RX SRAM */

   (db->inblk)(db->io_data, rdptr, RxLen);
   dev->stats.rx_bytes += RxLen;

   /* Pass to upper layer */
   skb->protocol = eth_type_trans(skb, dev);
   if (db->rx_csum) {
    if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
     skb->ip_summed = CHECKSUM_UNNECESSARY;
    else
     skb_checksum_none_assert(skb);
   }
   netif_rx(skb);                                 /*將數據包交給上層協議棧*/
   dev->stats.rx_packets++;

  } else {
   /* need to dump the packet's data */

   (db->dumpblk)(db->io_data, RxLen);
  }
 } while (rxbyte & DM9000_PKT_RDY);
--}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章