CyU3PReturnStatus_t CyFxMscErrorRecovery ( void) { CyU3PReturnStatus_t status = CY_U3P_SUCCESS; /* Abort and reset the IN endpoint. */ if (glMscInEp != 0) { CyU3PDmaChannelReset (&glMscInCh); CyU3PUsbHostEpAbort (glMscInEp); status = CyFxSendSetupRqt (0x02, CY_U3P_USB_SC_CLEAR_FEATURE, 0, glMscInEp, 0, glEp0Buffer); if (status == CY_U3P_SUCCESS) { status = CyU3PUsbHostEpReset (glMscInEp); } } /* Abort and reset the OUT endpoint. */ if ((status == CY_U3P_SUCCESS) && (glMscOutEp != 0)) { CyU3PDmaChannelReset (&glMscOutCh); CyU3PUsbHostEpAbort (glMscOutEp); status = CyFxSendSetupRqt (0x02, CY_U3P_USB_SC_CLEAR_FEATURE, 0, glMscOutEp, 0, glEp0Buffer); if (status == CY_U3P_SUCCESS) { status = CyU3PUsbHostEpReset (glMscOutEp); } } return status; }
/* Initalizes the mouse driver. */ CyU3PReturnStatus_t CyFxMouseDriverInit () { uint16_t length, size, interval; CyU3PReturnStatus_t status; CyU3PUsbHostEpConfig_t epCfg; CyU3PDmaChannelConfig_t dmaCfg; /* Read first four bytes of configuration descriptor to determine * the total length. */ status = CyFxSendSetupRqt (0x80, CY_U3P_USB_SC_GET_DESCRIPTOR, (CY_U3P_USB_CONFIG_DESCR << 8), 0, 4, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Identify the length of the data received. */ length = CY_U3P_MAKEWORD(glEp0Buffer[3], glEp0Buffer[2]); if (length > CY_FX_HOST_EP0_BUFFER_SIZE) { goto enum_error; } /* Read the full configuration descriptor. */ status = CyFxSendSetupRqt (0x80, CY_U3P_USB_SC_GET_DESCRIPTOR, (CY_U3P_USB_CONFIG_DESCR << 8), 0, length, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Save the required information. */ glHostMouseEp = glEp0Buffer[29]; size = CY_U3P_MAKEWORD(glEp0Buffer[32], glEp0Buffer[31]); interval = glEp0Buffer[33]; /* Set the new configuration. */ status = CyFxSendSetupRqt (0x00, CY_U3P_USB_SC_SET_CONFIGURATION, 1, 0, 0, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Set the report mode to idle so that report is sent only * when there is active data. */ status = CyFxSendSetupRqt (0x21, 0x0A, 0, 0, 0, glEp0Buffer); #if 0 /* It does not matter even if the request gets stalled. */ if (status != CY_U3P_SUCCESS) { goto enum_error; } #endif /* Initialize the HID mouse. */ CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof(epCfg)); epCfg.type = CY_U3P_USB_EP_INTR; epCfg.mult = 1; epCfg.maxPktSize = size; interval = (1 << (interval - 1)) / 8; if (interval > 255) { interval = 255; } epCfg.pollingRate = interval; /* Since DMA buffer sizes can only be multiple of 16 bytes and * also since this is an interrupt endpoint where the max data * packet size is same as the maxPktSize field, the fullPktSize * has to be a multiple of 16 bytes. */ size = ((size + 0x0F) & ~0x0F); epCfg.fullPktSize = size; /* Since the IN token has to be sent out continously, it * is easier to enable the stream mode. Otherwise we will * have to maintain the timing. */ epCfg.isStreamMode = CyTrue; status = CyU3PUsbHostEpAdd (glHostMouseEp, &epCfg); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Create a DMA channel for this EP. */ CyU3PMemSet ((uint8_t *)&dmaCfg, 0, sizeof(dmaCfg)); dmaCfg.size = size; dmaCfg.count = CY_FX_HOST_DMA_BUF_COUNT; dmaCfg.prodSckId = (CyU3PDmaSocketId_t)(CY_U3P_UIB_SOCKET_PROD_0 + (0x0F & glHostMouseEp)); dmaCfg.consSckId = CY_U3P_CPU_SOCKET_CONS; dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE; dmaCfg.notification = CY_U3P_DMA_CB_PROD_EVENT; dmaCfg.cb = CyFxMouseDmaCb; dmaCfg.prodHeader = 0; dmaCfg.prodFooter = 0; dmaCfg.consHeader = 0; dmaCfg.prodAvailCount = 0; status = CyU3PDmaChannelCreate (&glHostMouseCh, CY_U3P_DMA_TYPE_MANUAL_IN, &dmaCfg); if (status != CY_U3P_SUCCESS) { goto app_error; } /* Enable EP transfer. In stream mode, the transfer size should be zero. */ status = CyU3PUsbHostEpSetXfer (glHostMouseEp, CY_U3P_USB_HOST_EPXFER_NORMAL, 0); if (status != CY_U3P_SUCCESS) { goto app_error; } /* Set for infinite transfer. */ status = CyU3PDmaChannelSetXfer (&glHostMouseCh, 0); if (status != CY_U3P_SUCCESS) { goto app_error; } CyU3PDebugPrint (4, "USB HID Mouse driver initialized successfully.\r\n"); return CY_U3P_SUCCESS; app_error: CyU3PDmaChannelDestroy (&glHostMouseCh); if (glHostMouseEp != 0) { CyU3PUsbHostEpRemove (glHostMouseEp); glHostMouseEp = 0; } enum_error: return CY_U3P_ERROR_FAILURE; }
/* This function initializes the mouse driver application. */ void CyFxApplnStart () { uint16_t length; CyU3PReturnStatus_t status; CyU3PUsbHostEpConfig_t epCfg; /* Add EP0 to the scheduler. */ CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof(epCfg)); epCfg.type = CY_U3P_USB_EP_CONTROL; epCfg.mult = 1; /* Start off with 8 byte EP0 packet size. */ epCfg.maxPktSize = 8; epCfg.pollingRate = 0; epCfg.fullPktSize = 8; epCfg.isStreamMode = CyFalse; status = CyU3PUsbHostEpAdd (0, &epCfg); if (status != CY_U3P_SUCCESS) { goto enum_error; } CyU3PThreadSleep (100); /* Get the device descriptor. */ status = CyFxSendSetupRqt (0x80, CY_U3P_USB_SC_GET_DESCRIPTOR, (CY_U3P_USB_DEVICE_DESCR << 8), 0, 8, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Identify the EP0 packet size and update the scheduler. */ if (glEp0Buffer[7] != 8) { CyU3PUsbHostEpRemove (0); epCfg.maxPktSize = glEp0Buffer[7]; epCfg.fullPktSize = glEp0Buffer[7]; status = CyU3PUsbHostEpAdd (0, &epCfg); if (status != CY_U3P_SUCCESS) { goto enum_error; } } /* Read the full device descriptor. */ status = CyFxSendSetupRqt (0x80, CY_U3P_USB_SC_GET_DESCRIPTOR, (CY_U3P_USB_DEVICE_DESCR << 8), 0, 18, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Set the peripheral device address. */ status = CyFxSendSetupRqt (0x00, CY_U3P_USB_SC_SET_ADDRESS, CY_FX_HOST_PERIPHERAL_ADDRESS, 0, 0, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } status = CyU3PUsbHostSetDeviceAddress (CY_FX_HOST_PERIPHERAL_ADDRESS); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Read first four bytes of configuration descriptor to determine * the total length. */ status = CyFxSendSetupRqt (0x80, CY_U3P_USB_SC_GET_DESCRIPTOR, (CY_U3P_USB_CONFIG_DESCR << 8), 0, 4, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Identify the length of the data received. */ length = CY_U3P_MAKEWORD(glEp0Buffer[3], glEp0Buffer[2]); if (length > CY_FX_HOST_EP0_BUFFER_SIZE) { goto enum_error; } /* Read the full configuration descriptor. */ status = CyFxSendSetupRqt (0x80, CY_U3P_USB_SC_GET_DESCRIPTOR, (CY_U3P_USB_CONFIG_DESCR << 8), 0, length, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Identify if this is an HID mouse or MSC device that can be * supported. If the device cannot be supported, just disable * the port and wait for a new device to be attached. We support * only single interface with interface class = HID(0x03), * interface sub class = Boot (0x01) * and interface protocol = Mouse (0x02). * or single interface with interface class = MSC(0x08), * interface sub class 0x06 and interface protocol BOT (0x50). */ if ((glEp0Buffer[5] == 1) && (glEp0Buffer[14] == 0x03) && (glEp0Buffer[15] == 0x01) && (glEp0Buffer[16] == 0x02) && (glEp0Buffer[28] == CY_U3P_USB_ENDPNT_DESCR)) { status = CyFxMouseDriverInit (); if (status == CY_U3P_SUCCESS) { glIsApplnActive = CyTrue; glHostOwner = CY_FX_HOST_OWNER_MOUSE_DRIVER; return; } } else if ((glEp0Buffer[5] == 1) && (glEp0Buffer[14] == 0x08) && (glEp0Buffer[15] == 0x06) && (glEp0Buffer[16] == 0x50)) { status = CyFxMscDriverInit (); if (status == CY_U3P_SUCCESS) { glIsApplnActive = CyTrue; glHostOwner = CY_FX_HOST_OWNER_MSC_DRIVER; return; } } else { /* Do nothing here. Fall-through to disable the USB port. * We do not support this device. */ status = CY_U3P_ERROR_NOT_SUPPORTED; } enum_error: /* Remove EP0. and disable the port. */ glHostOwner = CY_FX_HOST_OWNER_NONE; CyU3PUsbHostEpRemove (0); CyU3PUsbHostPortDisable (); CyU3PDebugPrint (4, "Application start failed with error: %d.\r\n", status); }
CyU3PReturnStatus_t CyFxMscDriverInit () { uint8_t maxLun = 0, i, retry; uint16_t length, size, offset; CyU3PReturnStatus_t status; CyU3PUsbHostEpConfig_t epCfg; CyU3PDmaChannelConfig_t dmaCfg; /* Read first four bytes of configuration descriptor to determine * the total length. */ status = CyFxSendSetupRqt (0x80, CY_U3P_USB_SC_GET_DESCRIPTOR, (CY_U3P_USB_CONFIG_DESCR << 8), 0, 4, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Identify the length of the data received. */ length = CY_U3P_MAKEWORD(glEp0Buffer[3], glEp0Buffer[2]); if (length > CY_FX_HOST_EP0_BUFFER_SIZE) { goto enum_error; } /* Read the full configuration descriptor. */ status = CyFxSendSetupRqt (0x80, CY_U3P_USB_SC_GET_DESCRIPTOR, (CY_U3P_USB_CONFIG_DESCR << 8), 0, length, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Identify the EP characteristics. */ offset = 0; while (offset < length) { if (glEp0Buffer[offset + 1] == CY_U3P_USB_ENDPNT_DESCR) { if (glEp0Buffer[offset + 3] != CY_U3P_USB_EP_BULK) { goto enum_error; } /* Retreive the information. */ glMscEpSize = CY_U3P_MAKEWORD(glEp0Buffer[offset + 5], glEp0Buffer[offset + 4]); if (glEp0Buffer[offset + 2] & 0x80) { glMscInEp = glEp0Buffer[offset + 2]; } else { glMscOutEp = glEp0Buffer[offset + 2]; } } /* Advance to next descriptor. */ offset += glEp0Buffer[offset]; } /* Set the new configuration. */ status = CyFxSendSetupRqt (0x00, CY_U3P_USB_SC_SET_CONFIGURATION, 1, 0, 0, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Identify the number of LUNs available. * We will use only the first available LUN. */ status = CyFxSendSetupRqt (0xA1, CY_FX_MSC_GET_MAX_LUN, 0, 0, 1, glEp0Buffer); if (status != CY_U3P_SUCCESS) { goto enum_error; } maxLun = glEp0Buffer[0]; /* Add the IN endpoint. */ CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof(epCfg)); epCfg.type = CY_U3P_USB_EP_BULK; epCfg.mult = 1; epCfg.maxPktSize = glMscEpSize; epCfg.pollingRate = 0; /* Since DMA buffer sizes can only be multiple of 16 bytes and * also since this is an interrupt endpoint where the max data * packet size is same as the maxPktSize field, the fullPktSize * has to be a multiple of 16 bytes. */ size = ((glMscEpSize + 0x0F) & ~0x0F); epCfg.fullPktSize = size; epCfg.isStreamMode = CyFalse; status = CyU3PUsbHostEpAdd (glMscInEp, &epCfg); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Add the OUT EP. */ status = CyU3PUsbHostEpAdd (glMscOutEp, &epCfg); if (status != CY_U3P_SUCCESS) { goto enum_error; } /* Create a DMA channel for IN EP. */ CyU3PMemSet ((uint8_t *)&dmaCfg, 0, sizeof(dmaCfg)); dmaCfg.size = glMscEpSize; dmaCfg.count = 0; dmaCfg.prodSckId = (CyU3PDmaSocketId_t)(CY_U3P_UIB_SOCKET_PROD_0 + (0x0F & glMscInEp)); dmaCfg.consSckId = CY_U3P_CPU_SOCKET_CONS; dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE; dmaCfg.notification = 0; dmaCfg.cb = NULL; dmaCfg.prodHeader = 0; dmaCfg.prodFooter = 0; dmaCfg.consHeader = 0; dmaCfg.prodAvailCount = 0; status = CyU3PDmaChannelCreate (&glMscInCh, CY_U3P_DMA_TYPE_MANUAL_IN, &dmaCfg); if (status != CY_U3P_SUCCESS) { goto app_error; } /* Create a DMA channel for OUT EP. */ dmaCfg.prodSckId = CY_U3P_CPU_SOCKET_PROD; dmaCfg.consSckId = (CyU3PDmaSocketId_t)(CY_U3P_UIB_SOCKET_CONS_0 + (0x0F & glMscOutEp)); status = CyU3PDmaChannelCreate (&glMscOutCh, CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaCfg); if (status != CY_U3P_SUCCESS) { goto app_error; } for (retry = 0; retry < CY_FX_MSC_MAX_RETRY; retry++) { /* Give some time for the device to initialize. */ CyU3PThreadSleep (1000); for (i = 0; i <= maxLun; i++) { /* Check if the unit is ready. */ status = CyFxMscTestUnitReady (maxLun); if (status == CY_U3P_SUCCESS) { glMscTestLun = i; break; } } if (status == CY_U3P_SUCCESS) { break; } } if (status != CY_U3P_SUCCESS) { glMscTestLun = 0; goto app_error; } /* Read the device capacity. */ status = CyFxMscReadCapacity (glMscTestLun); if (status != CY_U3P_SUCCESS) { goto app_error; } glMscIsActive = CyTrue; return status; app_error: CyU3PDmaChannelDestroy (&glMscInCh); if (glMscInEp != 0) { CyU3PUsbHostEpRemove (glMscInEp); glMscInEp = 0; } CyU3PDmaChannelDestroy (&glMscOutCh); if (glMscOutEp != 0) { CyU3PUsbHostEpRemove (glMscOutEp); glMscOutEp = 0; } glMscEpSize = 0; glMscSectorSize = 0; glMscCapacity = 0; glMscTestLun = 0; glMscTestSector = 0; glTimerCount = 0; enum_error: return CY_U3P_ERROR_FAILURE; }