男女午夜激情_www.天堂av.com_亚洲综合小说区_亚洲欧美自拍视频_成年精品_久久www免费人成—看片_激情综合五月天_久久高潮视频_最新国产成人ab网站_国产精品卡一

機電之家資源網
單片機首頁|單片機基礎|單片機應用|單片機開發|單片機文案|軟件資料下載|音響制作|電路圖下載 |嵌入式開發
培訓信息
贊助商
Linux-2.6.20的cs8900驅動分析(二)(轉載)
Linux-2.6.20的cs8900驅動分析(二)(轉載)
 更新時間:2009-8-12 16:51:49  點擊數:0
【字體: 字體顏色
http://blog.chinaunix.net/u1/49924/showart_488183.html  
Linux-2.6.20的cs8900驅動分析(二)

二、net_opennet_closenet_interrupt

2.1 net_opennet_close

net_open函數主要完成的工作有:(這段net_open函數的概要內容總結來源于網絡,網址:http://www.akae.cn/bbs/archiver/?tid-6657.html

A.獲取私有數據指針存放于lp

B.啟動設備總線控制功能和啟動存儲器

C.調用request_irq()請求中斷并注冊net_interrupt為中斷服務程序;

D.寫中斷號存于設備中write_irq()

E.如果無法申請中斷號,則返回錯誤

F.如果支持DMA則通過以下函數初始化DMA

              _get_dma_pages();

              get_order();

               dma_page_eq();

G.申請DMArequeset_dma()

H.初始化設備結構中關于DMA的參數,并使能DMA

I.設置以太網地址,writereg()

J.檢測鏈路,從而確定連接媒體類型

K.配置鏈路:

               a.10B_T:detect_tp()

              b.AUI:detect_aui()

              c.10B_2:detect_bnu()

               d.AUT從頭檢測自動配置

L.輸出信息

M.啟動鏈路串行接收和發送功能

N.初始化lp相關參數

O.配置DMAset_dma_cfg()

P.配置芯片相關寄存器

Q.配置DMA緩沖dma_bufcfg()

R.使能芯片中斷;

S.啟動網絡傳輸隊列,netif_start_queue()

       這部分內容都與cs8900芯片具體操作相關,相對來說和比較簡單,下面直接給出net_opennet_close的相關注解

static int net_open(struct net_device *dev)

{

       struct net_local *lp = netdev_priv(dev);

       int result = 0;

       int i;

       int ret;

 

      ......//省略一些信息

/* FIXME: Cirrus' release had this: */

       writereg(dev, PP_BusCTL, readreg(dev,PP_BusCTL)|ENABLE_IRQ);//使能cs8900中斷

     write_irq(dev, lp->chip_type, dev->irq);//該函數選擇cs8900芯片內部的中斷線,

二、net_opennet_closenet_interrupt

2.1 net_opennet_close

net_open函數主要完成的工作有:(這段net_open函數的概要內容總結來源于網絡,網址:http://www.akae.cn/bbs/archiver/?tid-6657.html

A.獲取私有數據指針存放于lp

B.啟動設備總線控制功能和啟動存儲器

C.調用request_irq()請求中斷并注冊net_interrupt為中斷服務程序;

D.寫中斷號存于設備中write_irq()

E.如果無法申請中斷號,則返回錯誤

F.如果支持DMA則通過以下函數初始化DMA

              _get_dma_pages();

              get_order();

               dma_page_eq();

G.申請DMArequeset_dma()

H.初始化設備結構中關于DMA的參數,并使能DMA

I.設置以太網地址,writereg()

J.檢測鏈路,從而確定連接媒體類型

K.配置鏈路:

               a.10B_T:detect_tp()

              b.AUI:detect_aui()

              c.10B_2:detect_bnu()

               d.AUT從頭檢測自動配置

L.輸出信息

M.啟動鏈路串行接收和發送功能

N.初始化lp相關參數

O.配置DMAset_dma_cfg()

P.配置芯片相關寄存器

Q.配置DMA緩沖dma_bufcfg()

R.使能芯片中斷;

S.啟動網絡傳輸隊列,netif_start_queue()

       這部分內容都與cs8900芯片具體操作相關,相對來說和比較簡單,下面直接給出net_opennet_close的相關注解

static int net_open(struct net_device *dev)

{

       struct net_local *lp = netdev_priv(dev);

       int result = 0;

       int i;

       int ret;

 

      ......//省略一些信息

/* FIXME: Cirrus' release had this: */

       writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );                                                           //使能cs8900中斷

             

     write_irq(dev, lp->chip_type, dev->irq);     //該函數選擇cs8900芯片內部的中斷線,

                                                                       //見本文件中的write_irq實現

//++++++++++++++++++++++這段代碼為自己添加,內核原版中沒有

#if defined(CONFIG_ARCH_S3C2410)

           set_irq_type(dev->irq, IRQT_RISING);  //該函數在kernel\irq\chip實現,

        //可選擇的中斷類型有include\linux\interrupt.h中定義,此處設置為上升沿觸發中斷

#endif

//++++++++++++++++++++++

              ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev); //注冊中斷

              if (ret) {

                     if (net_debug)

                            printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq);

                     goto bad_out;

              }

……

 

       /* set the Ethernet address *///MAC地址設置到cs8900Individual Address寄存器

       for (i=0; i < ETH_ALEN/2; i++)

              writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));

 

       /* while we're testing the interface, leave interrupts disabled */

       writereg(dev, PP_BusCTL, MEMORY_ON);  //使cd8900工作到memory模式,

                                                                               //如果dev->mem_start域為0

     //將關閉該模式

 

 

       //以下代碼為選擇cs8900的物理傳輸媒體的類型

       /* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */

       //由于沒有eepromlp->adapter_cnfcs89x0_probe1中未設置,此值為0.

       if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH))

                lp->linectl = LOW_RX_SQUELCH;

       else

                lp->linectl = 0;

 

        /* check to make sure that they have the "right" hardware available */

       switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {

       case A_CNF_MEDIA_10B_T: result = lp->adapter_cnf & A_CNF_10B_T; break;

       case A_CNF_MEDIA_AUI:   result = lp->adapter_cnf & A_CNF_AUI; break;

       case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;

        default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);

        }

 

#if defined(CONFIG_ARCH_PNX0105) || defined(CONFIG_ARCH_S3C2410)//+++++++++

       result = A_CNF_10B_T;    //上面由于lp->adapter_cnf=0,導致result=0

         //這里額外設置該值可以根據需要實際情況設置,可設置的值可在

        //cs89x0.h中找到當然這里也可以設置lp->adapter_cnf成想要的值

#endif

        if (!result) {//result==0時執行此段代碼

                printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);

        release_irq:

        ......

                writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));

                free_irq(dev->irq, dev);

              ret = -EAGAIN;

              goto bad_out;

       }

 

        /* set the hardware to the configured choice */

       switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {//lp->adapter_cnf & A_CNF_MEDIA_TYPE==0,

                                                   //不符合任何case情況,將執行default,但未實現default

       case A_CNF_MEDIA_10B_T:

                result = detect_tp(dev);  //detect_tp探測物理傳輸媒體類型是RJ-45H,

                                                     //還是RJ-45F

                if (result==DETECTED_NONE) {

                        printk(KERN_WARNING "%s: 10Base-T (RJ-45) has no cable\n", dev->name);

                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */

                                result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */

                }

              break;

       case A_CNF_MEDIA_AUI:

                result = detect_aui(dev);//detect_tp探測物理傳輸媒體類型是否為AUI

                if (result==DETECTED_NONE) {

                        printk(KERN_WARNING "%s: 10Base-5 (AUI) has no cable\n", dev->name);

                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */

                                result = DETECTED_AUI; /* Yes! I don't care if I see a carrrier */

                }

              break;

       case A_CNF_MEDIA_10B_2:

                result = detect_bnc(dev);  //detect_tp探測物理傳輸媒體類型是否為BNC

                if (result==DETECTED_NONE) {

                        printk(KERN_WARNING "%s: 10Base-2 (BNC) has no cable\n", dev->name);

                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */

                                result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */

                }

              break;

       case A_CNF_MEDIA_AUT

              writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET);

              if (lp->adapter_cnf & A_CNF_10B_T)

                     if ((result = detect_tp(dev)) != DETECTED_NONE)

                            break;

              if (lp->adapter_cnf & A_CNF_AUI)

                     if ((result = detect_aui(dev)) != DETECTED_NONE)

                            break;

              if (lp->adapter_cnf & A_CNF_10B_2)

                     if ((result = detect_bnc(dev)) != DETECTED_NONE)

                            break;

              printk(KERN_ERR "%s: no media detected\n", dev->name);

                goto release_irq;

       }

       switch(result) {     //上面將result賦成了A_CNF_10B_T,該值為1,剛好等于

                 //DETECTED_RJ45H所以也可以在上面的result中直接賦成

                 //DETECTED_RJ45H或者其他類型的接口

       case DETECTED_NONE:

              printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name);

                goto release_irq;

       case DETECTED_RJ45H:

              printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);

              break;

       case DETECTED_RJ45F:

              printk(KERN_INFO "%s: using full-duplex 10Base-T (RJ-45)\n", dev->name);

              break;

       case DETECTED_AUI:

              printk(KERN_INFO "%s: using 10Base-5 (AUI)\n", dev->name);

              break;

       case DETECTED_BNC:

              printk(KERN_INFO "%s: using 10Base-2 (BNC)\n", dev->name);

              break;

       }

 

       /* Turn on both receive and transmit operations */

       writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);

 

       /* Receive only error free packets addressed to this card */

       lp->rx_mode = 0;//確定接收模式,0表示接收廣播, 0表示全部接收

       writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);    //初始化接收控制器RxCTL為默認

                      //接收模式。該模式下,只接收BroadcastIndividualCRC

                                            //正確的數據包,具體可查看cs8900手冊。

 

       lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;   //接收OK產生中斷,

                                                      //CRC錯產生中斷

 

       if (lp->isa_config & STREAM_TRANSFER)//判斷是否打開cs8900stream傳輸模式

              lp->curr_rx_cfg |= RX_STREAM_ENBL;//使用stream模式,此處沒有啟用。

 

       writereg(dev, PP_RxCFG, lp->curr_rx_cfg);       //初始化接收配置控制器RxCFG

                                                                                  //這里確定了接收中斷源

 

  //初始化發送配置控制器TxCFGTxCFG寄存器的全部有效位置為1

  //也確定了發送中斷源

       writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |

              TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);

 

       writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |

 

              TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);

 

       /* now that we've got our act together, enable everything */

       writereg(dev, PP_BusCTL, ENABLE_IRQ          //開中斷

               | (dev->mem_start?MEMORY_ON : 0)      //沒有設置共享內存空

                                                              //dev->mem_start0memory模式將被關閉

 

                 );

        netif_start_queue(dev);  //激活設備發送隊列,以便內核可以開始發送數據

       if (net_debug > 1)

              printk("cs89x0: net_open() succeeded\n");

       return 0;

bad_out:

       return ret;

}

 

 

net_close(struct net_device *dev)

{

  ......//略去DMA部分

 

       netif_stop_queue(dev);//停止設備發送隊列,通知內核不能使用該設備發送數據

 

       writereg(dev, PP_RxCFG, 0);//禁用接收

       writereg(dev, PP_TxCFG, 0);//禁用發送

       writereg(dev, PP_BufCFG, 0);//關閉cs8900內部緩沖區

       writereg(dev, PP_BusCTL, 0);//停止總線

 

       free_irq(dev->irq, dev);//釋放占用的中斷線

 

  ......//略去DMA部分

 

       /* Update the statistics here. */

       return 0;

}

2.2 net_interrupt

       該函數的大體流程如下:(此段總結來源同上)

A.獲取設備私有數據net_priv()

B.讀取CS8900的中斷端口狀態readword()

C.判斷中斷類型:

              a.接收事件:調用net_rx()接收數據;

              b.傳輸事件:調用netif_wake_queue()喚醒傳輸隊列,進行異常處理;

              c.緩沖區事件:可以發送數據,調用netif_wake_queue()喚醒傳輸隊列;

              d.接收包丟失事件:初始化相關error,錯誤計數

e.傳輸沖突時間:初始化相關error

D.返回中斷句柄。

net_interrupt中斷處理函數的實現非常簡單,它首先讀出cs8900ISQ寄存器的值,然后根據ISQ的值分別處理各種情況。當中斷發生時,這些中斷實際反映在相應的寄存器中,ISQ寄存器用低6位記錄了當前寄存器的編號,高10位記錄了當前寄存器的實際內容。這些寄存器有:RxEvent(Register 4)TxEvent(Register 8)BufEvent(RegisterC)RxMISS(Register 10) TxCOL(Register 12)。比如,傳輸成功后,cs8900TxEvent的第0bit置為1,如果允許該事件中斷,那么ISQ寄存器的低6位將記錄TxEvent的編號8,并且將TxEvent寄存器的高10copy到它的高10位中。

       net_interrupt注解如下:

 

static irqreturn_t net_interrupt(int irq, void *dev_id)

{

       struct net_device *dev = dev_id;

       struct net_local *lp;

       int ioaddr, status;

      int handled = 0;

 

       ioaddr = dev->base_addr;

       lp = netdev_priv(dev);

 

       /* we MUST read all the events out of the ISQ, otherwise we'll never

           get interrupted again.  As a consequence, we can't have any limit

           on the number of times we loop in the interrupt handler.  The

           hardware guarantees that eventually we'll run out of events.  Of

           course, if you're on a slow machine, and packets are arriving

           faster than you can read them off, you're screwed.  Hasta la

           vista, baby!  */

       while ((status = readword(dev->base_addr, ISQ_PORT))) {

   //ISQ_PORT=08h,根據cs8900的用戶手冊,這里再次說明了cs8900工作在I/O模式

              if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);

              handled = 1;

              switch(status & ISQ_EVENT_MASK) {    //ISQ_EVENT_MASK=0x3f

                                   //確定ISQ的低6位,6位紀錄了發生中斷的寄存器

              case ISQ_RECEIVER_EVENT:     //ISQ_RECEIVER_EVENT=0x04,

                                         //中斷源來自RxEvent表示接收到了數據包

                     /* Got a packet(s). */

                     net_rx(dev);

                     break;

              case ISQ_TRANSMITTER_EVENT:   //ISQ_RECEIVER_EVENT=0x08,

                       //中斷源來自TxEvent,根據 net_open中設置,有很多發送事件

                     //可以產生中斷,需要分別處理

                     lp->stats.tx_packets++;    //累加發送包的總數

                     netif_wake_queue(dev);  /* Inform upper layers. */ 

                     if ((status & ( TX_OK |    //ISQ的高10位描述了TxEvent的實際內容,

                              //也即實際傳輸的信息這里似乎status應該右移6位?的確應該

                              //這樣,這里之所以沒這樣做,是因為TX_OK等這些值,在設

                              //計時已經左移了6

                                   TX_LOST_CRS |

                                   TX_SQE_ERROR |

                                   TX_LATE_COL |

                                   TX_16_COL)) != TX_OK) {  //做些錯誤統計工作

                            if ((status & TX_OK) == 0) lp->stats.tx_errors++;

                            if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;

                            if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;

                            if (status & TX_LATE_COL) lp->stats.tx_window_errors++;

                            if (status & TX_16_COL) lp->stats.tx_aborted_errors++;

                     }

                     break;

              case ISQ_BUFFER_EVENT:  //ISQ_RECEIVER_EVENT=0x0c,

                                                              //中斷源來自BufEvent

      if (status & TX_UNDERRUN) {   //這里說明估計的發送長度過短,可能需要做調整

                            if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);

                                lp->send_underrun++;

                                if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; //此值cs89x0_probe1時初始化為5,這里修正。

                                else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;

                            /* transmit cycle is done, although

                               frame wasn't transmitted - this

                               avoids having to wait for the upper

                               layers to timeout on us, in the

                               event of a tx underrun */

                            netif_wake_queue(dev); /* Inform upper layers. */

                        }

      ......//DMA部分

                     break;

              case ISQ_RX_MISS_EVENT:  //ISQ_RX_MISS_EVENT=0x10,

                                         //中斷來自于RxMISS該寄存器的高10位記錄丟失的數據包

                     lp->stats.rx_missed_errors += (status >>6);

                     break;

              case ISQ_TX_COL_EVENT:        //ISQ_TX_COL_EVENT=0x12,中斷來自于

                //TxCOL該寄存器的高10位記錄發了生沖突的數據包

                     lp->stats.collisions += (status >>6);

                     break;

              }

       }

       return IRQ_RETVAL(handled);

}

                                                                                       To be continued……

                                                                                 ------ anmnmnly

                                                                                 ------ 2007.12.5

  • 上一篇: Linux-2.6.20的cs8900驅動分析(一)(轉載)
  • 下一篇: Linux-2.6.20的cs8900驅動分析(三)(轉載)
  • 發表評論   告訴好友   打印此文  收藏此頁  關閉窗口  返回頂部
    熱點文章
     
    推薦文章
     
    相關文章
    網友評論:(只顯示最新5條。)
    關于我們 | 聯系我們 | 廣告合作 | 付款方式 | 使用幫助 | 機電之家 | 會員助手 | 免費鏈接

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

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

    網站經營許可證:浙B2-20080178-1
    主站蜘蛛池模板: 贡觉县| 三河市| 穆棱市| 黔西县| 五台县| 惠来县| 莱芜市| 高邑县| 三原县| 中超| 宝坻区| 通河县| 和龙市| 库伦旗| 建湖县| 时尚| 怀化市| 杭锦后旗| 潞西市| 梁平县| 海淀区| 莆田市| 碌曲县| 青川县| 新津县| 巴塘县| 渝北区| 阳城县| 会昌县| 台州市| 封开县| 青州市| 公安县| 泸溪县| 伊金霍洛旗| 那坡县| 东光县| 七台河市| 许昌县| 那坡县| 新乡市|