/* Show out NAT session table. */ static void ShowNatSession(__NAT_MANAGER* pMgr, size_t ss_num) { size_t top = ss_num; __EASY_NAT_ENTRY* pEntry = NULL; int show_cnt = 0; BUG_ON(NULL == pMgr); if (0 == top) { top = MAX_DWORD_VALUE; } WaitForThisObject(NatManager.lock); pEntry = NatManager.entryList.pNext; while (pEntry != &NatManager.entryList) { top--; ShowNatEntry(pEntry); show_cnt++; if (0 == top) { break; } pEntry = pEntry->pNext; } ReleaseMutex(NatManager.lock); _hx_printf("[%d] NAT entries showed.\r\n", show_cnt); return; }
/* Uninitializer of NAT manager. */ static void nmUninitialize(__NAT_MANAGER* pMgr) { __EASY_NAT_ENTRY* pEntry = NULL; BUG_ON(NULL == pMgr); BUG_ON(NULL == pMgr->pTree); BUG_ON(NULL == pMgr->lock); /* Destroy all NAT entries in system. */ WaitForThisObject(pMgr->lock); pEntry = pMgr->entryList.pNext; while (pEntry != &pMgr->entryList) { /* Unlink it first. */ pEntry->pNext->pPrev = pEntry->pPrev; pEntry->pPrev->pNext = pEntry->pNext; _hx_free(pEntry); pEntry = pMgr->entryList.pNext; } ReleaseMutex(pMgr->lock); /* Destroy lock. */ DestroyMutex(pMgr->lock); /* Destroy the radix tree object. */ DestroyRadixTree(pMgr->pTree); return; }
/* Periodic timer handler of NAT. */ static void PeriodicTimerHandler() { __EASY_NAT_ENTRY* pEntry = NULL; __EASY_NAT_ENTRY* pPurge = NULL; unsigned long time_out = 0; /* Scan every NAT entry in system. */ WaitForThisObject(NatManager.lock); pEntry = NatManager.entryList.pNext; while (pEntry != &NatManager.entryList) { pEntry->ms += NAT_ENTRY_SCAN_PERIOD; switch (pEntry->protocol) { case IP_PROTO_TCP: time_out = NAT_ENTRY_TIMEOUT_TCP; break; case IP_PROTO_UDP: time_out = NAT_ENTRY_TIMEOUT_UDP; break; case IP_PROTO_ICMP: time_out = NAT_ENTRY_TIMEOUT_ICMP; break; default: time_out = NAT_ENTRY_TIMEOUT_DEF; break; } /* For debugging purpose. */ if (NULL == pEntry->pNext) { ShowNatEntry(pEntry); BUG_ON(NULL == pEntry->pNext); } if (pEntry->ms > time_out) /* Should purge the entry. */ { pPurge = pEntry; pEntry = pEntry->pNext; PurgeNatEntry(pPurge); } else { pEntry = pEntry->pNext; } } ReleaseMutex(NatManager.lock); }
/* Do not free buffers associated with QHs, they're owned by someone else */ int EHCIDestroyIntQueue(struct usb_device *dev,struct int_queue *queue) { struct ehci_ctrl *ctrl = ehci_get_ctrl(dev); int result = -1; unsigned long timeout; struct QH *cur = NULL; DWORD dwFlags; struct int_queue* before = NULL, *current = NULL; //Remove it from the controller's pending list if it is in.It's a bit complicated since //the pending list is a one direction link list,and we also are not sure if the queue is //in list. __ENTER_CRITICAL_SECTION(NULL, dwFlags); if (NULL != ctrl->pIntQueueFirst) { if (queue == ctrl->pIntQueueFirst) { if (queue == ctrl->pIntQueueLast) { ctrl->pIntQueueFirst = NULL; ctrl->pIntQueueLast = NULL; } else { ctrl->pIntQueueFirst = queue->pNext; queue->pNext = NULL; } } else { before = ctrl->pIntQueueFirst; current = before->pNext; while (current && (current != queue)) { before = current; current = current->pNext; } if (queue == current) //Find the queue in list. { before->pNext = current->pNext; queue->pNext = NULL; if (NULL == current->pNext) //Last one. { ctrl->pIntQueueLast = before; } } } } __LEAVE_CRITICAL_SECTION(NULL, dwFlags); if (NULL != queue->pNext) { BUG(); } WaitForThisObject(ctrl->hMutex); if (ehci_disable_periodic(ctrl) < 0) { ReleaseMutex(ctrl->hMutex); debug("FATAL: periodic should never fail, but did"); goto out; } ctrl->periodic_schedules--; cur = &ctrl->periodic_queue; timeout = get_timer(0) + (500 / SYSTEM_TIME_SLICE); /* abort after 500ms */ while (!(cur->qh_link & cpu_to_hc32(QH_LINK_TERMINATE))) { debug("considering %p, with qh_link %x\r\n", cur, cur->qh_link); if (NEXT_QH(cur) == queue->first) { debug("found candidate. removing from chain\r\n"); cur->qh_link = queue->last->qh_link; flush_dcache_range((unsigned long)cur, ALIGN_END_ADDR(struct QH, cur, 1)); result = 0; break; } cur = NEXT_QH(cur); if (get_timer(0) > timeout) { ReleaseMutex(ctrl->hMutex); _hx_printf("Timeout destroying interrupt endpoint queue\r\n"); result = -1; goto out; } }
//Create and return an interrupt queue object. struct int_queue* EHCICreateIntQueue(struct usb_device *dev, unsigned long pipe, int queuesize, int elementsize, void *buffer, int interval) { struct ehci_ctrl *ctrl = ehci_get_ctrl(dev); struct int_queue *result = NULL; uint32_t i, toggle; struct QH *list = NULL; int cmd = 0; DWORD dwFlags; /* * Interrupt transfers requiring several transactions are not supported * because bInterval is ignored. * * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2 * <= PKT_ALIGN if several qTDs are required, while the USB * specification does not constrain this for interrupt transfers. That * means that ehci_submit_async() would support interrupt transfers * requiring several transactions only as long as the transfer size does * not require more than a single qTD. */ if (elementsize > usb_maxpacket(dev, pipe)) { printf("%s: xfers requiring several transactions are not supported.\r\n", "_ehci_create_int_queue"); return NULL; } if (usb_pipetype(pipe) != PIPE_INTERRUPT) { debug("non-interrupt pipe (type=%lu)", usb_pipetype(pipe)); return NULL; } /* limit to 4 full pages worth of data - * we can safely fit them in a single TD, * no matter the alignment */ if (elementsize >= 16384) { debug("too large elements for interrupt transfers\r\n"); return NULL; } result = malloc(sizeof(*result)); if (!result) { debug("ehci intr queue: out of memory\r\n"); goto fail1; } //Create EVENT object to synchronizing the access. result->hEvent = CreateEvent(FALSE); if (NULL == result->hEvent) { goto fail1; } result->dwTimeOut = 0; result->pNext = NULL; result->pOwnerThread = KernelThreadManager.lpCurrentKernelThread; result->QueueIntHandler = _ehciQueueIntHandler; result->pUsbDev = dev; result->dwStatus = INT_QUEUE_STATUS_INITIALIZED; result->elementsize = elementsize; result->pipe = pipe; result->first = memalign(USB_DMA_MINALIGN, sizeof(struct QH) * queuesize); if (!result->first) { debug("ehci intr queue: out of memory\r\n"); goto fail2; } debug("%s: Allocate %d QH(s) at %X.\r\n", __func__,queuesize,result->first); result->current = result->first; result->last = result->first + queuesize - 1; result->tds = memalign(USB_DMA_MINALIGN, sizeof(struct qTD) * queuesize); if (!result->tds) { debug("ehci intr queue: out of memory\r\n"); goto fail3; } debug("%s: Allocate %d qTD(s) at %X.\r\n", __func__,queuesize, result->tds); memset(result->first, 0, sizeof(struct QH) * queuesize); memset(result->tds, 0, sizeof(struct qTD) * queuesize); toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); for (i = 0; i < (uint32_t)queuesize; i++) { struct QH *qh = result->first + i; struct qTD *td = result->tds + i; void **buf = &qh->buffer; qh->qh_link = cpu_to_hc32((unsigned long)(qh + 1) | QH_LINK_TYPE_QH); if (i == queuesize - 1) qh->qh_link = cpu_to_hc32(QH_LINK_TERMINATE); qh->qh_overlay.qt_next = cpu_to_hc32((unsigned long)td); qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); qh->qh_endpt1 = cpu_to_hc32((0 << 28) | /* No NAK reload (ehci 4.9) */ (usb_maxpacket(dev, pipe) << 16) | /* MPS */ (1 << 14) | QH_ENDPT1_EPS(ehci_encode_speed(dev->speed)) | (usb_pipeendpoint(pipe) << 8) | /* Endpoint Number */ (usb_pipedevice(pipe) << 0)); qh->qh_endpt2 = cpu_to_hc32((1 << 30) | /* 1 Tx per mframe */ (1 << 0)); /* S-mask: microframe 0 */ if (dev->speed == USB_SPEED_LOW || dev->speed == USB_SPEED_FULL) { /* C-mask: microframes 2-4 */ qh->qh_endpt2 |= cpu_to_hc32((0x1c << 8)); } ehci_update_endpt2_dev_n_port(dev, qh); td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); debug("%s: communication direction is '%s'\r\n", __func__, usb_pipein(pipe) ? "in" : "out"); if (i == queuesize - 1) //Last one,set IoC bit. { td->qt_token = cpu_to_hc32( QT_TOKEN_DT(toggle) | (elementsize << 16) | (1 << 15) | //Interrupt On Completion. (3 << 10) | //CERR bits. ((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */ 0x80); /* active */ } else { td->qt_token = cpu_to_hc32( QT_TOKEN_DT(toggle) | (elementsize << 16) | (3 << 10) | //CERR bits. ((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */ 0x80); /* active */ } debug("%s: construct TD token = %X.\r\n", __func__, td->qt_token); td->qt_buffer[0] = cpu_to_hc32((unsigned long)buffer + i * elementsize); td->qt_buffer[1] = cpu_to_hc32((td->qt_buffer[0] + 0x1000) & ~0xfff); td->qt_buffer[2] = cpu_to_hc32((td->qt_buffer[0] + 0x2000) & ~0xfff); td->qt_buffer[3] = cpu_to_hc32((td->qt_buffer[0] + 0x3000) & ~0xfff); td->qt_buffer[4] = cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff); #ifdef __MS_VC__ //MS VC can not support sizeof(void) operation,we should //convert the buffer type to char*. *buf = (void*)((char*)buffer + i * elementsize); #else //sizeof(void) is 1 under GCC or other environment,so the //following sentence is same as above one. *buf = buffer + i * elementsize; #endif toggle ^= 1; } flush_dcache_range((unsigned long)buffer, ALIGN_END_ADDR(char, buffer, queuesize * elementsize)); flush_dcache_range((unsigned long)result->first, ALIGN_END_ADDR(struct QH, result->first, queuesize)); flush_dcache_range((unsigned long)result->tds, ALIGN_END_ADDR(struct qTD, result->tds, queuesize)); //Acquire exclusively accessing of the controller. WaitForThisObject(ctrl->hMutex); if (ctrl->periodic_schedules > 0) { if (ehci_disable_periodic(ctrl) < 0) { ReleaseMutex(ctrl->hMutex); _hx_printf("FATAL %s: periodic should never fail, but did.\r\n",__func__); goto fail3; } } __ENTER_CRITICAL_SECTION(NULL, dwFlags); /* hook up to periodic list */ list = &ctrl->periodic_queue; result->last->qh_link = list->qh_link; list->qh_link = cpu_to_hc32((unsigned long)result->first | QH_LINK_TYPE_QH); //Link interrupt queue to Controller's pending queue. if (NULL == ctrl->pIntQueueFirst) { ctrl->pIntQueueFirst = result; ctrl->pIntQueueLast = result; } else { result->pNext = ctrl->pIntQueueFirst; ctrl->pIntQueueFirst = result; } __LEAVE_CRITICAL_SECTION(NULL, dwFlags); flush_dcache_range((unsigned long)result->last, ALIGN_END_ADDR(struct QH, result->last, 1)); flush_dcache_range((unsigned long)list, ALIGN_END_ADDR(struct QH, list, 1)); if (ehci_enable_periodic(ctrl) < 0) { ReleaseMutex(ctrl->hMutex); _hx_printf("FATAL %s: periodic should never fail, but did.\r\n", __func__);; goto fail3; } ctrl->periodic_schedules++; ReleaseMutex(ctrl->hMutex); debug("Exit create_int_queue\r\n"); return result; fail3: if (result->tds) free(result->tds); fail2: if (result->first) free(result->first); //if (result) // free(result); fail1: if (result) { if (NULL != result->hEvent) { DestroyEvent(result->hEvent); } free(result); } return NULL; }
//Start USB isochronous transfer. BOOL usbStartISOXfer(__USB_ISO_DESCRIPTOR* pIsoDesc) { __COMMON_USB_CONTROLLER* pCommCtrl = NULL; struct iTD* pitd = NULL; struct usb_device* pUsbDev = NULL; struct ehci_ctrl* pEhciCtrl = NULL; DWORD dwResult = 0; BOOL bResult = FALSE; //int transact = 0; if (NULL == pIsoDesc) { goto __TERMINAL; } pCommCtrl = pIsoDesc->pCtrl; pUsbDev = pIsoDesc->pPhyDev->lpPrivateInfo; if ((NULL == pCommCtrl) || (NULL == pUsbDev)) { BUG(); } pitd = pIsoDesc->itdArray; pEhciCtrl = pCommCtrl->pUsbCtrl; if ((NULL == pitd) || (NULL == pEhciCtrl)) { BUG(); } //Set descriptor's status accordingly. pIsoDesc->status = USB_ISODESC_STATUS_INPROCESS; ResetEvent(pIsoDesc->hEvent); #if 0 //Set the act bit of each transaction(s) iTD descriptor,so controller will process it. for (int transact = 0; transact < 8; transact++) { if (0 == pitd->transaction[transact]) //Reach the end. { break; } pitd->transaction[transact] |= ITD_TRANS_STATUS_SET(ITD_TRANS_STATUS_ACT); //Just for debugging.__Fill_iTD should be called here... pitd->transaction[0] &= 0xF000FFFF; pitd->transaction[0] |= ITD_TRANS_XLEN_SET(pIsoDesc->bufflength); } #endif //Fill iTD's all variable fields. __Fill_iTD(pIsoDesc, pitd, pIsoDesc->direction, pIsoDesc->buffer, pIsoDesc->bufflength, pIsoDesc->endpoint, pIsoDesc->maxPacketSize, pIsoDesc->multi); flush_dcache_range((unsigned long)pitd, ALIGN_END_ADDR(struct iTD, pitd, 1)); //Start periodic schedule if not yet. WaitForThisObject(pEhciCtrl->hMutex); if (pEhciCtrl->periodic_schedules == 0) { ehci_enable_periodic(pEhciCtrl); pEhciCtrl->periodic_schedules++; } ReleaseMutex(pEhciCtrl->hMutex); //Pending on the descriptor to wait the arrival of data. dwResult = WaitForThisObjectEx(pIsoDesc->hEvent, USB_DEFAULT_XFER_TIMEOUT); switch (dwResult) { case OBJECT_WAIT_RESOURCE: if (USB_ISODESC_STATUS_COMPLETED == pIsoDesc->status) { bResult = TRUE; break; } if (USB_ISODESC_STATUS_ERROR == pIsoDesc->status) { //Try to restore from error. //IsoClearError(pIsoDesc); //Clear the act bit. pitd->transaction[0] &= ~0x80000000; pitd->transaction[1] &= ~0x80000000; pitd->transaction[2] &= ~0x80000000; pitd->transaction[3] &= ~0x80000000; pitd->transaction[4] &= ~0x80000000; pitd->transaction[5] &= ~0x80000000; pitd->transaction[6] &= ~0x80000000; pitd->transaction[7] &= ~0x80000000; flush_dcache_range((unsigned long)pitd, ALIGN_END_ADDR(struct iTD, pitd, 1)); break; } BUG(); break; case OBJECT_WAIT_TIMEOUT: case OBJECT_WAIT_FAILED: //Set status as canceled. pIsoDesc->status = USB_ISODESC_STATUS_CANCELED; //Clear the act bit. pitd->transaction[0] &= ~0x80000000; pitd->transaction[1] &= ~0x80000000; pitd->transaction[2] &= ~0x80000000; pitd->transaction[3] &= ~0x80000000; pitd->transaction[4] &= ~0x80000000; pitd->transaction[5] &= ~0x80000000; pitd->transaction[6] &= ~0x80000000; pitd->transaction[7] &= ~0x80000000; flush_dcache_range((unsigned long)pitd, ALIGN_END_ADDR(struct iTD, pitd, 1)); _hx_printf("%s:iTD timed out.\r\n", __func__); break; case OBJECT_WAIT_DELETED: BUG(); //Should not occur. break; default: _hx_printf("%s:unexcepted timeout waiting's return value[%d].\r\n", __func__, dwResult); BUG(); }
//Create a USB isochronous transfer descriptor and install it into system. __USB_ISO_DESCRIPTOR* usbCreateISODescriptor(__PHYSICAL_DEVICE* pPhyDev, int direction, int bandwidth, char* buffer, int bufflength, __U8 endpoint,__U16 maxPacketSize,__U8 multi) { __USB_ISO_DESCRIPTOR* pIsoDesc = NULL; BOOL bResult = FALSE; struct usb_device* pUsbDev = NULL; struct iTD* pitd = NULL; __COMMON_USB_CONTROLLER* pCtrl = NULL; struct ehci_ctrl* pEhciCtrl = NULL; int maxXferSize = 0, transact_leng = 0; int slot_num = 0; //How many slot the iTD should link to. int slot_space = 0; //The slot number between 2 iTDs in periodic list. int i = 0; char* buff_ptr = buffer; DWORD dwFlags; //Parameters check. if ((NULL == pPhyDev) || (NULL == buffer) || (0 == bufflength) || (0 == endpoint)) { goto __TERMINAL; } if ((bandwidth > EHCI_ISO_MAX_BANDWIDTH) || (0 == multi)) { goto __TERMINAL; } if (maxPacketSize > 1024) //EHCI spec. { goto __TERMINAL; } if ((direction != USB_TRANSFER_DIR_IN) && (direction != USB_TRANSFER_DIR_OUT)) { goto __TERMINAL; } pUsbDev = (struct usb_device*)pPhyDev->lpPrivateInfo; if (NULL == pUsbDev) { BUG(); } pCtrl = (__COMMON_USB_CONTROLLER*)pUsbDev->controller; pEhciCtrl = (struct ehci_ctrl*)pCtrl->pUsbCtrl; //8 transactions in one iTD descriptor. maxXferSize = maxPacketSize * multi * 8; if (bufflength > (int)maxXferSize) { goto __TERMINAL; } //Allocate a ISOxfer descriptor and initialize it accordingly. pIsoDesc = _hx_malloc(sizeof(__USB_ISO_DESCRIPTOR)); if (NULL == pIsoDesc) { goto __TERMINAL; } memset(pIsoDesc, 0, sizeof(__USB_ISO_DESCRIPTOR)); pIsoDesc->bandwidth = bandwidth; pIsoDesc->buffer = buffer; pIsoDesc->bufflength = bufflength; pIsoDesc->direction = direction; pIsoDesc->ISOXferIntHandler = ISOXferIntHandler; pIsoDesc->itdArray = NULL; //Will be initialized later. pIsoDesc->itdnumber = 0; //Will be initialized later. pIsoDesc->pCtrl = (__COMMON_USB_CONTROLLER*)pUsbDev->controller; pIsoDesc->hEvent = NULL; pIsoDesc->endpoint = endpoint; pIsoDesc->maxPacketSize = maxPacketSize; pIsoDesc->multi = multi; pIsoDesc->pNext = NULL; pIsoDesc->pPhyDev = pPhyDev; pIsoDesc->status = USB_ISODESC_STATUS_INITIALIZED; pIsoDesc->hEvent = CreateEvent(FALSE); if (NULL == pIsoDesc) { goto __TERMINAL; } //Create iTD and initialize it. pitd = (struct iTD*)_hx_aligned_malloc(sizeof(struct iTD), 32); if (NULL == pitd) { goto __TERMINAL; } memset(pitd, 0, sizeof(struct iTD)); pitd->lp_next |= ITD_NEXT_TERMINATE; //Terminate bit. pitd->lp_next |= ITD_NEXT_TYPE_SET(ITD_NEXT_TYPE_ITD); //Type as iTD. //pitd->transaction[0] |= ITD_TRANS_XLEN_SET(bufflength); //xlength. //pitd->transaction[0] |= ITD_TRANS_IOC_SET(1); //Set IOC bit. //pitd->transaction[0] |= ITD_TRANS_PG_SET(0); //Page 0. //pitd->transaction[0] |= ITD_TRANS_XOFFSET_SET(buffer); //Buffer offset. //pitd->pg_pointer[0] |= ITD_PGPTR_SET(buffer); //Buffer page pointer. pitd->pg_pointer[0] |= ITD_ENDPOINT_SET(endpoint); //Endpoint. pitd->pg_pointer[0] |= pUsbDev->devnum; //Device address. //Set transfer direction. if (USB_TRANSFER_DIR_IN == direction) { pitd->pg_pointer[1] |= ITD_XFERDIR_SET(1); } else { pitd->pg_pointer[1] |= ITD_XFERDIR_SET(0); } pitd->pg_pointer[1] |= ITD_MAX_PKTSZ_SET(maxPacketSize); //Max packet size. pitd->pg_pointer[2] |= ITD_MULTI_SET(multi); //multiple per (micro)frame. //Fill iTD's transaction(s) accordingly. __Fill_iTD(pIsoDesc,pitd,direction,buffer,bufflength,endpoint,maxPacketSize,multi); #if 0 //Initializes data buffer offset and pointer one by one. i = 0; buff_ptr = buffer; maxXferSize = bufflength; transact_leng = (maxPacketSize * multi > maxXferSize) ? maxXferSize : (maxPacketSize * multi); while (maxXferSize) { pitd->transaction[i] |= ITD_TRANS_XLEN_SET(bufflength); //xlength. pitd->transaction[i] |= ITD_TRANS_PG_SET(i); //Page 0. pitd->transaction[i] |= ITD_TRANS_XOFFSET_SET(buffer); //Buffer offset. pitd->pg_pointer[i] |= ITD_PGPTR_SET(buffer); //Buffer page pointer. } #endif #ifdef __DEBUG_USB_ISO _hx_printf("iso_iTD:lp_next = 0x%X,trans[0] = 0x%X,pg_ptr[0] = 0x%X,pg_ptr[1] = 0x%X,pg_ptr[2] = 0x%X.\r\n", pitd->lp_next, pitd->transaction[0], pitd->pg_pointer[0], pitd->pg_pointer[1],pitd->pg_pointer[2]); #endif flush_dcache_range((unsigned long)pitd, ALIGN_END_ADDR(struct iTD, pitd, 1)); //Link the iTD to isochronous transfer descriptor. pIsoDesc->itdArray = pitd; pIsoDesc->itdnumber = 1; //Calculate how many periodic list slot shall we use. slot_num = bandwidth / 8; if (slot_num < bufflength) { slot_num = 1; } else { slot_num = (0 == slot_num % bufflength) ? (slot_num / bufflength) : (slot_num / bufflength + 1); } if (slot_num > USB_PERIODIC_LIST_LENGTH) //Paameter checking makes sure this can not happen. { _hx_printf("%s:too many slot number[bw = %d,buff_len = %d,slot_num = %d.\r\n", __func__, bandwidth, bufflength, slot_num); goto __TERMINAL; } //Save the slot_num to descriptor,since it will be used in usbDestroyISODescriptor routine. pIsoDesc->slot_num = slot_num; slot_space = USB_PERIODIC_LIST_LENGTH / slot_num; if (0 == slot_space) { slot_space = 1; } #ifdef __DEBUG_USB_ISO _hx_printf("slot_num:%d,slot_space:%d.\r\n", slot_num, slot_space); #endif //Stop periodic schedule if enabled already. WaitForThisObject(pEhciCtrl->hMutex); if (pEhciCtrl->periodic_schedules > 0) { if (ehci_disable_periodic(pEhciCtrl) < 0) { ReleaseMutex(pEhciCtrl->hMutex); _hx_printf("FATAL %s: periodic should never fail, but did.\r\n", __func__); goto __TERMINAL; } } //Insert the iTD to periodic list,and insert the ISOXfer descriptor into EHCI controller's //list. i = 0; __ENTER_CRITICAL_SECTION(NULL, dwFlags); while (slot_num) { pitd->lp_next = pEhciCtrl->periodic_list[i]; pEhciCtrl->periodic_list[i] = ((__U32)pitd | QH_LINK_TYPE_ITD); flush_dcache_range((unsigned long)&pEhciCtrl->periodic_list[i], ALIGN_END_ADDR(uint32_t, &pEhciCtrl->periodic_list[i], 1)); i += slot_space; //Re-calculate the space between slot to make sure the iTD can be linked into //periodic list as scatterly as possible. slot_space = (USB_PERIODIC_LIST_LENGTH - i) / slot_num; if (0 == slot_space) { slot_space = 1; } slot_num--; } //Insert it into global list. if (NULL == pEhciCtrl->pIsoDescFirst) //First element. { pEhciCtrl->pIsoDescFirst = pIsoDesc; pEhciCtrl->pIsoDescLast = pIsoDesc; } else //Put it at last. { //We only support one isochronous xfer at the sametime for simpicity. BUG(); if (NULL == pEhciCtrl->pIsoDescLast) { BUG(); } pEhciCtrl->pIsoDescLast->pNext = pIsoDesc; pEhciCtrl->pIsoDescLast = pIsoDesc; } __LEAVE_CRITICAL_SECTION(NULL, dwFlags); //Restart the periodic schedule if already enabled. if (pEhciCtrl->periodic_schedules > 0) { ehci_enable_periodic(pEhciCtrl); } ReleaseMutex(pEhciCtrl->hMutex); bResult = TRUE; __TERMINAL: if (!bResult) { if (pIsoDesc) //Should release it. { if (pIsoDesc->hEvent) { DestroyEvent(pIsoDesc->hEvent); } _hx_free(pIsoDesc); } if (pitd) { _hx_free(pitd); } pIsoDesc = NULL; //Mark as failed. } return pIsoDesc; }
/* Purge one NAT entry from NAT module. */ static BOOL PurgeNatEntry(__EASY_NAT_ENTRY* pEntry) { BOOL bResult = FALSE; __EASY_NAT_ENTRY* pHashList = NULL; __EASY_NAT_ENTRY* pPrev = NULL; unsigned long hash_key = 0; int err_code = -1; BUG_ON(NULL == pEntry); hash_key = enatGetHashKeyByEntry(pEntry,in); WaitForThisObject(NatManager.lock); /* Get the hash list with the same key. */ pHashList = NatManager.pTree->Lookup(NatManager.pTree,hash_key); if (NULL == pHashList) /* Maybe caused by invalid pEntry. */ { ReleaseMutex(NatManager.lock); __LOG("NAT entry not in RDX tree[key = %d].\r\n", hash_key); goto __TERMINAL; } if (pHashList == pEntry) /* First one is the delete target. */ { if (NULL == pHashList->pHashNext) /* Only one NAT entry. */ { NatManager.pTree->Delete(NatManager.pTree, hash_key); } else /* More NAT entry exist. */ { /* Delete first and then insert the next NAT entry. */ NatManager.pTree->Delete(NatManager.pTree, hash_key); err_code = NatManager.pTree->Insert(NatManager.pTree, hash_key, pHashList->pHashNext); if (ERR_OK != err_code) { ReleaseMutex(NatManager.lock); _hx_printf("[NAT]: failed to re-insert NAT entry into radix tree[err = %d].\r\n", err_code); goto __TERMINAL; } } } else /* Just delete the pEntry from hash list. */ { pPrev = pHashList; pHashList = pHashList->pHashNext; while (pHashList) { if (pHashList == pEntry) { break; } pPrev = pHashList; pHashList = pHashList->pHashNext; } if (NULL == pHashList) /* Can not find pEntry in hash list. */ { ReleaseMutex(NatManager.lock); __LOG("NAT entry not in hash list[key = %d].\r\n", hash_key); goto __TERMINAL; } /* Delete pEntry from hash list. */ pPrev->pHashNext = pPrev->pHashNext->pHashNext; } /* Just delete pEntry from global list. */ pEntry->pNext->pPrev = pEntry->pPrev; pEntry->pPrev->pNext = pEntry->pNext; DestroyNatEntry(&NatManager, pEntry); ReleaseMutex(NatManager.lock); bResult = TRUE; __TERMINAL: return bResult; }
/* Packet out direction process for easy NAT. */ static BOOL enatPacketOut(struct pbuf* p, struct netif* out_if) { struct ip_hdr *pHdr = NULL; __EASY_NAT_ENTRY* pEntry = NULL; unsigned long hash_key = 0; int hash_deep = 0; BOOL bResult = FALSE; BUG_ON((NULL == p) || (NULL == out_if)); /* Validate the packet before apply NAT. */ if (!NAT_PACKET_VALIDATE(p, out)) { goto __TERMINAL; } /* Increment total translation request times. */ NatManager.stat.trans_times++; /* Calculate hash key to locate the NAT entry. */ pHdr = (struct ip_hdr*)p->payload; hash_key = enatGetHashKeyByHdr(pHdr,out); /* * Try to locate a corresponding NAT entry in * radix tree by apply hash key. * If can not locate,create a new one,otherwise, * translate the IP packet by using the NAT * entry. */ WaitForThisObject(NatManager.lock); pEntry = NatManager.pTree->Lookup(NatManager.pTree, hash_key); if (NULL == pEntry) /* No entry yet. */ { pEntry = AddNewNatEntry(&NatManager, pHdr, out_if); if (NULL == pEntry) { ReleaseMutex(NatManager.lock); goto __TERMINAL; } } else /* Found the corresponding NAT entries. */ { /* Travel the whole collision list. */ while (pEntry) { if (_OutPacketMatch(pHdr, pEntry)) { OutTranslation(pEntry, pHdr, p); if (hash_deep > NatManager.stat.hash_deep) { NatManager.stat.hash_deep = hash_deep; /* Save the NAT entry to stat object,for performance improvement purpuse. */ memcpy(&NatManager.stat.deepNat, pEntry, sizeof(__EASY_NAT_ENTRY)); } ReleaseMutex(NatManager.lock); bResult = TRUE; goto __TERMINAL; } hash_deep++; pEntry = pEntry->pHashNext; } /* * Also can not locate the NAT entry when reach here, * hash collision occur. */ pEntry = AddNewNatEntry(&NatManager, pHdr, out_if); if (NULL == pEntry) { ReleaseMutex(NatManager.lock); goto __TERMINAL; } } /* Translate the IP packet using the new created NAT entry. */ OutTranslation(pEntry, pHdr, p); ReleaseMutex(NatManager.lock); bResult = TRUE; __TERMINAL: return bResult; }
/* Packet in direction process for easy NAT. */ static BOOL enatPacketIn(struct pbuf* p, struct netif* in_if) { struct ip_hdr *pHdr = NULL; __EASY_NAT_ENTRY* pEntry = NULL; unsigned long hash_key = 0; int hash_deep = 0; BOOL bResult = FALSE; int i = 0; BUG_ON((NULL == p) || (NULL == in_if)); /* Validate the packet before apply NAT. */ if (!NAT_PACKET_VALIDATE(p, in)) { goto __TERMINAL; } /* Increment total translation request times. */ NatManager.stat.trans_times++; /* * Calculate hash key to locate the corresponding NAT entry * in radix tree. */ pHdr = (struct ip_hdr*)p->payload; hash_key = enatGetHashKeyByHdr(pHdr,in); /* Try to locate the NAT entry. */ WaitForThisObject(NatManager.lock); pEntry = NatManager.pTree->Lookup(NatManager.pTree, hash_key); if (NULL == pEntry) /* No NAT entry found. */ { ReleaseMutex(NatManager.lock); goto __TERMINAL; } /* Search the NAT entry list. */ while (pEntry) { if (_InPacketMatch(pHdr, pEntry)) { InTranslation(pEntry, pHdr, p); if (hash_deep > NatManager.stat.hash_deep) { NatManager.stat.hash_deep = hash_deep; /* Save the NAT entry to stat object,for performance improvement purpuse. */ memcpy(&NatManager.stat.deepNat, pEntry, sizeof(__EASY_NAT_ENTRY)); } ReleaseMutex(NatManager.lock); bResult = TRUE; goto __TERMINAL; } hash_deep++; pEntry = pEntry->pHashNext; } /* Can not find the matched NAT entry when reach here. */ ReleaseMutex(NatManager.lock); __TERMINAL: return bResult; }
/* * Add a new NAT entry in system,when out direction entry can not * be found. */ static __EASY_NAT_ENTRY* AddNewNatEntry(__NAT_MANAGER* pMgr, struct ip_hdr* pHdr, struct netif* pOutIf) { __EASY_NAT_ENTRY* pEntry = NULL; __EASY_NAT_ENTRY* pHashList = NULL; int err_code = -1; unsigned long hash_key = 0; BOOL bResult = FALSE; BUG_ON(NULL == pMgr); BUG_ON(NULL == pHdr); BUG_ON(NULL == pOutIf); /* Try to create a new NAT entry. */ pEntry = CreateNatEntry(pMgr); if (NULL == pEntry) { goto __TERMINAL; } /* Initialize it by using IP hdr. */ InitNatEntry(pEntry, pHdr, pOutIf); /* * Calculate the corresponding hash key of the new NAT * in radix tree. */ hash_key = enatGetHashKeyByHdr(pHdr,out); /* Add the new NAT entry into radix tree and global list. */ WaitForThisObject(pMgr->lock); pHashList = pMgr->pTree->Lookup(pMgr->pTree, hash_key); if (NULL == pHashList) /* No entry with the same key. */ { pEntry->pHashNext = NULL; err_code = pMgr->pTree->Insert(pMgr->pTree, hash_key, pEntry); if (ERR_OK != err_code) { ReleaseMutex(pMgr->lock); _hx_printf("Insert NAT entry into radix tree failed[code = %d]", err_code); goto __TERMINAL; } } else /* Hash collision,just link to hash list. */ { pEntry->pHashNext = pHashList->pHashNext; pHashList->pHashNext = pEntry; } /* Add to global NAT entry list. */ pEntry->pNext = pMgr->entryList.pNext; pEntry->pNext->pPrev = pEntry; pEntry->pPrev = &pMgr->entryList; pMgr->entryList.pNext = pEntry; ReleaseMutex(pMgr->lock); bResult = TRUE; __TERMINAL: if (!bResult) { if (pEntry) { _hx_free(pEntry); pEntry = NULL; } } return pEntry; }
/* * A helper routine to initialize and register a new found R8152 * device. It will be invoked when a new device is scaned in Driver Entry * routine. */ static int Init_R8152(struct usb_device *dev, unsigned int ifnum) { struct usb_interface *iface; struct usb_interface_descriptor *iface_desc; int ep_in_found = 0, ep_out_found = 0; struct ueth_data* ss = NULL; int i, ret = 0; struct r8152 *tp = NULL; char recv_name[64]; static int ef_idx = 0; /* Construct a new management data struct of R8152. */ ss = _hx_malloc(sizeof(struct ueth_data)); if (NULL == ss) { goto __TERMINAL; } memset(ss, 0, sizeof(struct ueth_data)); /* let's examine the device now */ iface = &dev->config.if_desc[ifnum]; iface_desc = &dev->config.if_desc[ifnum].desc; /* At this point, we know we've got a live one */ debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); /* Initialize the ueth_data structure with some useful info */ ss->ifnum = ifnum; ss->pusb_dev = dev; ss->subclass = iface_desc->bInterfaceSubClass; ss->protocol = iface_desc->bInterfaceProtocol; /* alloc driver private */ ss->dev_priv = calloc(1, sizeof(struct r8152)); if (!ss->dev_priv) { goto __TERMINAL; } memzero(ss->dev_priv, sizeof(struct r8152)); /* * We are expecting a minimum of 3 endpoints - in, out (bulk), and * int. We will ignore any others. */ for (i = 0; i < iface_desc->bNumEndpoints; i++) { /* is it an BULK endpoint? */ if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { u8 ep_addr = iface->ep_desc[i].bEndpointAddress; if ((ep_addr & USB_DIR_IN) && !ep_in_found) { ss->ep_in = ep_addr & USB_ENDPOINT_NUMBER_MASK; ep_in_found = 1; } else { if (!ep_out_found) { ss->ep_out = ep_addr & USB_ENDPOINT_NUMBER_MASK; ep_out_found = 1; } } } /* is it an interrupt endpoint? */ if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { ss->ep_int = iface->ep_desc[i].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ss->irqinterval = iface->ep_desc[i].bInterval; } } debug("Endpoints In %d Out %d Int %d\n", ss->ep_in, ss->ep_out, ss->ep_int); /* Do some basic sanity checks, and bail if we find a problem */ if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) || !ss->ep_in || !ss->ep_out || !ss->ep_int) { debug("Problems with device\n"); goto __TERMINAL; } /* Establish data structure's relationship. */ dev->privptr = (void *)ss; tp = ss->dev_priv; tp->udev = dev; tp->intf = iface; r8152b_get_version(tp); if (rtl_ops_init(tp)) { _hx_printf("%s: failed to init r8152 device.\r\n", __func__); goto __TERMINAL; } tp->rtl_ops.init(tp); tp->rtl_ops.up(tp); rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); /* Assign a index value to this USB ethernet interface. */ ss->ef_idx = ef_idx++; /* Initialization seems OK,now register the R8152 device into * HelloX kernel. */ if (!Register_R8152(dev, ss)) { _hx_printf("Failed to register R8152 into system.\r\n"); goto __TERMINAL; } /* * Create the recv and send buffer.These 2 buffers * will be released when the corresponding rx/tx thread exit. */ ss->rx_buff = (char*)_hx_aligned_malloc(RTL8152_AGG_BUF_SZ, USB_DMA_MINALIGN); if (NULL == ss->rx_buff) { goto __TERMINAL; } ss->tx_buff = (char*)_hx_aligned_malloc(RTL8152_AGG_BUF_SZ, USB_DMA_MINALIGN); if (NULL == ss->tx_buff) { goto __TERMINAL; } /* * Create the rx and tx bulk transfer descriptor,which is used * by the corresponding rx/tx thread. * These 2 descriptors will be destroyed by the rx/tx thread before * exit. */ ss->pTxDesc = usbCreateAsyncDescriptor( ss->pusb_dev, usb_sndbulkpipe(ss->pusb_dev, ss->ep_out), ss->tx_buff, RTL8152_AGG_BUF_SZ, NULL); if (NULL == ss->pTxDesc) { goto __TERMINAL; } ss->pRxDesc = usbCreateAsyncDescriptor( ss->pusb_dev, usb_rcvbulkpipe(ss->pusb_dev, ss->ep_in), ss->rx_buff, RTL8152_AGG_BUF_SZ, NULL); if (NULL == ss->pRxDesc) { _hx_printf("%s: create rx desc failed.\r\n", __func__); goto __TERMINAL; } /* * Create the dedicated receiving kernel thread. */ _hx_sprintf(recv_name, "%s%d", R8152_RECV_NAME_BASE, ss->ef_idx); ss->pRxThread = KernelThreadManager.CreateKernelThread( (__COMMON_OBJECT*)&KernelThreadManager, 0, KERNEL_THREAD_STATUS_SUSPENDED, PRIORITY_LEVEL_NORMAL, __R8152_Recv, (LPVOID)ss, NULL, recv_name); if (NULL == ss->pRxThread) { goto __TERMINAL; } /* * Create the dedicated sending kernel thread. */ _hx_sprintf(recv_name, "%s%d", R8152_SEND_NAME_BASE, ss->ef_idx); ss->pTxThread = KernelThreadManager.CreateKernelThread( (__COMMON_OBJECT*)&KernelThreadManager, 0, KERNEL_THREAD_STATUS_SUSPENDED, PRIORITY_LEVEL_NORMAL, __R8152_Send, (LPVOID)ss, NULL, recv_name); if (NULL == ss->pTxThread) { goto __TERMINAL; } /* Link the management data structure into global list. */ ss->pNext = global_list; global_list = ss; /* Resume the corresponding thread to run. */ /*KernelThreadManager.ResumeKernelThread( (__COMMON_OBJECT*)&KernelThreadManager, (__COMMON_OBJECT*)ss->pRxThread); KernelThreadManager.ResumeKernelThread( (__COMMON_OBJECT*)&KernelThreadManager, (__COMMON_OBJECT*)ss->pTxThread);*/ /* Mark all things in place. */ ret = 1; __TERMINAL: if (0 == ret) /* Failed,should release all resources allocated. */ { if (ss) { Unregister_R8152(dev, ss); if (ss->pRxThread) //Shoud destroy it. { WaitForThisObject((HANDLE)ss->pRxThread); KernelThreadManager.DestroyKernelThread( (__COMMON_OBJECT*)&KernelThreadManager, (__COMMON_OBJECT*)ss->pRxThread); } if (ss->pTxThread) { WaitForThisObject((HANDLE)ss->pTxThread); KernelThreadManager.DestroyKernelThread( (__COMMON_OBJECT*)&KernelThreadManager, (__COMMON_OBJECT*)ss->pTxThread); } if (ss->dev_priv) { _hx_free(ss->dev_priv); } if (ss->rx_buff) { _hx_free(ss->rx_buff); } if (ss->tx_buff) { _hx_free(ss->tx_buff); } if (ss->pRxDesc) { usbStopAsyncXfer(ss->pRxDesc); usbDestroyAsyncDescriptor(ss->pRxDesc); } if (ss->pTxDesc) { usbStopAsyncXfer(ss->pTxDesc); usbDestroyAsyncDescriptor(ss->pTxDesc); } _hx_free(ss); } /* Reset USB device's private pointer since it maybe changed in * above process. */ dev->privptr = NULL; } return ret; }
DWORD Fibonacci(LPVOID lpParam) { //LPSTR lpszParam = (LPSTR)lpParam; __CMD_PARA_OBJ* pCmdParaObj = (__CMD_PARA_OBJ*)lpParam; __FIBONACCI_CONTROL_BLOCK ControlBlock[5] = {0}; HANDLE hThread[5] = {NULL}; CHAR Buffer[12]; DWORD dwCounter; DWORD dwIndex,i; PrintLine("Fibonacci application running..."); GotoHome(); ChangeLine(); if(NULL == pCmdParaObj || pCmdParaObj->byParameterNum < 2) { return 0; } dwCounter = 0; for(i = 0;i < 5;i ++) { dwIndex = 0; while(pCmdParaObj->Parameter[1][dwCounter]) { Buffer[dwIndex] = pCmdParaObj->Parameter[1][dwCounter]; dwIndex ++; dwCounter ++; } Buffer[dwIndex] = 0; Str2Hex(Buffer,&ControlBlock[i].dwInitNum); //Convert the parameter to integer. if(pCmdParaObj->Parameter[1][dwCounter]) { break; } } i = 5; for(i;i > 0;i --) { hThread[i - 1] = CreateKernelThread( 0, //Stack size,use default. KERNEL_THREAD_STATUS_READY, //Status. PRIORITY_LEVEL_NORMAL, CalculateThread, //Start routine. (LPVOID)&ControlBlock[i - 1], NULL, "FIBONACCI"); if(NULL == hThread[i - 1]) //Failed to create kernel thread. { PrintLine("Create kernel thread failed."); break; } } // //Waiting for the kernel thread to over. // WaitForThisObject(hThread[0]); WaitForThisObject(hThread[1]); WaitForThisObject(hThread[2]); WaitForThisObject(hThread[3]); WaitForThisObject(hThread[4]); // //Now,we have calculated the fibonacci number,print them out. // for(i = 0;i < 5;i ++) { Int2Str(ControlBlock[i].dwInitNum,Buffer); PrintStr(Buffer); PrintStr("'s result is: "); Int2Str(ControlBlock[i].dwResult,Buffer); PrintStr(Buffer); GotoHome(); ChangeLine(); } // //Close the kernel thread. // DestroyKernelThread(hThread[0]); DestroyKernelThread(hThread[1]); DestroyKernelThread(hThread[2]); DestroyKernelThread(hThread[3]); DestroyKernelThread(hThread[4]); return 1L; }