Exemplo n.º 1
0
/* 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;
}
Exemplo n.º 2
0
/* 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;
}
Exemplo n.º 3
0
/* 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);
}
Exemplo n.º 4
0
/* 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;
		}
	}
Exemplo n.º 5
0
//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;
}
Exemplo n.º 6
0
//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();
	}
Exemplo n.º 7
0
//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;
}
Exemplo n.º 8
0
/* 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;
}
Exemplo n.º 9
0
/* 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;
}
Exemplo n.º 10
0
/* 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;
}
Exemplo n.º 11
0
/* 
 * 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;
}
Exemplo n.º 12
0
/*
* 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;
}
Exemplo n.º 13
0
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;
}