機電之家資源網
單片機首頁|單片機基礎|單片機應用|單片機開發(fā)|單片機文案|軟件資料下載|音響制作|電路圖下載 |嵌入式開發(fā)
培訓信息
贊助商
Linux-2.6.20的cs8900驅動分析(三)(轉載)
Linux-2.6.20的cs8900驅動分析(三)(轉載)
 更新時間:2009-8-12 16:51:54  點擊數:0
【字體: 字體顏色
http://blog.chinaunix.net/u1/49924/showart_488190.html 
Linux-2.6.20的cs8900驅動分析(三)
三、net_rxnet_send_packet3.1 net_rx在這部分將介紹cs8900驅動的兩個最重要的函數,內核通過該兩個函數實現了數據的收發(fā)。net_rx函數的主要功能是從cs8900的片上數據緩沖區(qū)中將數據傳送給sk_buff緩沖區(qū),sk_buff是網絡驅動程序與Linux內核通信的緩沖區(qū)。該結構可在<top_dir>\include\linux\skbuff.h中找到。net_rx函數的功能可總結如下:(該總結來源于:http://www.akae.cn/bbs/archiver/?tid-6657.htmlA.獲取私有數據存放于lp中;B.獲取設備緩沖區(qū)狀態(tài)和緩沖長度;C.如果狀態(tài)不為RX_OK則計數接收數據錯誤次數count_rx_error()D.分配一個sk_buf區(qū)間E.字對齊,skb_reserve();F.插入數據到接收口,insw();G.寫入數據;H.初始化sk_buff結構,eth_type_trans()I.進入上層接收函數netif_rx();J.初始化設備的計數;net_rx函數的注解如下所示:static void net_rx(struct net_device *dev){       struct net_local *lp = netdev_priv(dev);             //lp指向驅動程序的私有數據區(qū)       struct sk_buff *skb;                             //申請skb_buff指針       int status, length;        int ioaddr = dev->base_addr;                       // 得到cs8900的基地址       status = readword(ioaddr, RX_FRAME_PORT);       //獲取cs8900片上緩沖區(qū)的狀態(tài)       length = readword(ioaddr, RX_FRAME_PORT);       //獲取cs8900片上緩沖區(qū)的長度        if ((status & RX_OK) == 0) {          //狀態(tài)為接收錯誤,調用count_rx_errors統計錯誤              count_rx_errors(status, lp);              return;       }        /* Malloc up new buffer. */       skb = dev_alloc_skb(length + 2); //分配一個緩沖區(qū),dev_alloc_skb函數以三、net_rxnet_send_packet3.1 net_rx在這部分將介紹cs8900驅動的兩個最重要的函數,內核通過該兩個函數實現了數據的收發(fā)。net_rx函數的主要功能是從cs8900的片上數據緩沖區(qū)中將數據傳送給sk_buff緩沖區(qū),sk_buff是網絡驅動程序與Linux內核通信的緩沖區(qū)。該結構可在<top_dir>\include\linux\skbuff.h中找到。net_rx函數的功能可總結如下:(該總結來源于:http://www.akae.cn/bbs/archiver/?tid-6657.htmlA.獲取私有數據存放于lp中;B.獲取設備緩沖區(qū)狀態(tài)和緩沖長度;C.如果狀態(tài)不為RX_OK則計數接收數據錯誤次數count_rx_error()D.分配一個sk_buf區(qū)間E.字對齊,skb_reserve();F.插入數據到接收口,insw();G.寫入數據;H.初始化sk_buff結構,eth_type_trans()I.進入上層接收函數netif_rx()J.初始化設備的計數; net_rx函數的注解如下所示:static void net_rx(struct net_device *dev){       struct net_local *lp = netdev_priv(dev);             //lp指向驅動程序的私有數據區(qū)       struct sk_buff *skb;                             //申請skb_buff指針       int status, length;        int ioaddr = dev->base_addr;                       // 得到cs8900的基地址       status = readword(ioaddr, RX_FRAME_PORT);       //獲取cs8900片上緩沖區(qū)的狀態(tài)       length = readword(ioaddr, RX_FRAME_PORT);       //獲取cs8900片上緩沖區(qū)的長度        if ((status & RX_OK) == 0) {    //狀態(tài)為接收錯誤,調用count_rx_errors統計錯誤              count_rx_errors(status, lp);              return;       }        /* Malloc up new buffer. */       skb = dev_alloc_skb(length + 2);             //分配一個緩沖區(qū),dev_alloc_skb函數以                   //GFP_ATOMIC優(yōu)先級調用alloc_skb。alloc_skb的功能為分配一個緩沖區(qū)                   //并初始化skb->dataskb->tailskb_head域。dev_alloc_skballoc_skb的區(qū)                   //別為,前者在skb->dataskb_head之間保留了一些空間,網絡層使用這                   //一數據空間進行優(yōu)化工作,驅動程序不該訪問該空間。       if (skb == NULL) {    //skb緩沖區(qū)分配失?……              lp->stats.rx_dropped++;  //直接將丟包數加1              return;       }       skb_reserve(skb, 2);      /* longword align L3 header */    //該函數增加skbdatatail,               //該函數可填充緩沖區(qū)之前保留報文頭空間,大多數以太網在數據包之前               //保留2個字節(jié),這樣IP頭可在14字節(jié)的以太網頭之后,在16字節(jié)邊界上對               //齊。這里也空了兩個字節(jié),這兩個自己加上14字節(jié)的以太網頭剛好16              //節(jié)。所以這里的主要作用是字對齊。       skb->dev = dev;        readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1);  //skb_put            //數的作用是更新skbtaillen成員,也即在緩沖區(qū)尾部添加數據,該函數返            //skb->tail的先前值。整句代碼的含義為,cs8900的數據緩沖區(qū)中讀取      //length個字節(jié)數據到skb緩沖區(qū)。由于readwords是以讀取字(兩個字節(jié))為            //單位,所以length應該保持字對齊,也即length右移一位。       if (length & 1)       //因為前面length以字對齊,如果length為單字節(jié),                                   //所以這里應該補上最后一個字節(jié)              skb->data[length-1] = readword(ioaddr, RX_FRAME_PORT);……        skb->protocol=eth_type_trans(skb,dev);  //該函數定義在linux/net/ethernet/eth.c中,                                                 //該處可參見linux設備驅動程序相關章節(jié)       netif_rx(skb);       //通知內核已經接收到一個數據包,并封裝入一個套接字緩沖區(qū)       dev->last_rx = jiffies;                    //更新最后的接收包時間       lp->stats.rx_packets++;                //接收的總數據包數加1       lp->stats.rx_bytes += length;         //接收的字節(jié)數加上length} 3.1 net_send_packet       net_send_parcket為內核提供了數據包發(fā)送功能,該函數在cs89x0_probe1中被賦予了net_devicehard_start_xmit域,當內核需要發(fā)送數據包時,將調用dev-> hard_start_xmit完成最后的數據包發(fā)送。該函數被調用的前提是,在調用該函數之前,內核已經將數據包放入了skb緩沖區(qū)中。該函數的主要任務有:A.獲取設備私有數據指針B.加環(huán)形鎖,spin_lock_irq();C.檢測緩沖區(qū)是否為滿,若滿則調用netif_stop_queue()暫停發(fā)送隊列;D.寫發(fā)送命令和發(fā)送長度,writeword();E.讀取發(fā)送總線狀態(tài)readreg()F.解環(huán)形鎖,spin_unlock_irq()G.設置傳輸時鐘計數;H.釋放相應sk_buff, dev_kfree_skb().下面為此函數的簡單注釋:static int net_send_packet(struct sk_buff *skb, struct net_device *dev){       struct net_local *lp = netdev_priv(dev);            //獲得驅動程序的私有數據 ……        spin_lock_irq(&lp->lock);         //獲得自旋鎖,以便進入臨界區(qū)       netif_stop_queue(dev);    //通知內核暫停內核與驅動程序間的數據傳遞,也即告訴                                              //內核不要向skb緩沖區(qū)填充數據。        /* initiate a transmit sequence */  //初始化cs8900的發(fā)送對列,主要為寫命令和數                                                         //據長度,為數據發(fā)送做準備       writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd);       writeword(dev->base_addr, TX_LEN_PORT, skb->len);        /* Test to see if the chip has allocated memory for the packet * /       //查看cs8900是否為                                                                                      //發(fā)送分配了地址空間。       if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {           …….              spin_unlock_irq(&lp->lock);              if (net_debug) printk("cs89x0: Tx buffer not free!\n");              return 1;       }       /* Write the contents of the packet */       writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);  //將數                                                                                                               //據交給cs8900發(fā)送       spin_unlock_irq(&lp->lock);         //發(fā)送結束,釋放自旋鎖       lp->stats.tx_bytes += skb->len;    //累加發(fā)送的總字節(jié)數       dev->trans_start = jiffies;             //更新最后的傳輸時間       dev_kfree_skb (skb);                  //發(fā)送完畢,釋放skb緩沖區(qū)    ……       return 0;}總結:       cs8900驅動中,主要簡解了驅動程序中的部分重要函數,包括初始化、打開/關閉網絡驅動和發(fā)送/接收數據。對于其余的驅動程序代碼,如超時處理、狀態(tài)獲取等函數沒做解釋,它們的實現也比較簡單。由于自己板子上沒有EEPROM,所以也沒有分析與EEPROM相關部分的代碼。DMA部分好像編譯進去會錯,所以也沒有去分析,以后有時間再去弄弄DMA部分。                                                                                              The End                                                                                             ------ anmnmnly                                                                                             ------ 2007.12.16
  • 上一篇: Linux-2.6.20的cs8900驅動分析(二)(轉載)
  • 下一篇: Linux 2.6.19.x 內核編譯配置選項簡介(轉載)
  • 發(fā)表評論   告訴好友   打印此文  收藏此頁  關閉窗口  返回頂部
    熱點文章
     
    推薦文章
     
    相關文章
    網友評論:(只顯示最新5條。)
    關于我們 | 聯系我們 | 廣告合作 | 付款方式 | 使用幫助 | 機電之家 | 會員助手 | 免費鏈接

    點擊這里給我發(fā)消息66821730(技術支持)點擊這里給我發(fā)消息66821730(廣告投放) 點擊這里給我發(fā)消息41031197(編輯) 點擊這里給我發(fā)消息58733127(審核)
    本站提供的機電設備,機電供求等信息由機電企業(yè)自行提供,該企業(yè)負責信息內容的真實性、準確性和合法性。
    機電之家對此不承擔任何保證責任,有侵犯您利益的地方請聯系機電之家,機電之家將及時作出處理。
    Copyright 2007 機電之家 Inc All Rights Reserved.機電之家-由機電一體化網更名-聲明
    電話:0571-87774297 傳真:0571-87774298
    杭州濱興科技有限公司提供技術支持

    主辦:杭州市高新區(qū)(濱江)機電一體化學會
    中國行業(yè)電子商務100強網站

    網站經營許可證:浙B2-20080178-1