Пример #1
0
int main(void)
{
  uint32_t tTime;


  main_init();

  tTime = millis();
  while(1)
  {
    if( millis()-tTime > 100 )
    {
      tTime = millis();
      led_toggle(0);
    }


#if 0
    uint8_t ch;
    static uint32_t cnt = 0;

    vcp_printf("cnd : %d \r\n", cnt++);


    if( vcp_is_available() )
    {
      ch = vcp_getch();
      vcp_printf("pressed : 0x%02X \r\n", ch);
      //vcp_printf("float test %f\r\n",fvalue);
    }
#else
    msg_process_vcp();
#endif
  }
}
Пример #2
0
void HID_Default_Data_Handler(void* p_io, uint8_t* data, uint16_t len)
{
	USBH_DevIO_t* p_in = (USBH_DevIO_t*)p_io;

	vcp_printf("%s:C%d:IntIN:", USBH_Dev_DebugPrint(p_in->pdev, p_in->ep), len);
	for (uint8_t k = 0; k < len; k++) {
		vcp_printf(" 0x%02X", data[k]);
	}
	vcp_printf("\r\n");

	//dbg_printf(DBGMODE_DEBUG, "%s:C%d:IntIN:\r\n", USBH_Dev_DebugPrint(p_in->pdev, p_in->ep), len);

	HID_Rpt_Parsing_Params_t* parser = (HID_Rpt_Parsing_Params_t*)(p_in->extra);

	if (parser->mouse_exists > 0 && parser->mouse_ep == p_in->ep->bEndpointAddress && (parser->mouse_report_id <= 0 || parser->mouse_report_id == data[0]))
	{
		if (parser->mouse_report_id > 0) { data = &data[1]; len--; }
		kbm2c_handleMouseReport(data, len, parser);
	}
	if (parser->kb_exists > 0 && parser->kb_ep == p_in->ep->bEndpointAddress && (parser->kb_report_id <= 0 || parser->kb_report_id == data[0]))
	{
		if (parser->kb_report_id > 0) { data = &data[1]; len--; }
		kbm2c_handleKeyReport(data[0], &data[2], len - 2);
	}
}
Пример #3
0
void USBH_Dev_DefaultCB_EnumerationDone(USB_OTG_CORE_HANDLE *pcore , USBH_DEV *pdev)
{
	vcp_printf("Unknown Class Device V%04XP%04XA%d Enumerated\r\n", pdev->device_prop.Dev_Desc.idVendor, pdev->device_prop.Dev_Desc.idProduct, pdev->device_prop.address);
}
Пример #4
0
void USBH_Dev_HID_EnumerationDone(USB_OTG_CORE_HANDLE *pcore, USBH_DEV *pdev)
{
	if (pdev->Usr_Data != 0) {
		free(pdev->Usr_Data);
		pdev->Usr_Data = 0;
	}

	uint8_t numIntf = pdev->device_prop.Cfg_Desc.bNumInterfaces;
	char isHid = 0;
	pdev->Usr_Data = calloc(1, sizeof(HID_Data_t));
	HID_Data_t* HID_Data = pdev->Usr_Data;
	HID_Data->io = calloc(numIntf, sizeof(USBH_DevIO_t*));
	HID_Data->ioIdx = 0;

	dbg_printf(DBGMODE_DEBUG, "USBH_Dev_HID_EnumerationDone, bNumInterfaces: %d\r\n", numIntf);

	for (int i = 0; i < numIntf; i++)
	{
		// filter out non-HID class interfaces
		if (pdev->device_prop.Itf_Desc[i].bInterfaceClass != 0x03) {
			continue;
		}

		isHid = 1;

		USBH_DevD2H_DataHandler_t dataHandler = 0;
		HID_Rpt_Parsing_Params_t* parser = 0;
		uint8_t parserEp = 0;

		if (pdev->device_prop.Dev_Desc.idVendor == SONY_VID && pdev->device_prop.Dev_Desc.idProduct == DUALSHOCK3_PID) {
			// DUALSHOCK3
			dataHandler = USBH_DS3_Data_Handler;
			dbg_printf(DBGMODE_TRACE, "Dualshock 3 Detected\r\n");
		}
		else if (pdev->device_prop.Dev_Desc.idVendor == SONY_VID && pdev->device_prop.Dev_Desc.idProduct == DUALSHOCK4_PID) {
			// DUALSHOCK4
			dataHandler = USBH_DS4_Data_Handler;
			HID_Data->init_handler = USBH_DS4_Init_Handler;
			HID_Data->deinit_handler = USBH_DS4_DeInit_Handler;
			HID_Data->custom_task = USBH_DS4_Task;
			dbg_printf(DBGMODE_TRACE, "Dualshock 4 Detected\r\n");
		}
		// TODO handle others, like Xbox controllers
		else {
			// other, probably keyboard or mouse
			parser = malloc(sizeof(HID_Rpt_Parsing_Params_t));
			dataHandler = HID_Default_Data_Handler;
		}

		uint8_t maxEP = ( (pdev->device_prop.Itf_Desc[i].bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) ?
						pdev->device_prop.Itf_Desc[i].bNumEndpoints :
						USBH_MAX_NUM_ENDPOINTS);

		// assign interrupt endpoints to channels, and polling parameters for the D2H endpoint
		// warning: assume 1 interrupt endpoint per direction
		for (int j = 0; j < maxEP; j++)
		{
			USBH_EpDesc_TypeDef* epDesc = &(pdev->device_prop.Ep_Desc[i][j]);
			if ((epDesc->bmAttributes & EP_TYPE_MSK) == USB_EP_TYPE_INTR)
			{
				if ((epDesc->bEndpointAddress & USB_EP_DIR_MSK) == USB_EP_DIR_IN)
				{
					HID_Data->io[i] = USBH_DevIO_Manager_New(pcore, pdev, epDesc,
#ifdef USBH_HID_ENABLE_DYNAMIC_HC_ALLOC
							1
#else
							0
#endif
							,
							dataHandler, parser
					);
					parserEp = epDesc->bEndpointAddress;
				}
			}
		}

		USBH_Status status;

		if (parser != 0)
		{
			USBH_HIDDesc_TypeDef hidDesc;

			status = USBH_Get_HID_Descriptor_Blocking (pcore, pdev, i);
			if (status == USBH_OK) {
				USBH_ParseHIDDesc(&hidDesc, pcore->host.Rx_Buffer);
				vcp_printf("%sI%d:C%d:HIDDesc:\r\n", USBH_Dev_DebugPrint(pdev, 0), i, USB_HID_DESC_SIZE);
				for (uint8_t k = 0; k < USB_HID_DESC_SIZE; k++) {
					vcp_printf(" 0x%02X", pcore->host.Rx_Buffer[k]);
				}
				vcp_printf("\r\n");
			}
			else {
				dbg_printf(DBGMODE_ERR, "USBH_Get_HID_Descriptor_Blocking failed status: 0x%04X\r\n", status);
				USBH_ErrorHandle(pcore, pdev, status);
				continue;
			}

			uint8_t repIdList[8] = { 0, 0, 0, 0, 0, 0, 0, 0};

			status = USBH_Get_HID_ReportDescriptor_Blocking(pcore , pdev, i, hidDesc.wItemLength);
			if (status == USBH_OK) {
				dbg_printf(DBGMODE_DEBUG, "USBH_Get_HID_ReportDescriptor_Blocking OK: 0x%04X\r\n", status);

				vcp_printf("%sI%d:C%d:ReptDesc:", USBH_Dev_DebugPrint(pdev, 0), i, hidDesc.wItemLength);
				for (uint8_t k = 0; k < hidDesc.wItemLength; k++) {
					vcp_printf(" 0x%02X", pcore->host.Rx_Buffer[k]);
				}
				vcp_printf("\r\n");

				HID_Rpt_Parsing_Params_Reset(parser);
				HID_Rpt_Desc_Parse(pcore->host.Rx_Buffer, hidDesc.wItemLength, parser, parserEp, repIdList);
				//dbg_printf(DBGMODE_DEBUG, "HID_Rpt_Desc_Parse Complete \r\n");
				HID_Rpt_Parsing_Params_Debug_Dump(parser);
			}
			else {
				dbg_printf(DBGMODE_ERR, "USBH_Get_HID_ReportDescriptor_Blocking failed status: 0x%04X\r\n", status);
				USBH_ErrorHandle(pcore, pdev, status);
				continue;
			}

			char hasSetIdle = 0;
			for (int ridIdx = 0; ridIdx < 8; ridIdx++)
			{
				uint8_t rid = repIdList[ridIdx];
				if (rid > 0)
				{
					hasSetIdle = 1;
					status = USBH_Set_Idle_Blocking (pcore, pdev, i, 0, rid);
					if (status == USBH_OK) {
						dbg_printf(DBGMODE_DEBUG, "USBH_Set_Idle_Blocking[%d] OK: 0x%04X\r\n", rid, status);
					}
					else if(status == USBH_NOT_SUPPORTED || status == USBH_STALL) {
						dbg_printf(DBGMODE_DEBUG, "USBH_Set_Idle_Blocking[%d] NOT SUPPORTED\r\n", rid);
					}
					else {
						dbg_printf(DBGMODE_ERR, "USBH_Set_Idle_Blocking[%d] failed status: 0x%04X\r\n", rid, status);
						USBH_ErrorHandle(pcore, pdev, status);
					}
				}

				// end of list
				if (rid == 0) {
					break;
				}
			}

			if (hasSetIdle == 0)
			{
				status = USBH_Set_Idle_Blocking (pcore, pdev, i, 0, 0);
				if (status == USBH_OK) {
					dbg_printf(DBGMODE_DEBUG, "USBH_Set_Idle_Blocking[only %d] OK: 0x%04X\r\n", 0, status);
				}
				else if(status == USBH_NOT_SUPPORTED || status == USBH_STALL) {
					dbg_printf(DBGMODE_DEBUG, "USBH_Set_Idle_Blocking[only %d] NOT SUPPORTED\r\n", 0);
				}
				else {
					dbg_printf(DBGMODE_ERR, "USBH_Set_Idle_Blocking[only %d] failed status: 0x%04X\r\n", 0, status);
					USBH_ErrorHandle(pcore, pdev, status);
				}
			}
		}

		if (pdev->device_prop.Dev_Desc.idVendor == SONY_VID && pdev->device_prop.Dev_Desc.idProduct == DUALSHOCK4_PID)
		{
			// TODO
		}
		else
		{
			status = USBH_Set_Protocol_Blocking(pcore, pdev, i, 0); // this sets the protocol = "report"
			if (status == USBH_OK) {
				dbg_printf(DBGMODE_DEBUG, "USBH_Set_Protocol_Blocking OK: 0x%04X\r\n", status);
			}
			else {
				dbg_printf(DBGMODE_ERR, "USBH_Set_Protocol_Blocking failed status: 0x%04X\r\n", status);
				USBH_ErrorHandle(pcore, pdev, status);
			}
		}
	}

	if (isHid == 0) {

		// none of the interfaces are HID
		free(pdev->Usr_Data);
		pdev->Usr_Data = 0;
		pdev->cb = &USBH_Dev_CB_Default; // this will cause the device to not be serviced
	}

	if (HID_Data->init_handler != 0) {
		HID_Data->init_handler(pcore, pdev);
	}

	USBH_Dev_HID_Cnt++;
}
Пример #5
0
void USBH_Dev_Hub_DataHandler(void* p_io, uint8_t* data, uint16_t len)
{
	USBH_DevIO_t* p_in = p_io;
	USBH_DEV* pdev = p_in->pdev;
	USB_OTG_CORE_HANDLE* pcore = p_in->pcore;
	Hub_Data_t* Hub_Data = pdev->Usr_Data;
	USBH_Status errCode;

	int8_t alloc = 0;
	USBH_Dev_AllocControl(pcore, pdev);

	// when a device connects or disconnects from the hub, the hub will issue an interrupt-in message

	// iterate all the ports
	for (int pn = 0; pn < Hub_Data->num_ports; pn++)
	{
		int pnp1 = pn + 1;
		uint8_t bitIdx = pnp1 % 8;
		uint8_t byteIdx = pnp1 / 8;
		// did this port cause the event?
		if (data[byteIdx] & (1 << bitIdx))
		{
			if (Hub_Data->port_busy != 0 && Hub_Data->port_busy != pnp1) {
				// we can only handle one new device at a time, or else they all listen to address 0
				continue;
			}

			if (alloc == 0) {
				alloc = USBH_Dev_AllocControl(p_in->pcore, p_in->pdev);
			}

			uint16_t wPortStatus, wPortChange;
			errCode = USBH_Dev_Hub_GetPortStatus(pcore, pdev, pn, &wPortStatus, &wPortChange);

			if (errCode != USBH_OK) {
				dbg_printf(DBGMODE_ERR, "USBH_Dev_Hub_Handle_InterruptIn GetPortStatus (pn %d) failed (status 0x%04X) \r\n", pn, errCode);
				if (errCode == USBH_STALL || errCode == USBH_NOT_SUPPORTED) {
					errCode = USBH_ClrFeature_Blocking(pcore, pdev, 0, 0);
				}
				continue;
			}

			dbg_printf(DBGMODE_DEBUG, "Hub_Handle_InterruptIn Hub_GetPortStatus, pn: %d, s: 0x%04X, c: 0x%04X\r\n", pnp1, wPortStatus, wPortChange);

			if ((wPortStatus & (1 << HUBWPORTSTATUS_POWER_BIT)) == 0) {
				errCode = USBH_Dev_Hub_SetPortFeature(pcore, pdev, pnp1, HUBREQ_PORT_POWER);
				if (errCode == USBH_STALL || errCode == USBH_NOT_SUPPORTED) {
					errCode = USBH_ClrFeature_Blocking(pcore, pdev, 0, 0);
				}
			}

			if ((wPortStatus & (1 << HUBWPORTCHANGE_ENABLED_BIT)) == 0) {
				errCode = USBH_Dev_Hub_SetPortFeature(pcore, pdev, pn, HUBREQ_PORT_ENABLE);
				if (errCode == USBH_STALL || errCode == USBH_NOT_SUPPORTED) {
					errCode = USBH_ClrFeature_Blocking(pcore, pdev, 0, 0);
				}
			}

			if ((wPortChange & (1 << HUBWPORTCHANGE_RESET_BIT)) != 0) {
				errCode = USBH_Dev_Hub_ClearPortFeature(pcore, pdev, pn, HUBREQ_C_PORT_RESET, 0);
				if (errCode == USBH_STALL || errCode == USBH_NOT_SUPPORTED) {
					errCode = USBH_ClrFeature_Blocking(pcore, pdev, 0, 0);
				}
			}

			if ((wPortChange & (1 << HUBWPORTCHANGE_CONNSTAT_BIT)) != 0) {
				errCode = USBH_Dev_Hub_ClearPortFeature(pcore, pdev, pn, HUBREQ_C_PORT_CONNECTION, 0);
				if (errCode == USBH_STALL || errCode == USBH_NOT_SUPPORTED) {
					errCode = USBH_ClrFeature_Blocking(pcore, pdev, 0, 0);
				}
			}

			if ((wPortChange & (1 << HUBWPORTCHANGE_ENABLED_BIT)) != 0) {
				errCode = USBH_Dev_Hub_ClearPortFeature(pcore, pdev, pn, HUBREQ_C_PORT_ENABLE, 0);
				if (errCode == USBH_STALL || errCode == USBH_NOT_SUPPORTED) {
					errCode = USBH_ClrFeature_Blocking(pcore, pdev, 0, 0);
				}
			}

			if ((wPortStatus & (1 << HUBWPORTSTATUS_RESET_BIT)) != 0)
			{
				if (Hub_Data->children[pn] != 0 && Hub_Data->children[pn]->gState == HOST_IDLE)
				{
					Hub_Data->children[pn]->gState = HOST_DEV_RESET_PENDING;
				}
			}
			else
			{
				if (((wPortStatus & (1 << HUBWPORTSTATUS_CURCONN_BIT)) == 0 ||
				     (wPortStatus & (1 << HUBWPORTSTATUS_ENABLED_BIT)) == 0) &&
				     Hub_Data->children[pn] != 0 && Hub_Data->children[pn]->cb != 0 &&
				     Hub_Data->children[pn]->gState != HOST_IDLE && Hub_Data->children[pn]->gState != HOST_DEV_RESET_PENDING)
				{
					dbg_printf(DBGMODE_TRACE, "Hub %s disconnected device (pn %d)\r\n", USBH_Dev_DebugPrint(pdev, 0), pnp1);
					vcp_printf("Hub %s Lost Device on Port %d\r\n", USBH_Dev_DebugPrint(pdev, 0), pnp1);

					((USBH_Device_cb_TypeDef*)Hub_Data->children[pn]->cb)->DeviceDisconnected(pcore, pdev);
					USBH_DeInit(pcore, Hub_Data->children[pn]); // frees channels
					((USBH_Device_cb_TypeDef*)Hub_Data->children[pn]->cb)->DeInit(pcore, Hub_Data->children[pn]);
					((USBH_Device_cb_TypeDef*)Hub_Data->children[pn]->cb)->DeInitDev(pcore, Hub_Data->children[pn]); // this is the one that frees memory
					free(Hub_Data->children[pn]);
					Hub_Data->children[pn] = 0;
				}
				else if ((wPortStatus & (1 << HUBWPORTSTATUS_CURCONN_BIT)) != 0)
				{
					if ((wPortStatus & (1 << HUBWPORTSTATUS_RESET_BIT)) == 0 &&
					    (wPortStatus & (1 << HUBWPORTSTATUS_ENABLED_BIT)) != 0 &&
						Hub_Data->children[pn] != 0 && Hub_Data->children[pn]->cb != 0 && (Hub_Data->children[pn]->gState == HOST_DEV_RESET_PENDING || Hub_Data->children[pn]->gState == HOST_IDLE))
					{
						if (((USBH_Device_cb_TypeDef*)Hub_Data->children[pn]->cb)->ResetDevice != 0)
							((USBH_Device_cb_TypeDef*)Hub_Data->children[pn]->cb)->ResetDevice(pcore, pdev);
						Hub_Data->children[pn]->device_prop.speed = (wPortStatus & (1 << 9)) ? HPRT0_PRTSPD_LOW_SPEED : HPRT0_PRTSPD_FULL_SPEED; // if bit 9 is 1, then it is low speed (0x02), or else it is full speed (0x01)
						if (((USBH_Device_cb_TypeDef*)Hub_Data->children[pn]->cb)->DeviceSpeedDetected != 0)
							((USBH_Device_cb_TypeDef*)Hub_Data->children[pn]->cb)->DeviceSpeedDetected(pcore, Hub_Data->children[pn], Hub_Data->children[pn]->device_prop.speed);

						Hub_Data->children[pn]->gState = HOST_DEV_DELAY;
						USBH_Dev_Reset_Timer = systick_1ms_cnt;
						Hub_Data->children[pn]->device_prop.address = 0; // new attached devices to a hub is always address 0
						Hub_Data->port_busy = pnp1;
						Hub_Data->intInEpIo->enabled = 0;
						// we are allowed to pass this on to the upper state machine now, it will seem like it was attached normally
						dbg_printf(DBGMODE_TRACE, "Hub passed new device (pn %d) to upper state machine \r\n", pnp1);
						vcp_printf("Hub %s New Device on Port %d\r\n", USBH_Dev_DebugPrint(pdev, 0), pnp1);
					}
					else if (Hub_Data->children[pn] == 0)
					{
						errCode = USBH_Dev_Hub_SetPortFeature(pcore, pdev, pn, HUBREQ_PORT_RESET);
						Hub_Data->children[pn] = calloc(1, sizeof(USBH_DEV));
						Hub_Data->children[pn]->Parent = pdev;
						Hub_Data->children[pn]->gState = HOST_IDLE;
						Hub_Data->children[pn]->gStateBkp = HOST_IDLE;
						Hub_Data->children[pn]->EnumState = ENUM_IDLE;
						Hub_Data->children[pn]->RequestState = CMD_SEND;
						Hub_Data->children[pn]->device_prop.address = USBH_DEVICE_ADDRESS_DEFAULT; // this better be 0
						Hub_Data->children[pn]->device_prop.speed = HPRT0_PRTSPD_LOW_SPEED;
						Hub_Data->children[pn]->port_num = pnp1;
						Hub_Data->children[pn]->Control.hc_num_in = -1;
						Hub_Data->children[pn]->Control.hc_num_out = -1;
						Hub_Data->children[pn]->Control.hc_in_tgl_in = -1;
						Hub_Data->children[pn]->Control.hc_in_tgl_out = -1;
						Hub_Data->children[pn]->Control.hc_out_tgl_in = -1;
						Hub_Data->children[pn]->Control.hc_out_tgl_out = -1;
						Hub_Data->children[pn]->Control.state = CTRL_IDLE;
						Hub_Data->children[pn]->Control.ep0size = USB_OTG_MAX_EP0_SIZE;
						Hub_Data->children[pn]->cb = (void*)&USBH_Dev_CB_Default;
						Hub_Data->port_busy = pnp1;
						dbg_printf(DBGMODE_TRACE, "Hub %s created new child (pn %d) \r\n", USBH_Dev_DebugPrint(pdev, 0), pnp1);
					}
				}
			}
		}
	}

	if (alloc != 0) {
		USBH_Dev_FreeControl(p_in->pcore, p_in->pdev);
	}
}
Пример #6
0
void USBH_Dev_Hub_EnumerationDone(USB_OTG_CORE_HANDLE *pcore , USBH_DEV *pdev)
{
	dbg_printf(DBGMODE_TRACE, "Hub_EnumerationDone \r\n");

	if (pdev->Usr_Data != 0) {
		free(pdev->Usr_Data);
		pdev->Usr_Data = 0;
	}
	pdev->Usr_Data = calloc(1, sizeof(Hub_Data_t));
	Hub_Data_t* Hub_Data = pdev->Usr_Data;

	uint8_t maxEP = ( (pdev->device_prop.Itf_Desc[0].bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) ?
					pdev->device_prop.Itf_Desc[0].bNumEndpoints :
					USBH_MAX_NUM_ENDPOINTS);

	for (uint8_t num=0; num < maxEP; num++)
	{
		USBH_EpDesc_TypeDef* epDesc = &(pdev->device_prop.Ep_Desc[0][num]);

		if ((epDesc->bmAttributes & EP_TYPE_MSK) == USB_EP_TYPE_INTR && (epDesc->bEndpointAddress & USB_EP_DIR_MSK) == USB_EP_DIR_IN)
		{
			//if (epDesc->bInterval > 50) epDesc->bInterval = 50;

			Hub_Data->intInEpIo = USBH_DevIO_Manager_New(pcore, pdev, epDesc,
#ifdef HUB_ENABLE_DYNAMIC_HC_ALLOC
						1
#else
						0
#endif
						, USBH_Dev_Hub_DataHandler, 0);
			Hub_Data->intInEpIo->force_poll_interval = 1;
			Hub_Data->intInEpIo->timeout = 10;
		}
	}

	if (Hub_Data->intInEpIo == 0) {
		dbg_printf(DBGMODE_ERR, "Hub %s has no interrupt-in endpoints!\r\n", USBH_Dev_DebugPrint(pdev, 0));
	}

	// the old example HID code used a state machine to perform the sequence of requests, but here we will just do everything in a sequence

	// get the hub descriptor so we know the number of ports available
	USBH_Status status = USBH_GetDescriptor_Blocking(pcore,
								pdev,
								USB_REQ_RECIPIENT_DEVICE
								| USB_REQ_TYPE_CLASS,
								USB_DESC_HUB,
								0,
								pcore->host.Rx_Buffer,
								USB_HUB_DESC_SIZE
								);

	if (status != USBH_OK) {
		dbg_printf(DBGMODE_ERR, "Hub_EnumerationDone GetDescriptor failed, status 0x%02X \r\n", status);
		USBH_ErrorHandle(pcore, pdev, status);
		return;
	}

	Hub_Data->num_ports = pcore->host.Rx_Buffer[2];

	//dbg_printf(DBGMODE_DEBUG, "\tbDescriptorType = 0x%02X\r\n", pcore->host.Rx_Buffer[1]);
	dbg_printf(DBGMODE_DEBUG, "\tnum_ports = %d\r\n", Hub_Data->num_ports);
	vcp_printf("Hub V%04XP%04XA%d Enumerated, %d ports\r\n", pdev->device_prop.Dev_Desc.idVendor, pdev->device_prop.Dev_Desc.idProduct, pdev->device_prop.address, Hub_Data->num_ports);

	// allocate memory for the children devices
	if (Hub_Data->children != 0) {
		free(Hub_Data->children);
		Hub_Data->children = 0;
	}
	Hub_Data->children = calloc(Hub_Data->num_ports, sizeof(USBH_DEV*));

	// iterate all the ports
	for (int pn = 0; pn < Hub_Data->num_ports; pn++)
	{
		Hub_Data->children[pn] = 0; // reset

		uint16_t wps, wpc;

		status = USBH_Dev_Hub_GetPortStatus(pcore, pdev, pn, &wps, &wpc);
		if (status != USBH_OK) {
			dbg_printf(DBGMODE_ERR, "Hub_EnumerationDone GetPortStatus (pn %d) failed, status 0x%02X \r\n", pn + 1, status);
			USBH_ErrorHandle(pcore, pdev, status);
			continue;
		}

		status = USBH_Dev_Hub_SetPortFeature(pcore, pdev, pn, HUBREQ_PORT_POWER);
		if (status != USBH_OK) {
			dbg_printf(DBGMODE_ERR, "Hub_EnumerationDone SetPortFeature (pn %d) failed, status 0x%02X \r\n", pn + 1, status);
			USBH_ErrorHandle(pcore, pdev, status);
			continue;
		}
	}

	// wait for power ready
	char pwrRdy;
	volatile int pwrTries = 700 / Hub_Data->num_ports;
	do
	{
		pwrRdy = 1;
		for (int pn = 0; pn < Hub_Data->num_ports; pn++)
		{
			uint16_t wps, wpc;

			status = USBH_Dev_Hub_GetPortStatus(pcore, pdev, pn, &wps, &wpc);
			if (status != USBH_OK) {
				dbg_printf(DBGMODE_ERR, "Hub_EnumerationDone GetPortStatus (pn %d) failed, status 0x%02X \r\n", pn + 1, status);
				//USBH_ErrorHandle(pcore, pdev, status);
				continue;
			}

			if (wps & (1 << HUBWPORTSTATUS_POWER_BIT) == 0) {
				pwrRdy = 0;
			}
		}
	}
	while (pwrRdy == 0 && pwrTries--);

	if (pwrRdy != 0) {
		dbg_printf(DBGMODE_TRACE, "Hub_EnumerationDone all port power ready \r\n");
	}
	else {
		dbg_printf(DBGMODE_ERR, "Hub_EnumerationDone error, power not ready \r\n");
	}

	vcp_printf("%s:Hub Ready, Ports: %d \r\n", USBH_Dev_DebugPrint(pdev, 0), Hub_Data->num_ports);
}