/** * * This function configures the DEVICE side of the controller. The caller needs * to pass in the desired configuration (e.g. number of endpoints) and a * DMAable buffer that will hold the Queue Head List and the Transfer * Descriptors. The required size for this buffer can be obtained by the caller * using the: XUsbPs_DeviceMemRequired() macro. * * @param InstancePtr is a pointer to the XUsbPs instance of the * controller. * @param CfgPtr is a pointer to the configuration structure that contains * the desired DEVICE side configuration. * * @return * - XST_SUCCESS: The operation completed successfully. * - XST_FAILURE: An error occured. * * @note * The caller may configure the controller for both, DEVICE and * HOST side. * ******************************************************************************/ int XUsbPs_ConfigureDevice(XUsbPs *InstancePtr, const XUsbPs_DeviceConfig *CfgPtr) { int Status; u32 ModeValue = 0x0; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(CfgPtr != NULL); /* Copy the configuration data over into the local instance structure */ InstancePtr->DeviceConfig = *CfgPtr; /* Align the buffer to a 2048 byte (XUSBPS_dQH_BASE_ALIGN) boundary.*/ InstancePtr->DeviceConfig.PhysAligned = (InstancePtr->DeviceConfig.DMAMemPhys + XUSBPS_dQH_BASE_ALIGN) & ~(XUSBPS_dQH_BASE_ALIGN -1); /* Initialize the endpoint pointer list data structure. */ XUsbPs_EpListInit(&InstancePtr->DeviceConfig); /* Initialize the Queue Head structures in DMA memory. */ XUsbPs_dQHInit(&InstancePtr->DeviceConfig); /* Initialize the Transfer Descriptors in DMA memory.*/ Status = XUsbPs_dTDInit(&InstancePtr->DeviceConfig); if (XST_SUCCESS != Status) { return XST_FAILURE; } /* Changing the DEVICE mode requires a controller RESET. */ if (XST_SUCCESS != XUsbPs_Reset(InstancePtr)) { return XST_FAILURE; } /* Set the Queue Head List address. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPLISTADDR_OFFSET, InstancePtr->DeviceConfig.PhysAligned); /* Set the USB mode register to configure DEVICE mode. * * XUSBPS_MODE_SLOM_MASK note: * Disable Setup Lockout. Setup Lockout is not required as we * will be using the tripwire mechanism when handling setup * packets. */ ModeValue = XUSBPS_MODE_CM_DEVICE_MASK | XUSBPS_MODE_SLOM_MASK; XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_MODE_OFFSET, ModeValue); XUsbPs_SetBits(InstancePtr, XUSBPS_OTGCSR_OFFSET, XUSBPS_OTGSC_OT_MASK); return XST_SUCCESS; }
/** * This function handles a standard device request. * * @param InstancePtr is a pointer to XUsbPs instance of the controller. * @param SetupData is a pointer to the data structure containing the * setup request. * * @return None. * * @note None. * ******************************************************************************/ static void XUsbPs_StdDevReq(XUsbPs *InstancePtr, XUsbPs_SetupData *SetupData) { int Status; int Error = 0; XUsbPs_Local *UsbLocalPtr; int ReplyLen; #ifdef __ICCARM__ #pragma data_alignment = 32 static u8 Reply[XUSBPS_REQ_REPLY_LEN]; #pragma data_alignment = 4 #else static u8 Reply[XUSBPS_REQ_REPLY_LEN] ALIGNMENT_CACHELINE; #endif /* Check that the requested reply length is not bigger than our reply * buffer. This should never happen... */ if (SetupData->wLength > XUSBPS_REQ_REPLY_LEN) { return; } UsbLocalPtr = (XUsbPs_Local *) InstancePtr->UserDataPtr; #ifdef CH9_DEBUG printf("std dev req %d\n", SetupData->bRequest); #endif switch (SetupData->bRequest) { case XUSBPS_REQ_GET_STATUS: switch(SetupData->bmRequestType & XUSBPS_STATUS_MASK) { case XUSBPS_STATUS_DEVICE: /* It seems we do not have to worry about zeroing out the rest * of the reply buffer even though we are only using the first * two bytes. */ *((u16 *) &Reply[0]) = 0x0100; /* Self powered */ break; case XUSBPS_STATUS_INTERFACE: *((u16 *) &Reply[0]) = 0x0; break; case XUSBPS_STATUS_ENDPOINT: { u32 Status; int EpNum = SetupData->wIndex; Status = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPCRn_OFFSET(EpNum & 0xF)); if(EpNum & 0x80) { /* In EP */ if(Status & XUSBPS_EPCR_TXS_MASK) { *((u16 *) &Reply[0]) = 0x0100; }else { *((u16 *) &Reply[0]) = 0x0000; } } else { /* Out EP */ if(Status & XUSBPS_EPCR_RXS_MASK) { *((u16 *) &Reply[0]) = 0x0100; }else { *((u16 *) &Reply[0]) = 0x0000; } } break; } default: ; #ifdef CH9_DEBUG printf("unknown request for status %x\n", SetupData->bmRequestType); #endif } XUsbPs_EpBufferSend(InstancePtr, 0, Reply, SetupData->wLength); break; case XUSBPS_REQ_SET_ADDRESS: /* With bit 24 set the address value is held in a shadow * register until the status phase is acked. At which point it * address value is written into the address register. */ XUsbPs_SetDeviceAddress(InstancePtr, SetupData->wValue); #ifdef CH9_DEBUG printf("Set address %d\n", SetupData->wValue); #endif /* There is no data phase so ack the transaction by sending a * zero length packet. */ XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0); break; case XUSBPS_REQ_GET_INTERFACE: #ifdef CH9_DEBUG printf("Get interface %d/%d/%d\n", SetupData->wIndex, SetupData->wLength, InstancePtr->CurrentAltSetting); #endif Response = (u8)InstancePtr->CurrentAltSetting; /* Ack the host */ XUsbPs_EpBufferSend(InstancePtr, 0, &Response, 1); break; case XUSBPS_REQ_GET_DESCRIPTOR: #ifdef CH9_DEBUG printf("Get desc %x/%d\n", (SetupData->wValue >> 8) & 0xff, SetupData->wLength); #endif /* Get descriptor type. */ switch ((SetupData->wValue >> 8) & 0xff) { case XUSBPS_TYPE_DEVICE_DESC: case XUSBPS_TYPE_DEVICE_QUALIFIER: /* Set up the reply buffer with the device descriptor * data. */ ReplyLen = XUsbPs_Ch9SetupDevDescReply( Reply, XUSBPS_REQ_REPLY_LEN); ReplyLen = ReplyLen > SetupData->wLength ? SetupData->wLength : ReplyLen; if(((SetupData->wValue >> 8) & 0xff) == XUSBPS_TYPE_DEVICE_QUALIFIER) { Reply[0] = (u8)ReplyLen; Reply[1] = (u8)0x6; Reply[2] = (u8)0x0; Reply[3] = (u8)0x2; Reply[4] = (u8)0xFF; Reply[5] = (u8)0x00; Reply[6] = (u8)0x0; Reply[7] = (u8)0x10; Reply[8] = (u8)0; Reply[9] = (u8)0x0; } Status = XUsbPs_EpBufferSend(InstancePtr, 0, Reply, ReplyLen); if (XST_SUCCESS != Status) { /* Failure case needs to be handled */ for (;;); } break; case XUSBPS_TYPE_CONFIG_DESC: /* Set up the reply buffer with the configuration * descriptor data. */ ReplyLen = XUsbPs_Ch9SetupCfgDescReply( Reply, XUSBPS_REQ_REPLY_LEN); #ifdef CH9_DEBUG printf("get config %d/%d\n", ReplyLen, SetupData->wLength); #endif ReplyLen = ReplyLen > SetupData->wLength ? SetupData->wLength : ReplyLen; Status = XUsbPs_EpBufferSend(InstancePtr, 0, Reply, ReplyLen); if (XST_SUCCESS != Status) { /* Failure case needs to be handled */ for (;;); } break; case XUSBPS_TYPE_STRING_DESC: /* Set up the reply buffer with the string descriptor * data. */ ReplyLen = XUsbPs_Ch9SetupStrDescReply( Reply, XUSBPS_REQ_REPLY_LEN, SetupData->wValue & 0xFF); ReplyLen = ReplyLen > SetupData->wLength ? SetupData->wLength : ReplyLen; Status = XUsbPs_EpBufferSend(InstancePtr, 0, Reply, ReplyLen); if (XST_SUCCESS != Status) { /* Failure case needs to be handled */ for (;;); } break; #ifdef MOUSE_SIMULATION case XUSBPS_TYPE_HID_DESC: /* Set up the reply buffer with the HID descriptor * data. */ ReplyLen = XUsbPs_Ch9SetupHidDescReply( Reply, XUSBPS_REQ_REPLY_LEN); ReplyLen = ReplyLen > SetupData->wLength ? SetupData->wLength : ReplyLen; Status = XUsbPs_EpBufferSend(InstancePtr, 0, Reply, ReplyLen); if (XST_SUCCESS != Status) { /* Failure case needs to be handled */ for (;;); } break; case XUSBPS_TYPE_REPORT_DESC: /* Set up the reply buffer with the report descriptor * data. */ ReplyLen = XUsbPs_Ch9SetupReportDescReply( Reply, XUSBPS_REQ_REPLY_LEN); #ifdef CH9_DEBUG printf("report desc len %d\n", ReplyLen); #endif ReplyLen = ReplyLen > SetupData->wLength ? SetupData->wLength : ReplyLen; Status = XUsbPs_EpBufferSend(InstancePtr, 0, Reply, ReplyLen); if (XST_SUCCESS != Status) { /* Failure case needs to be handled */ for (;;); } break; #endif /* MOUSE_SIMULATION */ default: Error = 1; break; } break; case XUSBPS_REQ_SET_CONFIGURATION: /* * Only allow configuration index 1 as this is the only one we * have. */ if ((SetupData->wValue & 0xff) != 1) { Error = 1; break; } UsbLocalPtr->CurrentConfig = SetupData->wValue & 0xff; /* Call the application specific configuration function to * apply the configuration with the given configuration index. */ XUsbPs_SetConfiguration(InstancePtr, UsbLocalPtr->CurrentConfig); /* There is no data phase so ack the transaction by sending a * zero length packet. */ XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0); break; case XUSBPS_REQ_GET_CONFIGURATION: Response = (u8)InstancePtr->CurrentAltSetting; XUsbPs_EpBufferSend(InstancePtr, 0, &Response, 1); break; case XUSBPS_REQ_CLEAR_FEATURE: switch(SetupData->bmRequestType & XUSBPS_STATUS_MASK) { case XUSBPS_STATUS_ENDPOINT: if(SetupData->wValue == XUSBPS_ENDPOINT_HALT) { int EpNum = SetupData->wIndex; if(EpNum & 0x80) { /* In ep */ XUsbPs_ClrBits(InstancePtr, XUSBPS_EPCRn_OFFSET(EpNum & 0xF), XUSBPS_EPCR_TXS_MASK); }else { /* Out ep */ XUsbPs_ClrBits(InstancePtr, XUSBPS_EPCRn_OFFSET(EpNum), XUSBPS_EPCR_RXS_MASK); } } /* Ack the host ? */ XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0); break; default: Error = 1; break; } break; case XUSBPS_REQ_SET_FEATURE: switch(SetupData->bmRequestType & XUSBPS_STATUS_MASK) { case XUSBPS_STATUS_ENDPOINT: if(SetupData->wValue == XUSBPS_ENDPOINT_HALT) { int EpNum = SetupData->wIndex; if(EpNum & 0x80) { /* In ep */ XUsbPs_SetBits(InstancePtr, XUSBPS_EPCRn_OFFSET(EpNum & 0xF), XUSBPS_EPCR_TXS_MASK); }else { /* Out ep */ XUsbPs_SetBits(InstancePtr, XUSBPS_EPCRn_OFFSET(EpNum), XUSBPS_EPCR_RXS_MASK); } } /* Ack the host ? */ XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0); break; case XUSBPS_STATUS_DEVICE: if (SetupData->wValue == XUSBPS_TEST_MODE) { int TestSel = (SetupData->wIndex >> 8) & 0xFF; /* Ack the host, the transition must happen after status stage and < 3ms */ XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0); usleep(1000); switch (TestSel) { case XUSBPS_TEST_J: case XUSBPS_TEST_K: case XUSBPS_TEST_SE0_NAK: case XUSBPS_TEST_PACKET: case XUSBPS_TEST_FORCE_ENABLE: XUsbPs_SetBits(InstancePtr, \ XUSBPS_PORTSCR1_OFFSET, \ TestSel << 16); break; default: /* Unsupported test selector */ break; } break; } default: Error = 1; break; } break; /* For set interface, check the alt setting host wants */ case XUSBPS_REQ_SET_INTERFACE: #ifdef CH9_DEBUG printf("set interface %d/%d\n", SetupData->wValue, SetupData->wIndex); #endif /* Not supported */ /* XUsbPs_SetInterface(InstancePtr, SetupData->wValue, SetupData->wIndex); */ /* Ack the host after device finishes the operation */ Error = XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0); if(Error) { #ifdef CH9_DEBUG printf("EpBufferSend failed %d\n", Error); #endif } break; default: Error = 1; break; }