ワイヤレス主導の移行と開発-MTKソースコード分析



Wireless Driven Migration



最初

MTKdirver upは、上位層の操作中に次の一般的な手順を実行します。

  1. /var/Wireless/RT2860AP/RT2860AP.datなどのワイヤレス変更構成ファイルはhostapd.confとして見ることができます
  2. 電力制限/ var / Wireless / RT2860AP / SingleSKU.datを変更し、ハードウェアの放出制限を超える電力を防止して、PAを焼き付けます
  3. EEPROMを変更し、主にMAC、​​無線送信電力など、MTXXX_EEPROM_Guidelineの特定の参照値を変更します。
  4. insmod mt-wifi.ko
  5. ifconfig ra0 up
  6. brctl addif br0 ra0

次に、主に駆動源から上記のステップまでを詳しく説明します



insmod mt-wifi.ko

Module_initは、ドライバーで直接検索します。ソースM7628の対象は次のとおりです。

int __init rt2880_module_init(void) { .... RtmpRaDevCtrlInit (pAd, RTMP_DEV_INF_RBUS) // initialize PRTMP_ADAPTER .... net_dev = RtmpPhyNetDevInit (pAd, & netDevHook) // initialize pDevOpHook .... rv = RtmpOSNetDevAttach (pAd-> OpMode, net_dev, & netDevHook) // initialize the ops netdev .... }

より重要な機能としての、ワイヤレスネットワークデバイスのRtmpOSNetDevAttach初期化操作



pNetDevOps->ndo_open = MainVirtualIF_open pNetDevOps->ndo_stop = MainVirtualIF_close pNetDevOps->ndo_start_xmit =rt28xx_send_packets pNetDevOps->ndo_do_ioctl = rt28xx_ioctl pNetDev->wireless_handlers = rt28xx_ap_iw_handler_def if (rtnl_locked) ret = register_netdevice(pNetDev) else ret = register_netdev(pNetDev) netif_stop_queue(pNetDev)

最後に、register_netdeviceホームネットワーク機器とnetif_stop_queueストップキュー。netdevice名はRtmpPhyNetDevMainCreateで変更する必要があります。この関数は、RtmpPhyNetDevInitによって呼び出されます。

ifconfig ra0 up

フレーズコマンドが呼び出されますpNetDevOps-> ndo_open、つまりMainVirtualIF_open:

int MainVirtualIF_open(struct net_device *net_dev) { ... if (VIRTUAL_IF_UP (pAd)! = 0) // continue up interface return -1 .... // open network queue netif_start_queue(net_dev) netif_carrier_on(net_dev) netif_wake_queue(net_dev) return 0 }

ioctl呼び出しrt28xx_openによるVIRTUAL_IF_UP



int rt28xx_open(VOID *dev) { ... RtmpOSIRQRequest(net_dev)//request irq RTMP_DRIVER_IRQ_INIT(pAd) if (rt28xx_init (pAd, mac, hostname) == FALSE) // init drive goto err .... / * Initialize The following are other wifi interface, they will not mention * / RT28xx_MBSS_Init(pAd, net_dev)//Multi BSS RT28xx_WDS_Init(pAd, net_dev)// WDS fuction RT28xx_ApCli_Init(pAd, net_dev)//ap client RT28xx_Monitor_Init(pAd, net_dev)//sniffer .... RTMPDrvOpen (pAd) // open bottom drive, hardware-related txrx ... }

より重要な機能は3つ以上あります。

  1. RtmpOSIRQRequestアプリケーションソフトウェア割り込み、主にパケットの受信に使用されます
  2. rt28xx_initドライブの初期化、構成ファイルの読み取り、EEPROMはこの機能に含まれています
  3. RTMPDrvOpenオープンエンド、オープンハードウェアスイッチなど

rt28xx_initstartを開始するには以下を参照してください

int rt28xx_init(VOID *pAdSrc, RTMP_STRING *pDefaultMac, RTMP_STRING *pHostName) { Status = RtmpNetTaskInit (pAd) // registration packet kernel work RtmpMgmtTaskInit (pAd) // Registration frames kernel work /* initialize MLME*/ Status = MlmeInit(pAd) if (rtmp_cfg_init (pAd, pHostName)! = TRUE) // reads the configuration file goto err5 if (MCUSysInit(pAd) != NDIS_STATUS_SUCCESS)//load firmware goto err6 RtmpChipOpsEepromHook (pAd, pAd-> infType, E2P_NONE) // initialize chipops, in order to prepare to read EEPROM NICReadEEPROMParameters (pAd, (RTMP_STRING *) pDefaultMac) // read EEPROM APStartUp (pAd) // initialize wdev, the actual function of contracting MlmeRadioOn(pAd) }

RtmpNetTaskInitは、rxタスクレットの初期化などのパケットの例です。

RTMP_OS_TASKLET_INIT(pAd, &pObj->rx_done_task, rx_done_tasklet, (unsigned long)pAd) RTMP_OS_TASKLET_INIT(pAd, &pObj->bcn_dma_done_task, bcn_dma_done_tasklet, (unsigned long)pAd) RTMP_OS_TASKLET_INIT(pAd, &pObj->mt_mac_int_0_task, mt_mac_int_0_tasklet, (unsigned long)pAd) RTMP_OS_TASKLET_INIT(pAd, &pObj->mt_mac_int_1_task, mt_mac_int_1_tasklet, (unsigned long)pAd) RTMP_OS_TASKLET_INIT(pAd, &pObj->mt_mac_int_2_task, mt_mac_int_2_tasklet, (unsigned long)pAd) RTMP_OS_TASKLET_INIT(pAd, &pObj->mt_mac_int_3_task, mt_mac_int_3_tasklet, (unsigned long)pAd) RTMP_OS_TASKLET_INIT(pAd, &pObj->mt_mac_int_4_task, mt_mac_int_4_tasklet, (unsigned long)pAd) RTMP_OS_TASKLET_INIT(pAd, &pObj->bmc_dma_done_task, bmc_dma_done_tasklet, (unsigned long)pAd) ........ RTMP_OS_TASKLET_INIT(pAd, &pObj->dfs_task, dfs_tasklet, (unsigned long)pAd)

rtmp_cfg_init読み取り/var/Wireless/RT2860AP/RT2860AP.datおよび/var/Wireless/RT2860AP/SingleSKU.dat、ワイヤレス構成

RTMPReadParametersHook // reads the configuration parameters AP_PROFILE_PATH_RBUS in, it can be seen as hostapd.conf RTMPSetSingleSKUParameters // read SINGLE_SKU_TABLE_FILE_NAME, storing the transmit power limit

NICReadEEPROMParametersは、特定のRtmpChipOpsEepromHookで定義されたeepromまたはフラッシュeepromキャリブレーション値から読み取られ、rtmp_nv_initを呼び出してから、構成値をeepromの無線に送信します

NDIS_STATUS rtmp_nv_init(RTMP_ADAPTER *pAd) { spiflash_ioctl_read(pAd->eebuf, DEFAULT_RF_OFFSET, EEPROM_SIZE) rtmp_ee_flash_init (pAd, pAd-> eebuf) // flash disposed in question is read from the default EEPROM_DEFAULT_FILE_PATH EEPROM file, stored MAC, radio calibration, etc. }

wdev_init、初期化wdev APStartUpを呼び出すと、実際の契約関数APHardTransmitを確認できます。

wdev->tx_pkt_allowed = ApAllowToSendPacket wdev->tx_pkt_handle = APSendPacket wdev->wdev_hard_tx = APHardTransmit wdev->rx_pkt_allowed = ap_rx_pkt_allow wdev->rx_ps_handle = ap_rx_ps_handle wdev->rx_pkt_foward = ap_rx_foward_handle

この時点で、ネットワーク層全体が基盤となる構成に組み込まれ、送受信パケットキューが開かれます。次のコードは、単純な分析パケットトランシーバーです。

ra0契約

Ra0デバイスは、送信されたパケットのネットワークプロトコルスタックを受信し、最初にpNetDevOps-> ndo_start_xmit = rt28xx_send_packetsに、ドリブンフォワード関数に関係なく、直接wdev_tx_pktsに入力します。

INT wdev_tx_pkts(NDIS_HANDLE dev_hnd, PPNDIS_PACKET pkt_list, UINT pkt_cnt, struct wifi_dev *wdev) { if ((wdev->allow_data_tx == TRUE)&& (wdev->tx_pkt_allowed)) { allowToSend = wdev->tx_pkt_allowed(pAd, wdev, pPacket, &wcid) } else { allowToSend = FALSE } if (allowToSend == TRUE) { if (wdev->tx_pkt_handle) wdev->tx_pkt_handle(pAd, pPacket) } RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, WCID_ALL, MAX_TX_PROCESS) }

wdev_tx_pktsより重要な関数には3つあります:tx_pkt_allowed tx_pkt_handle RTMPDeQueuePacket

最初の2つの関数は、APStartUp wdev_initが初期化される前に呼び出され、対応する関数は次のようになります。

wdev->tx_pkt_allowed = ApAllowToSendPacket wdev->tx_pkt_handle = APSendPacket

ApAllowToSendPacket目的のMacがデバイスに関連付けられているかどうかを確認します。許可されている場合は、許可されていません。

INT APSendPacket(RTMP_ADAPTER *pAd, PNDIS_PACKET pPacket) { sta_num=0 Total_Packet_Number = 0 for (i=0 iMacTab.Content[i] tr_entry_tmp = &pAd->MacTab.tr_entry[pEntry->wcid] /* dump all MacTable entries */ if (pEntry->EntryType == ENTRY_NONE) continue sta_num++ Total_Packet_Number = Total_Packet_Number + tr_entry_tmp->ps_queue.Number for (j = 0 j tx_queue[j].Number } // check message for all associated clients, if over 1024 and more than three clients, drop the packet if (Total_Packet_Number > 1024 && sta_num > 3) { //DBG_WARN('too many packets cached in all tr_entry, do not enq 0x%08x ', pPacket) drop_reason = 12 goto drop_pkt } // decide WMM queue wdev = tr_entry->wdev UserPriority = 0 QueIdx = QID_AC_BE if (RTMPCheckEtherType(pAd, pPacket, tr_entry, wdev, &UserPriority, &QueIdx) == FALSE) { drop_reason = INVALID_ETH_TYPE goto drop_pkt } // fragmented packet processing RTMP_SET_PACKET_FRAGMENTS(pPacket, NumberOfFrag) // After the WMM priority queue exceeds the length of the stop to close the network interface, usually set to 512 if (pAd->TxSwQueue[QueIdx].Number >= pAd->TxSwQMaxLen) { { #ifdef BLOCK_NET_IF StopNetIfQueue(pAd, QueIdx, pPacket) #endif /* BLOCK_NET_IF */ drop_reason = DROP_TXQ_FULL goto drop_pkt } } // the message into the team rtmp_enq_req(pAd, pPacket, QueIdx, tr_entry, FALSE,NULL); }

パケットをエンキューし、RTMPDeQueuePacketを呼び出して、各キューパケットのコントラクトプロセスを呼び出します。実際に呼び出されるコントラクトはAPHardTransmit wdev_initで定義され、実際のハードウェア送信コントラクト関数を駆動します

inline VOID _RTMPDeQueuePacket( IN RTMP_ADAPTER *pAd, IN BOOLEAN in_hwIRQ, IN UCHAR QIdx, IN INT wcid, IN INT max_cnt) { do { DEQUEUE_LOCK (& pAd-> irq_lock, in_hwIRQ, IrqFlags) // lock // get the packet queue, not to take out of the loop rtmp_deq_req(pAd, max_cnt, &deq_info) DEQUEUE_UNLOCK (& pAd-> irq_lock, in_hwIRQ, IrqFlags) // release the lock RTMP_START_DEQUEUE(pAd, QueIdx, IrqFlags,deq_info) DEQUEUE_LOCK(&pAd->irq_lock, in_hwIRQ, IrqFlags) deq_packet_gatter(pAd, &deq_info, pTxBlk, in_hwIRQ) DEQUEUE_UNLOCK(&pAd->irq_lock, in_hwIRQ, IrqFlags) if (pTxBlk->wdev && pTxBlk->wdev->wdev_hard_tx) { pTxBlk-> wdev-> wdev_hard_tx (pAd, pTxBlk) // call APHardTransmit } }while(1) }

パケット受信ra0

RtmpOSIRQRequestの呼び出しについて話し合ったときにra0が開く前に、ソフト割り込みが登録されました

request_irq(pci_dev->irq, rt2860_interrupt, SA_SHIRQ, (net_dev)->name, (net_dev))

ハードウェアを受信した後、ソフトパケット割り込みハンドラrt2860_interruptをトリガーします

VOID RTMPHandleInterrupt(VOID *pAdSrc) { /* Inital the Interrupt source. */ IntSource = 0x00000000L // source terminal, according to the various calls to kernel tasklet if (pAd->chipCap.hif_type == HIF_MT) { RTMP_IO_READ32(pAd, MT_INT_SOURCE_CSR, &IntSource) // rx packets received for it if (IntSource & INT_RX_DATA) { pAd->RxDMACheckTimes = 0 pAd->RxPseCheckTimes = 0 if ((pAd->int_disable_mask & INT_RX_DATA) == 0) { rt2860_int_disable (pAd, INT_RX_DATA) // close the rx interrupt is accepted RTMP_OS_TASKLET_SCHE (& pObj-> rx_done_task) // schedule rx of tasklet } pAd->int_pending |= INT_RX_DATA } }

また、RtmpNetTaskInitのrx_done_taskは、次の関数タスクレットで定義されています:rx_done_tasklet、rtmp_rx_done_handleを呼び出す

BOOLEAN rtmp_rx_done_handle(RTMP_ADAPTER *pAd) { // pick up the message from rxring pRxPacket = GetPacketFromRxRing(pAd, pRxBlk, &bReschedule, &RxPending, 0) // select a different function from the message type rx switch (pHeader->FC.Type) { case FC_TYPE_DATA: // Packet dev_rx_data_frm(pAd, &rxblk) break case FC_TYPE_MGMT: dev_rx_mgmt_frm(pAd, &rxblk) break case FC_TYPE_CNTL: dev_rx_ctrl_frm(pAd, &rxblk) break default: RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE) break } }

コールスタックdev_rx_data_frm関数は次のとおりです。netif_rxに到達するには、ネットワークプロトコルスタックに移動し、ここでの状況を考慮しませんでした。ampdu、forwardなど。

dev_rx_data_frm ---rx_data_frm_announce ---Indicate_Legacy_Packet ---Announce_or_Forward_802_3_Packet ---announce_802_3_packet ---RtmpOsPktRcvHandle ---netif_rx

参照文書

MT768_EEPROM_Guideline