diff options
Diffstat (limited to 'drivers/staging/rt3070/2870_main_dev.c')
-rw-r--r-- | drivers/staging/rt3070/2870_main_dev.c | 1627 |
1 files changed, 1627 insertions, 0 deletions
diff --git a/drivers/staging/rt3070/2870_main_dev.c b/drivers/staging/rt3070/2870_main_dev.c new file mode 100644 index 00000000000..401ddb01213 --- /dev/null +++ b/drivers/staging/rt3070/2870_main_dev.c @@ -0,0 +1,1627 @@ +/* + ************************************************************************* + * Ralink Tech Inc. + * 5F., No.36, Taiyuan St., Jhubei City, + * Hsinchu County 302, + * Taiwan, R.O.C. + * + * (c) Copyright 2002-2007, Ralink Technology, Inc. + * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + ************************************************************************* + + Module Name: + rtmp_main.c + + Abstract: + main initialization routines + + Revision History: + Who When What + -------- ---------- ---------------------------------------------- + Name Date Modification logs + Jan Lee 01-10-2005 modified + Sample Jun/01/07 Merge RT2870 and RT2860 drivers. +*/ + +#include "rt_config.h" + + +// Following information will be show when you run 'modinfo' +// *** If you have a solution for the bug in current version of driver, please mail to me. +// Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** +MODULE_AUTHOR("Paul Lin <paul_lin@ralinktech.com>"); +MODULE_DESCRIPTION("RT2870 Wireless Lan Linux Driver"); +#ifdef CONFIG_STA_SUPPORT +MODULE_LICENSE("GPL"); +#ifdef MODULE_VERSION +MODULE_VERSION(STA_DRIVER_VERSION); +#endif +#endif // CONFIG_STA_SUPPORT // + +#ifdef MULTIPLE_CARD_SUPPORT +// record whether the card in the card list is used in the card file +extern UINT8 MC_CardUsed[]; +#endif // MULTIPLE_CARD_SUPPORT // + +/* Kernel thread and vars, which handles packets that are completed. Only + * packets that have a "complete" function are sent here. This way, the + * completion is run out of kernel context, and doesn't block the rest of + * the stack. */ +//static int mlme_kill = 0; // Mlme kernel thread +//static int RTUSBCmd_kill = 0; // Command kernel thread +//static int TimerFunc_kill = 0; // TimerQ kernel thread + +//static wait_queue_head_t timerWaitQ; +//static wait_queue_t waitQ; + +extern INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, + IN UINT argc, OUT PRTMP_ADAPTER *ppAd); + + +/* module table */ +struct usb_device_id rtusb_usb_id[] = RT2870_USB_DEVICES; +INT const rtusb_usb_id_len = sizeof(rtusb_usb_id) / sizeof(struct usb_device_id); +MODULE_DEVICE_TABLE(usb, rtusb_usb_id); + +#ifndef PF_NOFREEZE +#define PF_NOFREEZE 0 +#endif + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + +/**************************************************************************/ +/**************************************************************************/ +//tested for kernel 2.4 series +/**************************************************************************/ +/**************************************************************************/ +static void *rtusb_probe(struct usb_device *dev, UINT interface, + const struct usb_device_id *id_table); +static void rtusb_disconnect(struct usb_device *dev, void *ptr); + +struct usb_driver rtusb_driver = { + name:"rt2870", + probe:rtusb_probe, + disconnect:rtusb_disconnect, + id_table:rtusb_usb_id, + }; + +#else + +#ifdef CONFIG_PM +static int rt2870_suspend(struct usb_interface *intf, pm_message_t state); +static int rt2870_resume(struct usb_interface *intf); +#endif // CONFIG_PM // + +/**************************************************************************/ +/**************************************************************************/ +//tested for kernel 2.6series +/**************************************************************************/ +/**************************************************************************/ +static int rtusb_probe (struct usb_interface *intf, + const struct usb_device_id *id); +static void rtusb_disconnect(struct usb_interface *intf); + +struct usb_driver rtusb_driver = { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + .owner = THIS_MODULE, +#endif + .name="rt2870", + .probe=rtusb_probe, + .disconnect=rtusb_disconnect, + .id_table=rtusb_usb_id, + +#ifdef CONFIG_PM + suspend: rt2870_suspend, + resume: rt2870_resume, +#endif + }; + +#ifdef CONFIG_PM + +VOID RT2860RejectPendingPackets( + IN PRTMP_ADAPTER pAd) +{ + // clear PS packets + // clear TxSw packets +} + +static int rt2870_suspend( + struct usb_interface *intf, + pm_message_t state) +{ + struct net_device *net_dev; + PRTMP_ADAPTER pAd = usb_get_intfdata(intf); + + + DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_suspend()\n")); + net_dev = pAd->net_dev; + netif_device_detach(net_dev); + + pAd->PM_FlgSuspend = 1; + if (netif_running(net_dev)) { + RTUSBCancelPendingBulkInIRP(pAd); + RTUSBCancelPendingBulkOutIRP(pAd); + } + DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_suspend()\n")); + return 0; +} + +static int rt2870_resume( + struct usb_interface *intf) +{ + struct net_device *net_dev; + PRTMP_ADAPTER pAd = usb_get_intfdata(intf); + + + DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_resume()\n")); + + pAd->PM_FlgSuspend = 0; + net_dev = pAd->net_dev; + netif_device_attach(net_dev); + netif_start_queue(net_dev); + netif_carrier_on(net_dev); + netif_wake_queue(net_dev); + + DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_resume()\n")); + return 0; +} +#endif // CONFIG_PM // +#endif // LINUX_VERSION_CODE // + + +// Init driver module +INT __init rtusb_init(void) +{ + printk("rtusb init --->\n"); + return usb_register(&rtusb_driver); +} + +// Deinit driver module +VOID __exit rtusb_exit(void) +{ + usb_deregister(&rtusb_driver); + printk("<--- rtusb exit\n"); +} + +module_init(rtusb_init); +module_exit(rtusb_exit); + + + + +/*--------------------------------------------------------------------- */ +/* function declarations */ +/*--------------------------------------------------------------------- */ + +/* +======================================================================== +Routine Description: + MLME kernel thread. + +Arguments: + *Context the pAd, driver control block pointer + +Return Value: + 0 close the thread + +Note: +======================================================================== +*/ +INT MlmeThread( + IN void *Context) +{ + PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Context; + POS_COOKIE pObj; + int status; + + pObj = (POS_COOKIE)pAd->OS_Cookie; + + rtmp_os_thread_init("rt2870MlmeThread", (PVOID)&(pAd->mlmeComplete)); + + while (pAd->mlme_kill == 0) + { + /* lock the device pointers */ + //down(&(pAd->mlme_semaphore)); + status = down_interruptible(&(pAd->mlme_semaphore)); + + /* lock the device pointers , need to check if required*/ + //down(&(pAd->usbdev_semaphore)); + + if (!pAd->PM_FlgSuspend) + MlmeHandler(pAd); + + /* unlock the device pointers */ + //up(&(pAd->usbdev_semaphore)); + if (status != 0) + { + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); + break; + } + } + + /* notify the exit routine that we're actually exiting now + * + * complete()/wait_for_completion() is similar to up()/down(), + * except that complete() is safe in the case where the structure + * is getting deleted in a parallel mode of execution (i.e. just + * after the down() -- that's necessary for the thread-shutdown + * case. + * + * complete_and_exit() goes even further than this -- it is safe in + * the case that the thread of the caller is going away (not just + * the structure) -- this is necessary for the module-remove case. + * This is important in preemption kernels, which transfer the flow + * of execution immediately upon a complete(). + */ + DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__)); + + pObj->MLMEThr_pid = NULL; + + complete_and_exit (&pAd->mlmeComplete, 0); + return 0; + +} + + +/* +======================================================================== +Routine Description: + USB command kernel thread. + +Arguments: + *Context the pAd, driver control block pointer + +Return Value: + 0 close the thread + +Note: +======================================================================== +*/ +INT RTUSBCmdThread( + IN void * Context) +{ + PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Context; + POS_COOKIE pObj; + int status; + + pObj = (POS_COOKIE)pAd->OS_Cookie; + + rtmp_os_thread_init("rt2870CmdThread", (PVOID)&(pAd->CmdQComplete)); + + NdisAcquireSpinLock(&pAd->CmdQLock); + pAd->CmdQ.CmdQState = RT2870_THREAD_RUNNING; + NdisReleaseSpinLock(&pAd->CmdQLock); + + while (pAd->CmdQ.CmdQState == RT2870_THREAD_RUNNING) + { + /* lock the device pointers */ + //down(&(pAd->RTUSBCmd_semaphore)); + status = down_interruptible(&(pAd->RTUSBCmd_semaphore)); + + if (pAd->CmdQ.CmdQState == RT2870_THREAD_STOPED) + break; + + if (status != 0) + { + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); + break; + } + /* lock the device pointers , need to check if required*/ + //down(&(pAd->usbdev_semaphore)); + + if (!pAd->PM_FlgSuspend) + CMDHandler(pAd); + + /* unlock the device pointers */ + //up(&(pAd->usbdev_semaphore)); + } + + if (!pAd->PM_FlgSuspend) + { // Clear the CmdQElements. + CmdQElmt *pCmdQElmt = NULL; + + NdisAcquireSpinLock(&pAd->CmdQLock); + pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; + while(pAd->CmdQ.size) + { + RTUSBDequeueCmd(&pAd->CmdQ, &pCmdQElmt); + if (pCmdQElmt) + { + if (pCmdQElmt->CmdFromNdis == TRUE) + { + if (pCmdQElmt->buffer != NULL) + NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0); + + NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0); + } + else + { + if ((pCmdQElmt->buffer != NULL) && (pCmdQElmt->bufferlength != 0)) + NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0); + { + NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0); + } + } + } + } + + NdisReleaseSpinLock(&pAd->CmdQLock); + } + /* notify the exit routine that we're actually exiting now + * + * complete()/wait_for_completion() is similar to up()/down(), + * except that complete() is safe in the case where the structure + * is getting deleted in a parallel mode of execution (i.e. just + * after the down() -- that's necessary for the thread-shutdown + * case. + * + * complete_and_exit() goes even further than this -- it is safe in + * the case that the thread of the caller is going away (not just + * the structure) -- this is necessary for the module-remove case. + * This is important in preemption kernels, which transfer the flow + * of execution immediately upon a complete(). + */ + DBGPRINT(RT_DEBUG_TRACE,( "<---RTUSBCmdThread\n")); + + pObj->RTUSBCmdThr_pid = NULL; + + complete_and_exit (&pAd->CmdQComplete, 0); + return 0; + +} + + +static void RT2870_TimerQ_Handle(RTMP_ADAPTER *pAd) +{ + int status; + RALINK_TIMER_STRUCT *pTimer; + RT2870_TIMER_ENTRY *pEntry; + unsigned long irqFlag; + + while(!pAd->TimerFunc_kill) + { +// printk("waiting for event!\n"); + pTimer = NULL; + + status = down_interruptible(&(pAd->RTUSBTimer_semaphore)); + + if (pAd->TimerQ.status == RT2870_THREAD_STOPED) + break; + + // event happened. + while(pAd->TimerQ.pQHead) + { + RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlag); + pEntry = pAd->TimerQ.pQHead; + if (pEntry) + { + pTimer = pEntry->pRaTimer; + + // update pQHead + pAd->TimerQ.pQHead = pEntry->pNext; + if (pEntry == pAd->TimerQ.pQTail) + pAd->TimerQ.pQTail = NULL; + + // return this queue entry to timerQFreeList. + pEntry->pNext = pAd->TimerQ.pQPollFreeList; + pAd->TimerQ.pQPollFreeList = pEntry; + } + RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlag); + + if (pTimer) + { + if (pTimer->handle != NULL) + if (!pAd->PM_FlgSuspend) + pTimer->handle(NULL, (PVOID) pTimer->cookie, NULL, pTimer); + if ((pTimer->Repeat) && (pTimer->State == FALSE)) + RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue); + } + } + + if (status != 0) + { + pAd->TimerQ.status = RT2870_THREAD_STOPED; + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); + break; + } + } +} + + +INT TimerQThread( + IN OUT PVOID Context) +{ + PRTMP_ADAPTER pAd; + POS_COOKIE pObj; + + pAd = (PRTMP_ADAPTER)Context; + pObj = (POS_COOKIE) pAd->OS_Cookie; + + rtmp_os_thread_init("rt2870TimerQHandle", (PVOID)&(pAd->TimerQComplete)); + + RT2870_TimerQ_Handle(pAd); + + /* notify the exit routine that we're actually exiting now + * + * complete()/wait_for_completion() is similar to up()/down(), + * except that complete() is safe in the case where the structure + * is getting deleted in a parallel mode of execution (i.e. just + * after the down() -- that's necessary for the thread-shutdown + * case. + * + * complete_and_exit() goes even further than this -- it is safe in + * the case that the thread of the caller is going away (not just + * the structure) -- this is necessary for the module-remove case. + * This is important in preemption kernels, which transfer the flow + * of execution immediately upon a complete(). + */ + DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__)); + + pObj->TimerQThr_pid = NULL; + + complete_and_exit(&pAd->TimerQComplete, 0); + return 0; + +} + + +RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert( + IN RTMP_ADAPTER *pAd, + IN RALINK_TIMER_STRUCT *pTimer) +{ + RT2870_TIMER_ENTRY *pQNode = NULL, *pQTail; + unsigned long irqFlags; + + + RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); + if (pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT) + { + if(pAd->TimerQ.pQPollFreeList) + { + pQNode = pAd->TimerQ.pQPollFreeList; + pAd->TimerQ.pQPollFreeList = pQNode->pNext; + + pQNode->pRaTimer = pTimer; + pQNode->pNext = NULL; + + pQTail = pAd->TimerQ.pQTail; + if (pAd->TimerQ.pQTail != NULL) + pQTail->pNext = pQNode; + pAd->TimerQ.pQTail = pQNode; + if (pAd->TimerQ.pQHead == NULL) + pAd->TimerQ.pQHead = pQNode; + } + RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); + + if (pQNode) + up(&pAd->RTUSBTimer_semaphore); + //wake_up(&timerWaitQ); + } + else + { + RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); + } + return pQNode; +} + + +BOOLEAN RT2870_TimerQ_Remove( + IN RTMP_ADAPTER *pAd, + IN RALINK_TIMER_STRUCT *pTimer) +{ + RT2870_TIMER_ENTRY *pNode, *pPrev = NULL; + unsigned long irqFlags; + + RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); + if (pAd->TimerQ.status >= RT2870_THREAD_INITED) + { + pNode = pAd->TimerQ.pQHead; + while (pNode) + { + if (pNode->pRaTimer == pTimer) + break; + pPrev = pNode; + pNode = pNode->pNext; + } + + // Now move it to freeList queue. + if (pNode) + { + if (pNode == pAd->TimerQ.pQHead) + pAd->TimerQ.pQHead = pNode->pNext; + if (pNode == pAd->TimerQ.pQTail) + pAd->TimerQ.pQTail = pPrev; + if (pPrev != NULL) + pPrev->pNext = pNode->pNext; + + // return this queue entry to timerQFreeList. + pNode->pNext = pAd->TimerQ.pQPollFreeList; + pAd->TimerQ.pQPollFreeList = pNode; + } + } + RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); + + return TRUE; +} + + +void RT2870_TimerQ_Exit(RTMP_ADAPTER *pAd) +{ + RT2870_TIMER_ENTRY *pTimerQ; + unsigned long irqFlags; + + RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); + while (pAd->TimerQ.pQHead) + { + pTimerQ = pAd->TimerQ.pQHead; + pAd->TimerQ.pQHead = pTimerQ->pNext; + // remove the timeQ + } + pAd->TimerQ.pQPollFreeList = NULL; + os_free_mem(pAd, pAd->TimerQ.pTimerQPoll); + pAd->TimerQ.pQTail = NULL; + pAd->TimerQ.pQHead = NULL; + pAd->TimerQ.status = RT2870_THREAD_STOPED; + RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); + +} + + +void RT2870_TimerQ_Init(RTMP_ADAPTER *pAd) +{ + int i; + RT2870_TIMER_ENTRY *pQNode, *pEntry; + unsigned long irqFlags; + + NdisAllocateSpinLock(&pAd->TimerQLock); + + RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); + NdisZeroMemory(&pAd->TimerQ, sizeof(pAd->TimerQ)); + //InterlockedExchange(&pAd->TimerQ.count, 0); + + /* Initialise the wait q head */ + //init_waitqueue_head(&timerWaitQ); + + os_alloc_mem(pAd, &pAd->TimerQ.pTimerQPoll, sizeof(RT2870_TIMER_ENTRY) * TIMER_QUEUE_SIZE_MAX); + if (pAd->TimerQ.pTimerQPoll) + { + pEntry = NULL; + pQNode = (RT2870_TIMER_ENTRY *)pAd->TimerQ.pTimerQPoll; + for (i = 0 ;i <TIMER_QUEUE_SIZE_MAX; i++) + { + pQNode->pNext = pEntry; + pEntry = pQNode; + pQNode++; + } + pAd->TimerQ.pQPollFreeList = pEntry; + pAd->TimerQ.pQHead = NULL; + pAd->TimerQ.pQTail = NULL; + pAd->TimerQ.status = RT2870_THREAD_INITED; + } + RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); +} + + +VOID RT2870_WatchDog(IN RTMP_ADAPTER *pAd) +{ + PHT_TX_CONTEXT pHTTXContext; + int idx; + ULONG irqFlags; + PURB pUrb; + BOOLEAN needDumpSeq = FALSE; + UINT32 MACValue; + + + idx = 0; + RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); + if ((MACValue & 0xff) !=0 ) + { + DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 0 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue)); + RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40012); + while((MACValue &0xff) != 0 && (idx++ < 10)) + { + RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); + NdisMSleep(1); + } + RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); + } + +//PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) +#ifdef CONFIG_STA_SUPPORT + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { + idx = 0; + if ((MACValue & 0xff00) !=0 ) + { + DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 1 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue)); + RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf4000a); + while((MACValue &0xff00) != 0 && (idx++ < 10)) + { + RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); + NdisMSleep(1); + } + RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); + } + } +#endif // CONFIG_STA_SUPPORT // + + if (pAd->watchDogRxOverFlowCnt >= 2) + { + DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Rx Bulk-In hanged! Cancel the pending Rx bulks request!\n")); + if ((!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | + fRTMP_ADAPTER_BULKIN_RESET | + fRTMP_ADAPTER_HALT_IN_PROGRESS | + fRTMP_ADAPTER_NIC_NOT_EXIST)))) + { + DBGPRINT(RT_DEBUG_TRACE, ("Call CMDTHREAD_RESET_BULK_IN to cancel the pending Rx Bulk!\n")); + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); + RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0); + needDumpSeq = TRUE; + } + pAd->watchDogRxOverFlowCnt = 0; + } + + + for (idx = 0; idx < NUM_OF_TX_RING; idx++) + { + pUrb = NULL; + + RTMP_IRQ_LOCK(&pAd->BulkOutLock[idx], irqFlags); + if ((pAd->BulkOutPending[idx] == TRUE) && pAd->watchDogTxPendingCnt) + { + pAd->watchDogTxPendingCnt[idx]++; + + if ((pAd->watchDogTxPendingCnt[idx] > 2) && + (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_BULKOUT_RESET))) + ) + { + // FIXME: Following code just support single bulk out. If you wanna support multiple bulk out. Modify it! + pHTTXContext = (PHT_TX_CONTEXT)(&pAd->TxContext[idx]); + if (pHTTXContext->IRPPending) + { // Check TxContext. + pUrb = pHTTXContext->pUrb; + } + else if (idx == MGMTPIPEIDX) + { + PTX_CONTEXT pMLMEContext, pNULLContext, pPsPollContext; + + //Check MgmtContext. + pMLMEContext = (PTX_CONTEXT)(pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa); + pPsPollContext = (PTX_CONTEXT)(&pAd->PsPollContext); + pNULLContext = (PTX_CONTEXT)(&pAd->NullContext); + + if (pMLMEContext->IRPPending) + { + ASSERT(pMLMEContext->IRPPending); + pUrb = pMLMEContext->pUrb; + } + else if (pNULLContext->IRPPending) + { + ASSERT(pNULLContext->IRPPending); + pUrb = pNULLContext->pUrb; + } + else if (pPsPollContext->IRPPending) + { + ASSERT(pPsPollContext->IRPPending); + pUrb = pPsPollContext->pUrb; + } + } + + RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); + + DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Tx Bulk-Out hanged! Cancel the pending Tx bulks request of idx(%d)!\n", idx)); + if (pUrb) + { + DBGPRINT(RT_DEBUG_TRACE, ("Unlink the pending URB!\n")); + // unlink it now + RTUSB_UNLINK_URB(pUrb); + // Sleep 200 microseconds to give cancellation time to work + RTMPusecDelay(200); + needDumpSeq = TRUE; + } + else + { + DBGPRINT(RT_DEBUG_ERROR, ("Unkonw bulkOut URB maybe hanged!!!!!!!!!!!!\n")); + } + } + else + { + RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); + } + } + else + { + RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); + } + } + +#ifdef DOT11_N_SUPPORT + // For Sigma debug, dump the ba_reordering sequence. + if((needDumpSeq == TRUE) && (pAd->CommonCfg.bDisableReordering == 0)) + { + USHORT Idx; + PBA_REC_ENTRY pBAEntry = NULL; + UCHAR count = 0; + struct reordering_mpdu *mpdu_blk; + + Idx = pAd->MacTab.Content[BSSID_WCID].BARecWcidArray[0]; + + pBAEntry = &pAd->BATable.BARecEntry[Idx]; + if((pBAEntry->list.qlen > 0) && (pBAEntry->list.next != NULL)) + { + DBGPRINT(RT_DEBUG_TRACE, ("NICUpdateRawCounters():The Queueing pkt in reordering buffer:\n")); + NdisAcquireSpinLock(&pBAEntry->RxReRingLock); + mpdu_blk = pBAEntry->list.next; + while (mpdu_blk) + { + DBGPRINT(RT_DEBUG_TRACE, ("\t%d:Seq-%d, bAMSDU-%d!\n", count, mpdu_blk->Sequence, mpdu_blk->bAMSDU)); + mpdu_blk = mpdu_blk->next; + count++; + } + + DBGPRINT(RT_DEBUG_TRACE, ("\npBAEntry->LastIndSeq=%d!\n", pBAEntry->LastIndSeq)); + NdisReleaseSpinLock(&pBAEntry->RxReRingLock); + } + } +#endif // DOT11_N_SUPPORT // +} + +/* +======================================================================== +Routine Description: + Release allocated resources. + +Arguments: + *dev Point to the PCI or USB device + pAd driver control block pointer + +Return Value: + None + +Note: +======================================================================== +*/ +static void _rtusb_disconnect(struct usb_device *dev, PRTMP_ADAPTER pAd) +{ + struct net_device *net_dev = NULL; + + + DBGPRINT(RT_DEBUG_ERROR, ("rtusb_disconnect: unregister usbnet usb-%s-%s\n", + dev->bus->bus_name, dev->devpath)); + if (!pAd) + { +#ifdef MULTIPLE_CARD_SUPPORT + if ((pAd->MC_RowID >= 0) && (pAd->MC_RowID <= MAX_NUM_OF_MULTIPLE_CARD)) + MC_CardUsed[pAd->MC_RowID] = 0; // not clear MAC address +#endif // MULTIPLE_CARD_SUPPORT // + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ + while(MOD_IN_USE > 0) + { + MOD_DEC_USE_COUNT; + } +#else + usb_put_dev(dev); +#endif // LINUX_VERSION_CODE // + + printk("rtusb_disconnect: pAd == NULL!\n"); + return; + } + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST); + + + + // for debug, wait to show some messages to /proc system + udelay(1); + + + + + net_dev = pAd->net_dev; + if (pAd->net_dev != NULL) + { + printk("rtusb_disconnect: unregister_netdev(), dev->name=%s!\n", net_dev->name); + unregister_netdev (pAd->net_dev); + } + udelay(1); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ +#else + flush_scheduled_work(); +#endif // LINUX_VERSION_CODE // + udelay(1); + + // free net_device memory +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ + kfree(net_dev); +#else + free_netdev(net_dev); +#endif // LINUX_VERSION_CODE // + + // free adapter memory + RTMPFreeAdapter(pAd); + + // release a use of the usb device structure +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ + while(MOD_IN_USE > 0) + { + MOD_DEC_USE_COUNT; + } +#else + usb_put_dev(dev); +#endif // LINUX_VERSION_CODE // + udelay(1); + + DBGPRINT(RT_DEBUG_ERROR, (" RTUSB disconnect successfully\n")); +} + + +/* +======================================================================== +Routine Description: + Probe RT28XX chipset. + +Arguments: + *dev Point to the PCI or USB device + interface + *id_table Point to the PCI or USB device ID + +Return Value: + None + +Note: +======================================================================== +*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ +static void *rtusb_probe(struct usb_device *dev, UINT interface, + const struct usb_device_id *id) +{ + PRTMP_ADAPTER pAd; + rt28xx_probe((void *)dev, (void *)id, interface, &pAd); + return (void *)pAd; +} + +//Disconnect function is called within exit routine +static void rtusb_disconnect(struct usb_device *dev, void *ptr) +{ + _rtusb_disconnect(dev, ((PRTMP_ADAPTER)ptr)); +} + +#else /* kernel 2.6 series */ +static int rtusb_probe (struct usb_interface *intf, + const struct usb_device_id *id) +{ + PRTMP_ADAPTER pAd; + return (int)rt28xx_probe((void *)intf, (void *)id, 0, &pAd); +} + + +static void rtusb_disconnect(struct usb_interface *intf) +{ + struct usb_device *dev = interface_to_usbdev(intf); + PRTMP_ADAPTER pAd; + + + pAd = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + + _rtusb_disconnect(dev, pAd); +} +#endif // LINUX_VERSION_CODE // + + +/* +======================================================================== +Routine Description: + Close kernel threads. + +Arguments: + *pAd the raxx interface data pointer + +Return Value: + NONE + +Note: +======================================================================== +*/ +VOID RT28xxThreadTerminate( + IN RTMP_ADAPTER *pAd) +{ + POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; + INT ret; + + + // Sleep 50 milliseconds so pending io might finish normally + RTMPusecDelay(50000); + + // We want to wait until all pending receives and sends to the + // device object. We cancel any + // irps. Wait until sends and receives have stopped. + RTUSBCancelPendingIRPs(pAd); + + // Terminate Threads + if (pObj->MLMEThr_pid) + { + printk("Terminate the MLMEThr_pid=%d!\n", pid_nr(pObj->MLMEThr_pid)); + mb(); + pAd->mlme_kill = 1; + //RT28XX_MLME_HANDLER(pAd); + mb(); + ret = kill_pid(pObj->MLMEThr_pid, SIGTERM, 1); + if (ret) + { + printk (KERN_WARNING "%s: unable to Mlme thread, pid=%d, ret=%d!\n", + pAd->net_dev->name, pid_nr(pObj->MLMEThr_pid), ret); + } + else + { + //wait_for_completion (&pAd->notify); + wait_for_completion (&pAd->mlmeComplete); + pObj->MLMEThr_pid = NULL; + } + } + + if (pObj->RTUSBCmdThr_pid >= 0) + { + printk("Terminate the RTUSBCmdThr_pid=%d!\n", pid_nr(pObj->RTUSBCmdThr_pid)); + mb(); + NdisAcquireSpinLock(&pAd->CmdQLock); + pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; + NdisReleaseSpinLock(&pAd->CmdQLock); + mb(); + //RTUSBCMDUp(pAd); + ret = kill_pid(pObj->RTUSBCmdThr_pid, SIGTERM, 1); + if (ret) + { + printk(KERN_WARNING "%s: unable to RTUSBCmd thread, pid=%d, ret=%d!\n", + pAd->net_dev->name, pid_nr(pObj->RTUSBCmdThr_pid), ret); + } + else + { + //wait_for_completion (&pAd->notify); + wait_for_completion (&pAd->CmdQComplete); + pObj->RTUSBCmdThr_pid = NULL; + } + } + if (pObj->TimerQThr_pid >= 0) + { + POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; + + printk("Terminate the TimerQThr_pid=%d!\n", pid_nr(pObj->TimerQThr_pid)); + mb(); + pAd->TimerFunc_kill = 1; + mb(); + ret = kill_pid(pObj->TimerQThr_pid, SIGTERM, 1); + if (ret) + { + printk(KERN_WARNING "%s: unable to stop TimerQThread, pid=%d, ret=%d!\n", + pAd->net_dev->name, pid_nr(pObj->TimerQThr_pid), ret); + } + else + { + printk("wait_for_completion TimerQThr\n"); + wait_for_completion(&pAd->TimerQComplete); + pObj->TimerQThr_pid = NULL; + } + } + // Kill tasklets + pAd->mlme_kill = 0; + pAd->CmdQ.CmdQState = RT2870_THREAD_UNKNOWN; + pAd->TimerFunc_kill = 0; +} + + +void kill_thread_task(IN PRTMP_ADAPTER pAd) +{ + POS_COOKIE pObj; + + pObj = (POS_COOKIE) pAd->OS_Cookie; + + tasklet_kill(&pObj->rx_done_task); + tasklet_kill(&pObj->mgmt_dma_done_task); + tasklet_kill(&pObj->ac0_dma_done_task); + tasklet_kill(&pObj->ac1_dma_done_task); + tasklet_kill(&pObj->ac2_dma_done_task); + tasklet_kill(&pObj->ac3_dma_done_task); + tasklet_kill(&pObj->hcca_dma_done_task); + tasklet_kill(&pObj->tbtt_task); + +} + + +/* +======================================================================== +Routine Description: + Check the chipset vendor/product ID. + +Arguments: + _dev_p Point to the PCI or USB device + +Return Value: + TRUE Check ok + FALSE Check fail + +Note: +======================================================================== +*/ +BOOLEAN RT28XXChipsetCheck( + IN void *_dev_p) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ + struct usb_device *dev_p = (struct usb_device *)_dev_p; +#else + struct usb_interface *intf = (struct usb_interface *)_dev_p; + struct usb_device *dev_p = interface_to_usbdev(intf); +#endif // LINUX_VERSION_CODE // + UINT32 i; + + + for(i=0; i<rtusb_usb_id_len; i++) + { + if (dev_p->descriptor.idVendor == rtusb_usb_id[i].idVendor && + dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct) + { + printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n", + dev_p->descriptor.idVendor, dev_p->descriptor.idProduct); + break; + } + } + + if (i == rtusb_usb_id_len) + { + printk("rt2870: Error! Device Descriptor not matching!\n"); + return FALSE; + } + + return TRUE; +} + + +/* +======================================================================== +Routine Description: + Init net device structure. + +Arguments: + _dev_p Point to the PCI or USB device + *net_dev Point to the net device + *pAd the raxx interface data pointer + +Return Value: + TRUE Init ok + FALSE Init fail + +Note: +======================================================================== +*/ +BOOLEAN RT28XXNetDevInit( + IN void *_dev_p, + IN struct net_device *net_dev, + IN RTMP_ADAPTER *pAd) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ + struct usb_device *dev_p = (struct usb_device *)_dev_p; +#else + struct usb_interface *intf = (struct usb_interface *)_dev_p; + struct usb_device *dev_p = interface_to_usbdev(intf); +#endif // LINUX_VERSION_CODE // + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ + pAd->config = dev_p->config; +#else + pAd->config = &dev_p->config->desc; +#endif // LINUX_VERSION_CODE // + return TRUE; +} + + +/* +======================================================================== +Routine Description: + Init net device structure. + +Arguments: + _dev_p Point to the PCI or USB device + *pAd the raxx interface data pointer + +Return Value: + TRUE Config ok + FALSE Config fail + +Note: +======================================================================== +*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +BOOLEAN RT28XXProbePostConfig( + IN void *_dev_p, + IN RTMP_ADAPTER *pAd, + IN INT32 interface) +{ + struct usb_device *dev_p = (struct usb_device *)_dev_p; + struct usb_interface *intf; + struct usb_interface_descriptor *iface_desc; + struct usb_endpoint_descriptor *endpoint; + ULONG BulkOutIdx; + UINT32 i; + + + /* get the active interface descriptor */ + intf = &dev_p->actconfig->interface[interface]; + iface_desc = &intf->altsetting[0]; + + /* get # of enpoints */ + pAd->NumberOfPipes = iface_desc->bNumEndpoints; + DBGPRINT(RT_DEBUG_TRACE, ("NumEndpoints=%d\n", iface_desc->bNumEndpoints)); + + /* Configure Pipes */ + endpoint = &iface_desc->endpoint[0]; + BulkOutIdx = 0; + + for(i=0; i<pAd->NumberOfPipes; i++) + { + if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && + ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)) + { + pAd->BulkInEpAddr = endpoint[i].bEndpointAddress; + pAd->BulkInMaxPacketSize = endpoint[i].wMaxPacketSize; + + DBGPRINT_RAW(RT_DEBUG_TRACE, + ("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize)); + DBGPRINT_RAW(RT_DEBUG_TRACE, + ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); + } + else if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && + ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) + { + // There are 6 bulk out EP. EP6 highest priority. + // EP1-4 is EDCA. EP5 is HCCA. + pAd->BulkOutEpAddr[BulkOutIdx++] = endpoint[i].bEndpointAddress; + pAd->BulkOutMaxPacketSize = endpoint[i].wMaxPacketSize; + + DBGPRINT_RAW(RT_DEBUG_TRACE, + ("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize)); + DBGPRINT_RAW(RT_DEBUG_TRACE, + ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); + } + } + + if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) + { + printk("Could not find both bulk-in and bulk-out endpoints\n"); + return FALSE; + } + + return TRUE; +} + +#else +BOOLEAN RT28XXProbePostConfig( + IN void *_dev_p, + IN RTMP_ADAPTER *pAd, + IN INT32 interface) +{ + struct usb_interface *intf = (struct usb_interface *)_dev_p; + struct usb_host_interface *iface_desc; + ULONG BulkOutIdx; + UINT32 i; + + + /* get the active interface descriptor */ + iface_desc = intf->cur_altsetting; + + /* get # of enpoints */ + pAd->NumberOfPipes = iface_desc->desc.bNumEndpoints; + DBGPRINT(RT_DEBUG_TRACE, + ("NumEndpoints=%d\n", iface_desc->desc.bNumEndpoints)); + + /* Configure Pipes */ + BulkOutIdx = 0; + + for(i=0; i<pAd->NumberOfPipes; i++) + { + if ((iface_desc->endpoint[i].desc.bmAttributes == + USB_ENDPOINT_XFER_BULK) && + ((iface_desc->endpoint[i].desc.bEndpointAddress & + USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)) + { + pAd->BulkInEpAddr = iface_desc->endpoint[i].desc.bEndpointAddress; + pAd->BulkInMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize; + + DBGPRINT_RAW(RT_DEBUG_TRACE, + ("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize)); + DBGPRINT_RAW(RT_DEBUG_TRACE, + ("EP address = 0x%2x\n", iface_desc->endpoint[i].desc.bEndpointAddress)); + } + else if ((iface_desc->endpoint[i].desc.bmAttributes == + USB_ENDPOINT_XFER_BULK) && + ((iface_desc->endpoint[i].desc.bEndpointAddress & + USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) + { + // there are 6 bulk out EP. EP6 highest priority. + // EP1-4 is EDCA. EP5 is HCCA. + pAd->BulkOutEpAddr[BulkOutIdx++] = iface_desc->endpoint[i].desc.bEndpointAddress; + pAd->BulkOutMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize; + + DBGPRINT_RAW(RT_DEBUG_TRACE, + ("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize)); + DBGPRINT_RAW(RT_DEBUG_TRACE, + ("EP address = 0x%2x \n", iface_desc->endpoint[i].desc.bEndpointAddress)); + } + } + + if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) + { + printk("%s: Could not find both bulk-in and bulk-out endpoints\n", __FUNCTION__); + return FALSE; + } + + return TRUE; +} +#endif // LINUX_VERSION_CODE // + + +/* +======================================================================== +Routine Description: + Disable DMA. + +Arguments: + *pAd the raxx interface data pointer + +Return Value: + None + +Note: +======================================================================== +*/ +VOID RT28XXDMADisable( + IN RTMP_ADAPTER *pAd) +{ + // no use +} + + + +/* +======================================================================== +Routine Description: + Enable DMA. + +Arguments: + *pAd the raxx interface data pointer + +Return Value: + None + +Note: +======================================================================== +*/ +VOID RT28XXDMAEnable( + IN RTMP_ADAPTER *pAd) +{ + WPDMA_GLO_CFG_STRUC GloCfg; + USB_DMA_CFG_STRUC UsbCfg; + int i = 0; + + + RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4); + do + { + RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); + if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) + break; + + DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n")); + RTMPusecDelay(1000); + i++; + }while ( i <200); + + + RTMPusecDelay(50); + GloCfg.field.EnTXWriteBackDDONE = 1; + GloCfg.field.EnableRxDMA = 1; + GloCfg.field.EnableTxDMA = 1; + DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word)); + RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); + + UsbCfg.word = 0; + UsbCfg.field.phyclear = 0; + /* usb version is 1.1,do not use bulk in aggregation */ + if (pAd->BulkInMaxPacketSize == 512) + UsbCfg.field.RxBulkAggEn = 1; + /* for last packet, PBF might use more than limited, so minus 2 to prevent from error */ + UsbCfg.field.RxBulkAggLmt = (MAX_RXBULK_SIZE /1024)-3; + UsbCfg.field.RxBulkAggTOut = 0x80; /* 2006-10-18 */ + UsbCfg.field.RxBulkEn = 1; + UsbCfg.field.TxBulkEn = 1; + + RTUSBWriteMACRegister(pAd, USB_DMA_CFG, UsbCfg.word); + +} + +/* +======================================================================== +Routine Description: + Write Beacon buffer to Asic. + +Arguments: + *pAd the raxx interface data pointer + +Return Value: + None + +Note: +======================================================================== +*/ +VOID RT28xx_UpdateBeaconToAsic( + IN RTMP_ADAPTER *pAd, + IN INT apidx, + IN ULONG FrameLen, + IN ULONG UpdatePos) +{ + PUCHAR pBeaconFrame = NULL; + UCHAR *ptr; + UINT i, padding; + BEACON_SYNC_STRUCT *pBeaconSync = pAd->CommonCfg.pBeaconSync; + UINT32 longValue; +// USHORT shortValue; + BOOLEAN bBcnReq = FALSE; + UCHAR bcn_idx = 0; + + + if (pBeaconFrame == NULL) + { + DBGPRINT(RT_DEBUG_ERROR,("pBeaconFrame is NULL!\n")); + return; + } + + if (pBeaconSync == NULL) + { + DBGPRINT(RT_DEBUG_ERROR,("pBeaconSync is NULL!\n")); + return; + } + + //if ((pAd->WdsTab.Mode == WDS_BRIDGE_MODE) || + // ((pAd->ApCfg.MBSSID[apidx].MSSIDDev == NULL) || !(pAd->ApCfg.MBSSID[apidx].MSSIDDev->flags & IFF_UP)) + // ) + if (bBcnReq == FALSE) + { + /* when the ra interface is down, do not send its beacon frame */ + /* clear all zero */ + for(i=0; i<TXWI_SIZE; i+=4) { + RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, 0x00); + } + pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx))); + NdisZeroMemory(pBeaconSync->BeaconTxWI[bcn_idx], TXWI_SIZE); + } + else + { + ptr = (PUCHAR)&pAd->BeaconTxWI; +#ifdef RT_BIG_ENDIAN + RTMPWIEndianChange(ptr, TYPE_TXWI); +#endif + if (NdisEqualMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE) == FALSE) + { // If BeaconTxWI changed, we need to rewrite the TxWI for the Beacon frames. + pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx))); + NdisMoveMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE); + } + + if ((pBeaconSync->BeaconBitMap & (1 << bcn_idx)) != (1 << bcn_idx)) + { + for (i=0; i<TXWI_SIZE; i+=4) // 16-byte TXWI field + { + longValue = *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24); + RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, longValue); + ptr += 4; + } + } + + ptr = pBeaconSync->BeaconBuf[bcn_idx]; + padding = (FrameLen & 0x01); + NdisZeroMemory((PUCHAR)(pBeaconFrame + FrameLen), padding); + FrameLen += padding; + for (i = 0 ; i < FrameLen /*HW_BEACON_OFFSET*/; i += 2) + { + if (NdisEqualMemory(ptr, pBeaconFrame, 2) == FALSE) + { + NdisMoveMemory(ptr, pBeaconFrame, 2); + //shortValue = *ptr + (*(ptr+1)<<8); + //RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, shortValue); + RTUSBMultiWrite(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, ptr, 2); + } + ptr +=2; + pBeaconFrame += 2; + } + + pBeaconSync->BeaconBitMap |= (1 << bcn_idx); + + // For AP interface, set the DtimBitOn so that we can send Bcast/Mcast frame out after this beacon frame. + } + +} + + +VOID RT2870_BssBeaconStop( + IN RTMP_ADAPTER *pAd) +{ + BEACON_SYNC_STRUCT *pBeaconSync; + int i, offset; + BOOLEAN Cancelled = TRUE; + + pBeaconSync = pAd->CommonCfg.pBeaconSync; + if (pBeaconSync && pBeaconSync->EnableBeacon) + { + INT NumOfBcn; + + +#ifdef CONFIG_STA_SUPPORT + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { + NumOfBcn = MAX_MESH_NUM; + } +#endif // CONFIG_STA_SUPPORT // + + RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled); + + for(i=0; i<NumOfBcn; i++) + { + NdisZeroMemory(pBeaconSync->BeaconBuf[i], HW_BEACON_OFFSET); + NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); + + for (offset=0; offset<HW_BEACON_OFFSET; offset+=4) + RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[i] + offset, 0x00); + + pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; + pBeaconSync->TimIELocationInBeacon[i] = 0; + } + pBeaconSync->BeaconBitMap = 0; + pBeaconSync->DtimBitOn = 0; + } +} + + +VOID RT2870_BssBeaconStart( + IN RTMP_ADAPTER *pAd) +{ + int apidx; + BEACON_SYNC_STRUCT *pBeaconSync; +// LARGE_INTEGER tsfTime, deltaTime; + + pBeaconSync = pAd->CommonCfg.pBeaconSync; + if (pBeaconSync && pBeaconSync->EnableBeacon) + { + INT NumOfBcn; + + +#ifdef CONFIG_STA_SUPPORT + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { + NumOfBcn = MAX_MESH_NUM; + } +#endif // CONFIG_STA_SUPPORT // + + for(apidx=0; apidx<NumOfBcn; apidx++) + { + UCHAR CapabilityInfoLocationInBeacon = 0; + UCHAR TimIELocationInBeacon = 0; + +#ifdef CONFIG_STA_SUPPORT +#endif // CONFIG_STA_SUPPORT // + + NdisZeroMemory(pBeaconSync->BeaconBuf[apidx], HW_BEACON_OFFSET); + pBeaconSync->CapabilityInfoLocationInBeacon[apidx] = CapabilityInfoLocationInBeacon; + pBeaconSync->TimIELocationInBeacon[apidx] = TimIELocationInBeacon; + NdisZeroMemory(pBeaconSync->BeaconTxWI[apidx], TXWI_SIZE); + } + pBeaconSync->BeaconBitMap = 0; + pBeaconSync->DtimBitOn = 0; + pAd->CommonCfg.BeaconUpdateTimer.Repeat = TRUE; + + pAd->CommonCfg.BeaconAdjust = 0; + pAd->CommonCfg.BeaconFactor = 0xffffffff / (pAd->CommonCfg.BeaconPeriod << 10); + pAd->CommonCfg.BeaconRemain = (0xffffffff % (pAd->CommonCfg.BeaconPeriod << 10)) + 1; + printk("RT2870_BssBeaconStart:BeaconFactor=%d, BeaconRemain=%d!\n", pAd->CommonCfg.BeaconFactor, pAd->CommonCfg.BeaconRemain); + RTMPSetTimer(&pAd->CommonCfg.BeaconUpdateTimer, pAd->CommonCfg.BeaconPeriod); + + } +} + + +VOID RT2870_BssBeaconInit( + IN RTMP_ADAPTER *pAd) +{ + BEACON_SYNC_STRUCT *pBeaconSync; + int i; + + NdisAllocMemory(pAd->CommonCfg.pBeaconSync, sizeof(BEACON_SYNC_STRUCT), MEM_ALLOC_FLAG); + if (pAd->CommonCfg.pBeaconSync) + { + pBeaconSync = pAd->CommonCfg.pBeaconSync; + NdisZeroMemory(pBeaconSync, sizeof(BEACON_SYNC_STRUCT)); + for(i=0; i < HW_BEACON_MAX_COUNT; i++) + { + NdisZeroMemory(pBeaconSync->BeaconBuf[i], HW_BEACON_OFFSET); + pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; + pBeaconSync->TimIELocationInBeacon[i] = 0; + NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); + } + pBeaconSync->BeaconBitMap = 0; + + //RTMPInitTimer(pAd, &pAd->CommonCfg.BeaconUpdateTimer, GET_TIMER_FUNCTION(BeaconUpdateExec), pAd, TRUE); + pBeaconSync->EnableBeacon = TRUE; + } +} + + +VOID RT2870_BssBeaconExit( + IN RTMP_ADAPTER *pAd) +{ + BEACON_SYNC_STRUCT *pBeaconSync; + BOOLEAN Cancelled = TRUE; + int i; + + if (pAd->CommonCfg.pBeaconSync) + { + pBeaconSync = pAd->CommonCfg.pBeaconSync; + pBeaconSync->EnableBeacon = FALSE; + RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled); + pBeaconSync->BeaconBitMap = 0; + + for(i=0; i<HW_BEACON_MAX_COUNT; i++) + { + NdisZeroMemory(pBeaconSync->BeaconBuf[i], HW_BEACON_OFFSET); + pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; + pBeaconSync->TimIELocationInBeacon[i] = 0; + NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); + } + + NdisFreeMemory(pAd->CommonCfg.pBeaconSync, HW_BEACON_OFFSET * HW_BEACON_MAX_COUNT, 0); + pAd->CommonCfg.pBeaconSync = NULL; + } +} + +VOID BeaconUpdateExec( + IN PVOID SystemSpecific1, + IN PVOID FunctionContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3) +{ + PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; + LARGE_INTEGER tsfTime_a;//, tsfTime_b, deltaTime_exp, deltaTime_ab; + UINT32 delta, remain, remain_low, remain_high; +// BOOLEAN positive; + + ReSyncBeaconTime(pAd); + + + + RTMP_IO_READ32(pAd, TSF_TIMER_DW0, &tsfTime_a.u.LowPart); + RTMP_IO_READ32(pAd, TSF_TIMER_DW1, &tsfTime_a.u.HighPart); + + + //positive=getDeltaTime(tsfTime_a, expectedTime, &deltaTime_exp); + remain_high = pAd->CommonCfg.BeaconRemain * tsfTime_a.u.HighPart; + remain_low = tsfTime_a.u.LowPart % (pAd->CommonCfg.BeaconPeriod << 10); + remain = (remain_high + remain_low)%(pAd->CommonCfg.BeaconPeriod << 10); + delta = (pAd->CommonCfg.BeaconPeriod << 10) - remain; + + pAd->CommonCfg.BeaconUpdateTimer.TimerValue = (delta >> 10) + 10; + +} + |