Beispiel #1
0
/*
 * Commit USB sending request.
 */
static BOOL __Commit_Send(__ETHERNET_INTERFACE* pEthInt, char* pSendingBuff, int length, int buff_num)
{
	int actual_len = 0;
	struct ueth_data* ss = NULL;
	struct usb_device *udev = NULL;

	ss = (struct ueth_data*)pEthInt->pIntExtension;
	BUG_ON(NULL == ss);
	udev = ss->pusb_dev;
	BUG_ON(NULL == udev);

	char* msg = _hx_aligned_malloc(length, USB_DMA_MINALIGN);
	if (NULL == msg)
	{
		return FALSE;
	}
	memcpy(msg, pSendingBuff, length);

	int err = usb_bulk_msg(udev, usb_sndbulkpipe(udev, ss->ep_out),
		(void *)pSendingBuff, length,
		//(void*)msg,length,
		&actual_len, USB_BULK_SEND_TIMEOUT);

	/* debug */
	//_hx_printf("%s:len = %d,buff_num = %d,actual_len = %d.\r\n", 
	//	__func__, length, buff_num, actual_len);

	if (err < 0)
	{
		if (pEthInt->ifState.dwTxErrorNum < 6)
		{
			_hx_printf("%s: bulk msg fail[err = %d,buf_l = %d,buff_n = %d].\r\n",
				__func__,
				err,
				length,
				buff_num);
		}
		pEthInt->ifState.dwTxErrorNum += buff_num;
		_hx_free(msg);
		return FALSE;
	}
	/* Update interface level statistics counter. */
	pEthInt->ifState.dwFrameSendSuccess += buff_num;
	_hx_free(msg);
	return TRUE;
}
Beispiel #2
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;
}
Beispiel #3
0
/*
 * Check if there is a PCI device in system that matches
 * the given ID,and initialize it if found.
 */
static BOOL _Check_E1000_Nic(struct pci_device_id* id)
{
	__PHYSICAL_DEVICE*    pDev = NULL;
	__IDENTIFIER          devId;
	struct e1000_hw*      priv = NULL;
	__U16                 iobase_s = 0, iobase_e = 0;
	LPVOID                memAddr_s = NULL;
	LPVOID                memAddr_e = NULL;
	int                   intVector = 0;
	int                   index = 0;
	BOOL                  bResult = FALSE;
	int                   cardnum = 0;

	//Set device ID accordingly.
	devId.dwBusType = BUS_TYPE_PCI;
	devId.Bus_ID.PCI_Identifier.ucMask = PCI_IDENTIFIER_MASK_VENDOR | PCI_IDENTIFIER_MASK_DEVICE;
	devId.Bus_ID.PCI_Identifier.wVendor = id->vendor_id;
	devId.Bus_ID.PCI_Identifier.wDevice = id->device_id;

	//Try to fetch the physical device with the specified ID.
	pDev = DeviceManager.GetDevice(
		&DeviceManager,
		BUS_TYPE_PCI,
		&devId,
		NULL);
	if (NULL == pDev)  //PCNet may not exist.
	{
		//DEBUGOUT("%s:No device[v_id = 0x%X,d_id = 0x%X] found.\r\n",
		//	__func__,id->vendor_id,id->device_id);
		goto __TERMINAL;
	}

	//Got a valid device,retrieve it's hardware resource and save them into 
	//private structure.
	while (pDev)
	{
		for (index = 0; index < MAX_RESOURCE_NUM; index++)
		{
			if (pDev->Resource[index].dwResType == RESOURCE_TYPE_INTERRUPT)
			{
				intVector = pDev->Resource[index].Dev_Res.ucVector;
			}
			if (pDev->Resource[index].dwResType == RESOURCE_TYPE_IO)
			{
				iobase_s = pDev->Resource[index].Dev_Res.IOPort.wStartPort;
				iobase_e = pDev->Resource[index].Dev_Res.IOPort.wEndPort;
			}
			if (pDev->Resource[index].dwResType == RESOURCE_TYPE_MEMORY)
			{
				memAddr_s = pDev->Resource[index].Dev_Res.MemoryRegion.lpStartAddr;
				memAddr_e = pDev->Resource[index].Dev_Res.MemoryRegion.lpEndAddr;
			}
		}
		//Check if the device with valid resource.
		if ((0 == intVector) && (0 == iobase_s) && (NULL == memAddr_s))
		{
			DEBUGOUT("%s: Find a device without valid resource.\r\n", __func__);
			goto __TERMINAL;
		}

		//Now allocate a rtl8111_priv_t structure and fill the resource.
		priv = (struct e1000_hw*)_hx_malloc(sizeof(struct e1000_hw));
		if (NULL == priv)
		{
			DEBUGOUT("%s:allocate e1000 private structure failed.\r\n", __func__);
			goto __TERMINAL;
		}
		memset(priv, 0, sizeof(struct e1000_hw));

		/* Create tx/rx descriptors and packet buffer. */
		priv->tx_base = (struct e1000_tx_desc*)_hx_aligned_malloc(
			TX_DESC_NUM * sizeof(struct e1000_tx_desc), E1000_BUFFER_ALIGN);
		if (NULL == priv->tx_base)
		{
			goto __TERMINAL;
		}
		priv->rx_base = (struct e1000_rx_desc*)_hx_aligned_malloc(
			RX_DESC_NUM * sizeof(struct e1000_rx_desc), E1000_BUFFER_ALIGN);
		if (NULL == priv->rx_base)
		{
			goto __TERMINAL;
		}
		priv->packet = (unsigned char*)_hx_aligned_malloc(PACKET_BUFFER_SIZE,
			E1000_BUFFER_ALIGN);
		if (NULL == priv->packet)
		{
			goto __TERMINAL;
		}

		priv->pdev = pDev;
		priv->ioport_s = iobase_s;
		priv->ioport_e = iobase_e;
		priv->memaddr_s = memAddr_s;
		priv->memaddr_e = memAddr_e;
		priv->int_vector = intVector;
		priv->cardnum = cardnum++;
		/* Save PCI id. */
		priv->device_id = id->device_id;
		priv->vendor_id = id->vendor_id;

		if (_Init_E1000(priv))
		{
			//Link the private object into global list.
			priv->pNext = e1000_hw_list;
			e1000_hw_list = priv;
			bResult = TRUE;
		}
		else
		{
			goto __TERMINAL;
		}

		DEBUGOUT("%s: Get a E1000 NIC device[int = %d,iobase = 0x%X,mem = 0x%X].\r\n",
			__func__,
			intVector,
			iobase_s,
			memAddr_s);

		//Try to fetch another PCNet device.
		pDev = DeviceManager.GetDevice(
			&DeviceManager,
			BUS_TYPE_PCI,
			&devId,
			pDev);
	}

__TERMINAL:
	if (!bResult)
	{
		if (priv)
		{
			if (priv->tx_base)
			{
				_hx_free(priv->tx_base);
			}
			if (priv->rx_base)
			{
				_hx_free(priv->rx_base);
			}
			if (priv->packet)
			{
				_hx_free(priv->packet);
			}
			_hx_free(priv);
		}
	}
	return bResult;
}
Beispiel #4
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;
}