From f7cd9b461ca33845339f4a11f49bdc142696827a Mon Sep 17 00:00:00 2001 From: Dominik Sliwa Date: Tue, 28 Jun 2016 09:51:29 +0200 Subject: Apalis_TK1_K20: SPI Communication, ADC, TSC, GPIO Support for Communication between TK1 SoC and K20 MCU This patch includes ADC, TSC and GPIO functionality. Signed-off-by: Dominik Sliwa --- .cproject | 241 ++-- .gitignore | 2 + .settings/language.settings.xml | 4 +- CMSIS/MK20D10_features.h | 2 +- MK20DN512xxx10_flash.ld | 10 +- board/board.c | 5 +- board/board.h | 13 + board/clock_config.c | 56 +- board/clock_config.h | 2 +- board/pin_mux.c | 128 ++- board/usb_host_config.h | 204 ++++ drivers/fsl_adc16.c | 2 +- k20_tester_Debug_Segger.launch | 42 +- source/adc_task.c | 343 ++++++ source/adc_task.h | 19 + source/com_task.c | 205 ++++ source/com_task.h | 130 +++ source/gpio_ext.c | 141 +++ source/gpio_ext.h | 73 ++ source/main.c | 83 +- usb_1.1.0/device/usb_device.h | 508 +++++++++ usb_1.1.0/device/usb_device_dci.c | 1109 ++++++++++++++++++ usb_1.1.0/device/usb_device_dci.h | 150 +++ usb_1.1.0/device/usb_device_khci.c | 1355 ++++++++++++++++++++++ usb_1.1.0/device/usb_device_khci.h | 243 ++++ usb_1.1.0/host/class/usb_host_audio.c | 1051 +++++++++++++++++ usb_1.1.0/host/class/usb_host_audio.h | 549 +++++++++ usb_1.1.0/host/class/usb_host_cdc.c | 1200 ++++++++++++++++++++ usb_1.1.0/host/class/usb_host_cdc.h | 518 +++++++++ usb_1.1.0/host/class/usb_host_hid.c | 804 +++++++++++++ usb_1.1.0/host/class/usb_host_hid.h | 411 +++++++ usb_1.1.0/host/class/usb_host_hub.c | 612 ++++++++++ usb_1.1.0/host/class/usb_host_hub.h | 390 +++++++ usb_1.1.0/host/class/usb_host_hub_app.c | 1106 ++++++++++++++++++ usb_1.1.0/host/class/usb_host_hub_app.h | 103 ++ usb_1.1.0/host/class/usb_host_msd.c | 1155 +++++++++++++++++++ usb_1.1.0/host/class/usb_host_msd.h | 872 ++++++++++++++ usb_1.1.0/host/class/usb_host_msd_ufi.c | 473 ++++++++ usb_1.1.0/host/class/usb_host_phdc.c | 1272 +++++++++++++++++++++ usb_1.1.0/host/class/usb_host_phdc.h | 329 ++++++ usb_1.1.0/host/class/usb_host_printer.c | 775 +++++++++++++ usb_1.1.0/host/class/usb_host_printer.h | 301 +++++ usb_1.1.0/host/usb_host.h | 569 ++++++++++ usb_1.1.0/host/usb_host_devices.c | 1345 ++++++++++++++++++++++ usb_1.1.0/host/usb_host_devices.h | 178 +++ usb_1.1.0/host/usb_host_framework.c | 377 ++++++ usb_1.1.0/host/usb_host_framework.h | 107 ++ usb_1.1.0/host/usb_host_hci.c | 754 ++++++++++++ usb_1.1.0/host/usb_host_hci.h | 118 ++ usb_1.1.0/host/usb_host_khci.c | 1886 +++++++++++++++++++++++++++++++ usb_1.1.0/host/usb_host_khci.h | 328 ++++++ usb_1.1.0/include/usb.h | 119 ++ usb_1.1.0/include/usb_khci.h | 62 + usb_1.1.0/include/usb_misc.h | 238 ++++ usb_1.1.0/include/usb_spec.h | 254 +++++ usb_1.1.0/osa/usb_osa.h | 578 ++++++++++ usb_1.1.0/osa/usb_osa_bm.c | 538 +++++++++ usb_1.1.0/osa/usb_osa_bm.h | 57 + usb_1.1.0/osa/usb_osa_freertos.c | 490 ++++++++ usb_1.1.0/osa/usb_osa_freertos.h | 111 ++ 60 files changed, 24907 insertions(+), 193 deletions(-) create mode 100644 .gitignore create mode 100644 board/usb_host_config.h create mode 100644 source/adc_task.c create mode 100644 source/adc_task.h create mode 100644 source/com_task.c create mode 100644 source/com_task.h create mode 100644 source/gpio_ext.c create mode 100644 source/gpio_ext.h create mode 100644 usb_1.1.0/device/usb_device.h create mode 100644 usb_1.1.0/device/usb_device_dci.c create mode 100644 usb_1.1.0/device/usb_device_dci.h create mode 100644 usb_1.1.0/device/usb_device_khci.c create mode 100644 usb_1.1.0/device/usb_device_khci.h create mode 100644 usb_1.1.0/host/class/usb_host_audio.c create mode 100644 usb_1.1.0/host/class/usb_host_audio.h create mode 100644 usb_1.1.0/host/class/usb_host_cdc.c create mode 100644 usb_1.1.0/host/class/usb_host_cdc.h create mode 100644 usb_1.1.0/host/class/usb_host_hid.c create mode 100644 usb_1.1.0/host/class/usb_host_hid.h create mode 100644 usb_1.1.0/host/class/usb_host_hub.c create mode 100644 usb_1.1.0/host/class/usb_host_hub.h create mode 100644 usb_1.1.0/host/class/usb_host_hub_app.c create mode 100644 usb_1.1.0/host/class/usb_host_hub_app.h create mode 100644 usb_1.1.0/host/class/usb_host_msd.c create mode 100644 usb_1.1.0/host/class/usb_host_msd.h create mode 100644 usb_1.1.0/host/class/usb_host_msd_ufi.c create mode 100644 usb_1.1.0/host/class/usb_host_phdc.c create mode 100644 usb_1.1.0/host/class/usb_host_phdc.h create mode 100644 usb_1.1.0/host/class/usb_host_printer.c create mode 100644 usb_1.1.0/host/class/usb_host_printer.h create mode 100644 usb_1.1.0/host/usb_host.h create mode 100644 usb_1.1.0/host/usb_host_devices.c create mode 100644 usb_1.1.0/host/usb_host_devices.h create mode 100644 usb_1.1.0/host/usb_host_framework.c create mode 100644 usb_1.1.0/host/usb_host_framework.h create mode 100644 usb_1.1.0/host/usb_host_hci.c create mode 100644 usb_1.1.0/host/usb_host_hci.h create mode 100644 usb_1.1.0/host/usb_host_khci.c create mode 100644 usb_1.1.0/host/usb_host_khci.h create mode 100644 usb_1.1.0/include/usb.h create mode 100644 usb_1.1.0/include/usb_khci.h create mode 100644 usb_1.1.0/include/usb_misc.h create mode 100644 usb_1.1.0/include/usb_spec.h create mode 100644 usb_1.1.0/osa/usb_osa.h create mode 100644 usb_1.1.0/osa/usb_osa_bm.c create mode 100644 usb_1.1.0/osa/usb_osa_bm.h create mode 100644 usb_1.1.0/osa/usb_osa_freertos.c create mode 100644 usb_1.1.0/osa/usb_osa_freertos.h diff --git a/.cproject b/.cproject index 769adc3..cb96519 100644 --- a/.cproject +++ b/.cproject @@ -17,41 +17,48 @@ - - - - - - - - - - - - - - + + @@ -154,42 +158,48 @@ - - - - - - - - - - - - - - + @@ -297,4 +304,6 @@ + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac01e66 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/Debug/ +/Release/ diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index a07f17e..1ba5254 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/CMSIS/MK20D10_features.h b/CMSIS/MK20D10_features.h index 3729f04..d42d831 100644 --- a/CMSIS/MK20D10_features.h +++ b/CMSIS/MK20D10_features.h @@ -127,7 +127,7 @@ /* @brief DRY availability on the SoC. */ #define FSL_FEATURE_SOC_DRY_COUNT (0) /* @brief DSPI availability on the SoC. */ - #define FSL_FEATURE_SOC_DSPI_COUNT (2) + #define FSL_FEATURE_SOC_DSPI_COUNT (3) /* @brief EMVSIM availability on the SoC. */ #define FSL_FEATURE_SOC_EMVSIM_COUNT (0) /* @brief ENC availability on the SoC. */ diff --git a/MK20DN512xxx10_flash.ld b/MK20DN512xxx10_flash.ld index 31b2d0f..782d555 100644 --- a/MK20DN512xxx10_flash.ld +++ b/MK20DN512xxx10_flash.ld @@ -60,7 +60,8 @@ MEMORY { m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400 m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010 - m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x0007FBF0 + m_fw_version (RX) : ORIGIN = 0x00000410, LENGTH = 0x00000004 + m_text (RX) : ORIGIN = 0x00000414, LENGTH = 0x0007FBEC m_data (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000 m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00010000 } @@ -79,10 +80,15 @@ SECTIONS .flash_config : { - . = ALIGN(4); + . = ALIGN(4); KEEP(*(.FlashConfig)) /* Flash Configuration Field (FCF) */ . = ALIGN(4); } > m_flash_config + + .fw_config : + { + KEEP(*(.FwVersion)) /* Firmware version */ + } > m_fw_version /* The program code and other data goes into internal flash */ .text : diff --git a/board/board.c b/board/board.c index c0bbde0..726870b 100644 --- a/board/board.c +++ b/board/board.c @@ -32,11 +32,14 @@ #include #include "board.h" +#include "fsl_debug_console.h" /*! * @brief initialize debug console to enable printf for this demo/example */ void BOARD_InitDebugConsole(void) { - /* The user initialization should be placed here */ + uint32_t uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ; + + DbgConsole_Init(BOARD_DEBUG_UART_BASEADDR, BOARD_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq); } diff --git a/board/board.h b/board/board.h index bd6d36b..00d185d 100644 --- a/board/board.h +++ b/board/board.h @@ -40,6 +40,19 @@ /* The board name */ #define BOARD_NAME "###-not-specified-###" +#define BOARD_USE_UART +#define BOARD_DEBUG_UART_TYPE DEBUG_CONSOLE_DEVICE_TYPE_UART +#define BOARD_DEBUG_UART_BASEADDR (uint32_t) UART3 +#define BOARD_DEBUG_UART_CLKSRC kCLOCK_BusClk +#define BOARD_DEBUG_UART_CLK_FREQ CLOCK_GetBusClkFreq() +#define BOARD_UART_IRQ UART3_RX_TX_IRQn +#define BOARD_UART_IRQ_HANDLER UART3_RX_TX_IRQHandler + +#define BOARD_USES_ADC + +#ifndef BOARD_DEBUG_UART_BAUDRATE +#define BOARD_DEBUG_UART_BAUDRATE 115200 +#endif /******************************************************************************* * API diff --git a/board/clock_config.c b/board/clock_config.c index 41f6eb5..16626ba 100644 --- a/board/clock_config.c +++ b/board/clock_config.c @@ -30,6 +30,11 @@ /* This is a template for clock configuration created by New Kinetis SDK 2.x Project Wizard. Enjoy! */ +#include "fsl_device_registers.h" +#include "fsl_common.h" +#include "fsl_clock.h" +#include "fsl_port.h" +#include "clock_config.h" /******************************************************************************* * Definitions @@ -43,10 +48,51 @@ * Code ******************************************************************************/ -/*! - * @brief configure clock after reset for this demo/example - */ -void BOARD_BootClockRUN(void) { - /* The user configuration should be placed here */ +void BOARD_InitOsc0(void) +{ + const osc_config_t oscConfig = {.freq = BOARD_XTAL0_CLK_HZ, + .capLoad = 0, + .workMode = kOSC_ModeOscLowPower, + .oscerConfig = { + .enableMode = kOSC_ErClkEnable, +#if (defined(FSL_FEATURE_OSC_HAS_EXT_REF_CLOCK_DIVIDER) && FSL_FEATURE_OSC_HAS_EXT_REF_CLOCK_DIVIDER) + .erclkDiv = 0U, +#endif + }}; + + CLOCK_InitOsc0(&oscConfig); + + /* Passing the XTAL0 frequency to clock driver. */ + CLOCK_SetXtal0Freq(BOARD_XTAL0_CLK_HZ); + /* Use RTC_CLKIN input clock directly. */ + //CLOCK_SetXtal32Freq(BOARD_XTAL32K_CLK_HZ); +} + +void BOARD_BootClockRUN(void) +{ + /* + * Core clock: 96MHz + * Bus clock: 48MHz + */ + mcg_pll_config_t pll0Config = { + .enableMode = 0U, .prdiv = 0x3U, .vdiv = 0x18U, + }; + const sim_clock_config_t simConfig = { + .pllFllSel = 1U, /* PLLFLLSEL select PLL. */ + .er32kSrc = 2U, /* ERCLK32K selection, use RTC. */ + .clkdiv1 = 0x01130000U, /* SIM_CLKDIV1. */ + }; + + CLOCK_SetSimSafeDivs(); + BOARD_InitOsc0(); + + CLOCK_CalcPllDiv(BOARD_XTAL0_CLK_HZ, 96000000U, &pll0Config.prdiv, &pll0Config.vdiv); + CLOCK_BootToPeeMode(kMCG_OscselOsc, kMCG_PllClkSelPll0, &pll0Config); + + CLOCK_SetInternalRefClkConfig(kMCG_IrclkEnable, kMCG_IrcSlow, 0); + CLOCK_SetSimConfig(&simConfig); + + SystemCoreClock = 96000000U; } + diff --git a/board/clock_config.h b/board/clock_config.h index e39811f..f9c2406 100644 --- a/board/clock_config.h +++ b/board/clock_config.h @@ -36,7 +36,7 @@ /******************************************************************************* * DEFINITION ******************************************************************************/ - +#define BOARD_XTAL0_CLK_HZ 8000000U /******************************************************************************* * API ******************************************************************************/ diff --git a/board/pin_mux.c b/board/pin_mux.c index be07825..3a538f5 100644 --- a/board/pin_mux.c +++ b/board/pin_mux.c @@ -34,6 +34,8 @@ #include "fsl_common.h" #include "fsl_port.h" #include "fsl_gpio.h" +#include "fsl_debug_console.h" +#include "gpio_ext.h" /******************************************************************************* * Code @@ -43,54 +45,96 @@ */ void BOARD_InitPins(void) { - gpio_pin_config_t gpio_out_config = { - kGPIO_DigitalOutput, 0, - }; + unsigned int i; + gpio_pin_config_t gpio_out_config = { + kGPIO_DigitalOutput, 0, + }; + gpio_pin_config_t gpio_out_hi_config = { + kGPIO_DigitalOutput, 1, + }; + gpio_pin_config_t gpio_in_config = { + kGPIO_DigitalInput, + }; + port_pin_config_t od_config; - CLOCK_EnableClock(kCLOCK_PortA); - CLOCK_EnableClock(kCLOCK_PortB); - CLOCK_EnableClock(kCLOCK_PortC); - CLOCK_EnableClock(kCLOCK_PortD); - CLOCK_EnableClock(kCLOCK_PortE); + CLOCK_EnableClock(kCLOCK_PortA); + CLOCK_EnableClock(kCLOCK_PortB); + CLOCK_EnableClock(kCLOCK_PortC); + CLOCK_EnableClock(kCLOCK_PortD); + CLOCK_EnableClock(kCLOCK_PortE); - /* Osc pins */ - PORT_SetPinMux(PORTA, 18UL, kPORT_PinDisabledOrAnalog); - PORT_SetPinMux(PORTA, 19UL, kPORT_PinDisabledOrAnalog); + /* Osc pins */ + PORT_SetPinMux(PORTA, 18UL, kPORT_PinDisabledOrAnalog); + PORT_SetPinMux(PORTA, 19UL, kPORT_PinDisabledOrAnalog); - /* CAN0 pinmux config */ - PORT_SetPinMux(PORTA, 12u, kPORT_MuxAlt2); /* CAN0 TX */ - PORT_SetPinMux(PORTA, 13u, kPORT_MuxAlt2); /* CAN0 RX */ + /* CAN0 pinmux config */ + PORT_SetPinMux(PORTA, 12u, kPORT_MuxAlt2); /* CAN0 TX */ + PORT_SetPinMux(PORTA, 13u, kPORT_MuxAlt2); /* CAN0 RX */ - /* CAN1 pinmux config */ - PORT_SetPinMux(PORTC, 17u, kPORT_MuxAlt2); /* CAN1 TX */ - PORT_SetPinMux(PORTC, 16u, kPORT_MuxAlt2); /* CAN1 RX */ + /* CAN1 pinmux config */ + PORT_SetPinMux(PORTC, 17u, kPORT_MuxAlt2); /* CAN1 TX */ + PORT_SetPinMux(PORTC, 16u, kPORT_MuxAlt2); /* CAN1 RX */ - /* Debug UART3 pinmux config */ - PORT_SetPinMux(PORTB, 11u, kPORT_MuxAlt3); /* UART3 TX */ - PORT_SetPinMux(PORTB, 10u, kPORT_MuxAlt3); /* UART3 RX */ +#ifdef SDK_DEBUGCONSOLE + /* Debug UART3 pinmux config */ + PORT_SetPinMux(PORTB, 11u, kPORT_MuxAlt3); /* UART3 TX */ + PORT_SetPinMux(PORTB, 10u, kPORT_MuxAlt3); /* UART3 RX */ +#endif - /* Resistive Touch panel pinmux config */ - PORT_SetPinMux(PORTE, 6u, kPORT_MuxAsGpio); - GPIO_PinInit(GPIOE, 6u, &gpio_out_config); - GPIO_SetPinsOutput(GPIOE, 1u << 6); /* Force X+*/ - PORT_SetPinMux(PORTB, 9u, kPORT_MuxAsGpio); - GPIO_PinInit(GPIOB, 9u, &gpio_out_config); - GPIO_ClearPinsOutput(GPIOB, 1u << 9); /* Force X-*/ - PORT_SetPinMux(PORTC, 5u, kPORT_MuxAsGpio); - GPIO_PinInit(GPIOC, 5u, &gpio_out_config); - GPIO_SetPinsOutput(GPIOC, 1u << 5); /* Force Y+*/ - PORT_SetPinMux(PORTC, 13u, kPORT_MuxAsGpio); - GPIO_PinInit(GPIOC, 13u, &gpio_out_config); - GPIO_ClearPinsOutput(GPIOC, 1u << 13); /* Force Y-*/ - PORT_SetPinMux(PORTB, 6UL, kPORT_PinDisabledOrAnalog); /* Sense X+ */ - PORT_SetPinMux(PORTB, 7UL, kPORT_PinDisabledOrAnalog); /* Sense X- */ - PORT_SetPinMux(PORTC, 8UL, kPORT_PinDisabledOrAnalog); /* Sense Y+ */ - PORT_SetPinMux(PORTC, 9UL, kPORT_PinDisabledOrAnalog); /* Sense Y- */ +#ifdef BOARD_USES_ADC + /* Resistive Touch panel pinmux config */ + PORT_SetPinMux(PORTE, 6u, kPORT_MuxAsGpio); + GPIO_PinInit(GPIOE, 6u, &gpio_out_hi_config); /* Force X+*/ + PORT_SetPinMux(PORTB, 9u, kPORT_MuxAsGpio); + GPIO_PinInit(GPIOB, 9u, &gpio_out_config); /* Force X-*/ + PORT_SetPinMux(PORTC, 5u, kPORT_MuxAsGpio); + GPIO_PinInit(GPIOC, 5u, &gpio_out_hi_config); /* Force Y+*/ + PORT_SetPinMux(PORTC, 13u, kPORT_MuxAsGpio); + GPIO_PinInit(GPIOC, 13u, &gpio_out_config); /* Force Y-*/ + PORT_SetPinMux(PORTB, 6UL, kPORT_PinDisabledOrAnalog); /* Sense X+ */ + GPIO_PinInit(GPIOB, 6u, &gpio_in_config); + PORT_SetPinMux(PORTB, 7UL, kPORT_PinDisabledOrAnalog); /* Sense X- */ + GPIO_PinInit(GPIOB, 7u, &gpio_in_config); + PORT_SetPinMux(PORTC, 8UL, kPORT_PinDisabledOrAnalog); /* Sense Y+ */ + GPIO_PinInit(GPIOC, 8u, &gpio_in_config); + PORT_SetPinMux(PORTC, 9UL, kPORT_PinDisabledOrAnalog); /* Sense Y- */ + GPIO_PinInit(GPIOC, 9u, &gpio_in_config); - /* SPI2 pinmux config */ - PORT_SetPinMux(PORTB, 21u, kPORT_MuxAlt2); /* SPI2_SCK */ - PORT_SetPinMux(PORTB, 22u, kPORT_MuxAlt2); /* SPI2_SOUT */ - PORT_SetPinMux(PORTB, 23u, kPORT_MuxAlt2); /* SPI2_SIN */ - PORT_SetPinMux(PORTB, 20u, kPORT_MuxAsGpio); /* SPI2_SS */ + /* Apalis ADC pinmux config */ + PORT_SetPinMux(PORTB, 0UL, kPORT_PinDisabledOrAnalog); /* ADC0 */ + PORT_SetPinMux(PORTB, 1UL, kPORT_PinDisabledOrAnalog); /* ADC1 */ + PORT_SetPinMux(PORTB, 2UL, kPORT_PinDisabledOrAnalog); /* ADC2 */ + PORT_SetPinMux(PORTB, 3UL, kPORT_PinDisabledOrAnalog); /* ADC3 */ +#endif + /* SPI2 pinmux config */ + PORT_SetPinMux(PORTB, 21u, kPORT_MuxAlt2); /* SPI2_SCK */ + PORT_SetPinMux(PORTB, 22u, kPORT_MuxAlt2); /* SPI2_SOUT */ + PORT_SetPinMux(PORTB, 23u, kPORT_MuxAlt2); /* SPI2_SIN */ + PORT_SetPinMux(PORTB, 20u, kPORT_MuxAlt2); /* SPI2_SS */ + + /* Open Drain INT pins config */ + od_config.mux = kPORT_MuxAsGpio; + od_config.openDrainEnable = kPORT_OpenDrainEnable; + od_config.pullSelect = kPORT_PullDisable; + od_config.slewRate = kPORT_FastSlewRate; + od_config.passiveFilterEnable = kPORT_PassiveFilterDisable; + od_config.driveStrength = kPORT_LowDriveStrength; + od_config.lockRegister = kPORT_UnlockRegister; + GPIO_PinInit(GPIOA, 16u, &gpio_out_hi_config); + PORT_SetPinConfig(PORTA, 16u, &od_config); /* MCU_INT1 */ + GPIO_PinInit(GPIOA, 29u, &gpio_out_hi_config); + PORT_SetPinConfig(PORTA, 29u, &od_config); /* MCU_INT2 */ + GPIO_PinInit(GPIOB, 8u, &gpio_out_config); + PORT_SetPinConfig(PORTB, 8u, &od_config); /* MCU_INT3 */ + GPIO_PinInit(GPIOE, 26u, &gpio_out_config); + PORT_SetPinConfig(PORTE, 26u, &od_config); /* MCU_INT4 */ + GPIO_PinInit(GPIOC, 19u, &gpio_out_hi_config); + PORT_SetPinConfig(PORTC, 19u, &od_config); /* PMIC_ONKEY */ + + /* GPIOs */ + for (i = 0; i < sizeof(gpio_list)/sizeof(struct gpio_id); i++){ + PORT_SetPinMux(gpio_list[i].port, gpio_list[i].pin, kPORT_MuxAsGpio); + GPIO_PinInit(gpio_list[i].gpio, gpio_list[i].pin, &gpio_in_config); + } } diff --git a/board/usb_host_config.h b/board/usb_host_config.h new file mode 100644 index 0000000..0bde321 --- /dev/null +++ b/board/usb_host_config.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_HOST_CONFIG_H_ +#define _USB_HOST_CONFIG_H_ + +/* Host Controller Enable */ +/*! + * @brief host khci instance count, meantime it indicates khci enable or disable. + * - if 0, host khci driver is disable. + * - if greater than 0, host khci driver is enable. + */ +#define USB_HOST_CONFIG_KHCI (1U) + +/*! + * @brief host ehci instance count, meantime it indicates ehci enable or disable. + * - if 0, host ehci driver is disable. + * - if greater than 0, host ehci driver is enable. + */ +#define USB_HOST_CONFIG_EHCI (0U) + +/* Common configuration macros for all controllers */ + +/*! + * @brief host driver instance max count. + * for example: 2 - one for khci, one for ehci. + */ +#define USB_HOST_CONFIG_MAX_HOST (2U) + +/*! + * @brief host pipe max count. + * pipe is the host driver resource for device endpoint, one endpoint need one pipe. + */ +#define USB_HOST_CONFIG_MAX_PIPES (16U) + +/*! + * @brief host transfer max count. + * transfer is the host driver resource for data transmission mission, one transmission mission need one transfer. + */ +#define USB_HOST_CONFIG_MAX_TRANSFERS (16U) + +/*! + * @brief the max endpoint for one interface. + * the max endpoint descriptor number that one interface descriptor contain. + */ +#define USB_HOST_CONFIG_INTERFACE_MAX_EP (4U) + +/*! + * @brief the max interface for one configuration. + * the max interface descriptor number that one configuration descriptor can contain. + */ +#define USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE (5U) + +/*! + * @brief the max power for one device. + * the max power the host can provide for one device. + */ +#define USB_HOST_CONFIG_MAX_POWER (250U) + +/*! + * @brief the max retries for enumeration. + * retry time when enumeration fail. + */ +#define USB_HOST_CONFIG_ENUMERATION_MAX_RETRIES (3U) + +/*! + * @brief the max retries for enumeration setup stall. + * the max times for one transfer can stall. + */ +#define USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES (1U) + +/*! + * @brief the max NAK count for one transaction. + * when nak count reach to the value, the transaction fail. + */ +#define USB_HOST_CONFIG_MAX_NAK (3000U) + +/*! @brief Whether the transfer buffer is cache-enabled or not. */ +#define USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE (0U) + +/*! @brief if 1, enable usb compliance test codes; if 0, disable usb compliance test codes. */ +#define USB_HOST_CONFIG_COMPLIANCE_TEST (0U) + +/*! @brief if 1, class driver clear stall automatically; if 0, class driver don't clear stall. */ +#define USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL (0U) + +/* KHCI configuration */ +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) + +/*! + * @brief khci dma align fix buffer size. + */ +#define USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER (64U) + +#endif + +/* EHCI configuration */ +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) + +/*! + * @brief ehci periodic frame list size. + * the value can be 1024, 512, 256, 128, 64, 32, 16 or 8. + */ +#define USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE (1024U) + +/*! + * @brief ehci QH max count. + */ +#define USB_HOST_CONFIG_EHCI_MAX_QH (8U) + +/*! + * @brief ehci QTD max count. + */ +#define USB_HOST_CONFIG_EHCI_MAX_QTD (8U) + +/*! + * @brief ehci ITD max count. + */ +#define USB_HOST_CONFIG_EHCI_MAX_ITD (0U) + +/*! + * @brief ehci SITD max count. + */ +#define USB_HOST_CONFIG_EHCI_MAX_SITD (0U) + +#endif + +/*! + * @brief host HUB class instance count, meantime it indicates HUB class enable or disable. + * - if 0, host HUB class driver is disable. + * - if greater than 0, host HUB class driver is enable. + */ +#define USB_HOST_CONFIG_HUB (0U) + +/*! + * @brief host HID class instance count, meantime it indicates HID class enable or disable. + * - if 0, host HID class driver is disable. + * - if greater than 0, host HID class driver is enable. + */ +#define USB_HOST_CONFIG_HID (0U) + +/*! + * @brief host MSD class instance count, meantime it indicates MSD class enable or disable. + * - if 0, host MSD class driver is disable. + * - if greater than 0, host MSD class driver is enable. + */ +#define USB_HOST_CONFIG_MSD (0U) + +/*! + * @brief host CDC class instance count, meantime it indicates CDC class enable or disable. + * - if 0, host CDC class driver is disable. + * - if greater than 0, host CDC class driver is enable. + */ +#define USB_HOST_CONFIG_CDC (0U) + +/*! + * @brief host AUDIO class instance count, meantime it indicates AUDIO class enable or disable. + * - if 0, host AUDIO class driver is disable. + * - if greater than 0, host AUDIO class driver is enable. + */ +#define USB_HOST_CONFIG_AUDIO (0U) + +/*! + * @brief host PHDC class instance count, meantime it indicates PHDC class enable or disable. + * - if 0, host PHDC class driver is disable. + * - if greater than 0, host PHDC class driver is enable. + */ +#define USB_HOST_CONFIG_PHDC (0U) + +/*! + * @brief host printer class instance count, meantime it indicates printer class enable or disable. + * - if 0, host printer class driver is disable. + * - if greater than 0, host printer class driver is enable. + */ +#define USB_HOST_CONFIG_PRINTER (0U) + +#endif /* _USB_HOST_CONFIG_H_ */ diff --git a/drivers/fsl_adc16.c b/drivers/fsl_adc16.c index 4fee1a8..800d1dc 100644 --- a/drivers/fsl_adc16.c +++ b/drivers/fsl_adc16.c @@ -152,7 +152,7 @@ status_t ADC16_DoAutoCalibration(ADC_Type *base) volatile uint32_t tmp32; /* 'volatile' here is for the dummy read of ADCx_R[0] register. */ status_t status = kStatus_Success; - /* The calibration would be failed when in hardwar mode. + /* The calibration would be failed when in hardware mode. * Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/ if (0U != (ADC_SC2_ADTRG_MASK & base->SC2)) { diff --git a/k20_tester_Debug_Segger.launch b/k20_tester_Debug_Segger.launch index b856cca..4c60bc3 100644 --- a/k20_tester_Debug_Segger.launch +++ b/k20_tester_Debug_Segger.launch @@ -1,31 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -33,6 +72,7 @@ - + + diff --git a/source/adc_task.c b/source/adc_task.c new file mode 100644 index 0000000..67d5bd0 --- /dev/null +++ b/source/adc_task.c @@ -0,0 +1,343 @@ +/* + * adc_task.c + * + */ + +#include "com_task.h" +#include "adc_task.h" +#include "fsl_adc16.h" +#include "fsl_port.h" +#include "errno.h" +#include "stdlib.h" + +/* + * Apalis ADC0 -> PTB0 -> ADC0_SE8 + * Apalis ADC1 -> PTB1 -> ADC0_SE9 + * Apalis ADC2 -> PTB2 -> ADC0_SE12 + * Apalis ADC3 -> PTB3 -> ADC0_SE13 + * + * Touch screen: + * Force: + * PTE6 X+ hi-off + * PTB9 X- lo-off + * PTC5 Y+ hi-off + * PTC13 Y- lo-off + * Sense: + * PTB7 -> ADC1_SE13 X- + * PTB6 -> ADC1_SE12 X+ + * PTC9 -> ADC1_SE5b Y- + * PTC8 -> ADC1_SE4b Y+ + */ +const uint8_t adc0_channels[ADC0_CHANNEL_CNT] = {8, 9, 12, 13}; +const uint8_t tsc_channels[TSC0_CHANNEL_CNT] = {13, 12, 5, 4}; + +static int adc_task_init(void) +{ + adc16_config_t adc_config; +#ifdef BOARD_USES_ADC + ADC16_GetDefaultConfig(&adc_config); + adc_config.resolution = kADC16_ResolutionSE16Bit; + adc_config.longSampleMode = kADC16_LongSampleDisabled; + adc_config.clockDivider = kADC16_ClockDivider8; + ADC16_Init(ADC0, &adc_config); + ADC16_SetHardwareAverage(ADC0, kADC16_HardwareAverageDisabled); + return 0; +#else + return -ENODEV; +#endif +} + +static int tsc_task_init(void) +{ + adc16_config_t adc_config; +#ifdef BOARD_USES_ADC + ADC16_GetDefaultConfig(&adc_config); + adc_config.resolution = kADC16_ResolutionSE12Bit; + adc_config.longSampleMode = kADC16_LongSampleDisabled; + adc_config.clockDivider = kADC16_ClockDivider8; + ADC16_Init(ADC1, &adc_config); + ADC16_SetChannelMuxMode(ADC1, kADC16_ChannelMuxB); + ADC16_SetHardwareAverage(ADC1, kADC16_HardwareAverageCount32); + return 0; +#else + return -ENODEV; +#endif +} + +#ifdef BOARD_USES_ADC +static void ts_force_drive(uint8_t xm, uint8_t xp, uint8_t ym, uint8_t yp) +{ + if (xp == 0) + GPIO_SetPinsOutput(GPIOE, 1 << 6); + else + GPIO_ClearPinsOutput(GPIOE, 1 << 6); + + if (xm > 0) + GPIO_SetPinsOutput(GPIOB, 1 << 9); + else + GPIO_ClearPinsOutput(GPIOB, 1 << 9); + + if (yp == 0) + GPIO_SetPinsOutput(GPIOC, 1 << 5); + else + GPIO_ClearPinsOutput(GPIOC, 1 << 5); + + if (ym > 0) + GPIO_SetPinsOutput(GPIOC, 1 << 13); + else + GPIO_ClearPinsOutput(GPIOC, 1 << 13); +} + +static inline uint16_t do_adc_conversion(ADC_Type *base, adc16_channel_config_t *channel) +{ + ADC16_SetChannelConfig(base, 0, channel); + while(ADC16_GetChannelStatusFlags(base, 0) == 0){vTaskDelay(0);} + return (uint16_t)ADC16_GetChannelConversionValue(base, 0); +} + +void adc_task(void *pvParameters) +{ + adc16_channel_config_t channel; + int i; + if (adc_task_init() < 0) + return; + + channel.enableDifferentialConversion = false; + channel.enableInterruptOnConversionCompleted = false; + + while(1) { + for (i = 0; i < ADC0_CHANNEL_CNT;i ++){ + channel.channelNumber = adc0_channels[i]; + gen_regs.adc[i] = do_adc_conversion(ADC0, &channel); + } + vTaskDelay(1); + } + +} + +enum touch_status { + PEN_UP, + PEN_DOWN +}; + +#define MIN_TOUCH_DET 5 + +/* PTB7 -> ADC1_SE13 X- + * PTB6 -> ADC1_SE12 X+ + * PTC9 -> ADC1_SE5b Y- + * PTC8 -> ADC1_SE4b Y+ + */ +void tsc_task(void *pvParameters) +{ + adc16_channel_config_t channel; + port_pin_config_t pin_config_pd, pin_config_ana; + int old_status, status = PEN_UP; + int irq_stat = 0; + if (tsc_task_init() < 0) + return; + + pin_config_pd.mux = kPORT_MuxAsGpio; + pin_config_pd.openDrainEnable = kPORT_OpenDrainDisable; + pin_config_pd.pullSelect = kPORT_PullDown; + pin_config_pd.slewRate = kPORT_FastSlewRate; + pin_config_pd.passiveFilterEnable = kPORT_PassiveFilterDisable; + pin_config_pd.driveStrength = kPORT_LowDriveStrength; + pin_config_pd.lockRegister = kPORT_UnlockRegister; + + pin_config_ana.mux = kPORT_PinDisabledOrAnalog; + pin_config_ana.openDrainEnable = kPORT_OpenDrainDisable; + pin_config_ana.pullSelect = kPORT_PullDisable; + pin_config_ana.slewRate = kPORT_FastSlewRate; + pin_config_ana.passiveFilterEnable = kPORT_PassiveFilterDisable; + pin_config_ana.driveStrength = kPORT_LowDriveStrength; + pin_config_ana.lockRegister = kPORT_UnlockRegister; + + channel.enableDifferentialConversion = false; + channel.enableInterruptOnConversionCompleted = false; + + while(1) { + //Touch detect power Y+, enable pulldown on xp and read xp GPIO + ts_force_drive(0, 0, 0, 1); + PORT_SetPinConfig(PORTB, 6u, &pin_config_pd); + vTaskDelay(10); + old_status = status; + status = GPIO_ReadPinInput(GPIOB, 6u) ? PEN_DOWN:PEN_UP; + PORT_SetPinConfig(PORTB, 6u, &pin_config_ana); + + if (status != old_status) + irq_stat = 0; + + if (status == PEN_DOWN) { + //probe ym with power across Y plane + ts_force_drive(0, 0, 1, 1); + vTaskDelay(10); + channel.channelNumber = tsc_channels[0]; + gen_regs.tsc_ym = do_adc_conversion(ADC1, &channel); + + //probe yp with power across Y plane + channel.channelNumber = tsc_channels[1]; + gen_regs.tsc_yp = do_adc_conversion(ADC1, &channel); + + //probe xm with power across X plane + ts_force_drive(1, 1, 0, 0); + vTaskDelay(10); + channel.channelNumber = tsc_channels[2]; + gen_regs.tsc_xm = do_adc_conversion(ADC1, &channel); + + //probe xp with power across X plane + channel.channelNumber = tsc_channels[3]; + gen_regs.tsc_xp = do_adc_conversion(ADC1, &channel); + + if (irq_stat == 0) { + generate_irq(APALIS_TK1_K20_TSC_IRQ); + irq_stat = 1; + } + } else { + gen_regs.tsc_xm = 0; + gen_regs.tsc_xp = 0; + gen_regs.tsc_ym = 0; + gen_regs.tsc_yp = 0; + vTaskDelay(20); + if (irq_stat == 0) { + generate_irq(APALIS_TK1_K20_TSC_IRQ); + irq_stat = 1; + } + } + vTaskDelay(10); + } + +} + +int tsc_registers(uint8_t *rx_buf, uint8_t *tx_buf) +{ + if (rx_buf[0] == APALIS_TK1_K20_READ_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_TSCREG: + tx_buf[0] = 0x00; + return 1; + case APALIS_TK1_K20_TSC_XML: + tx_buf[0] = gen_regs.tsc_xm & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_XMH: + tx_buf[0] = (gen_regs.tsc_xm >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_XPL: + tx_buf[0] = gen_regs.tsc_xp & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_XPH: + tx_buf[0] = (gen_regs.tsc_xp >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_YML: + tx_buf[0] = gen_regs.tsc_ym & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_YMH: + tx_buf[0] = (gen_regs.tsc_ym >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_YPL: + tx_buf[0] = gen_regs.tsc_yp & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_YPH: + tx_buf[0] = (gen_regs.tsc_yp >> 8) & 0xFF; + return 1; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_TSCREG: + return -ENOENT; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_BULK_READ_INST) { + switch (rx_buf[1]){ + case APALIS_TK1_K20_TSC_XML: + tx_buf[0] = gen_regs.tsc_xm & 0xFF; + tx_buf[1] = (gen_regs.tsc_xm >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_TSC_XPL: + tx_buf[0] = gen_regs.tsc_xp & 0xFF; + tx_buf[1] = (gen_regs.tsc_xp >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_TSC_YML: + tx_buf[0] = gen_regs.tsc_ym & 0xFF; + tx_buf[1] = (gen_regs.tsc_ym >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_TSC_YPL: + tx_buf[0] = gen_regs.tsc_yp & 0xFF; + tx_buf[1] = (gen_regs.tsc_yp >> 8) & 0xFF; + return 2; + default: + return -ENOENT; + } + } + return -ENOENT; +} + +int adc_registers(uint8_t *rx_buf, uint8_t *tx_buf) +{ + if (rx_buf[0] == APALIS_TK1_K20_READ_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_ADCREG: + tx_buf[0] = 0x00; + return 1; + case APALIS_TK1_K20_ADC_CH0L: + tx_buf[0] = gen_regs.adc[0] & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH0H: + tx_buf[0] = (gen_regs.adc[0] >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH1L: + tx_buf[0] = gen_regs.adc[1] & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH1H: + tx_buf[0] = (gen_regs.adc[1] >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH2L: + tx_buf[0] = gen_regs.adc[2] & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH2H: + tx_buf[0] = (gen_regs.adc[2] >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH3L: + tx_buf[0] = gen_regs.adc[3] & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH3H: + tx_buf[0] = (gen_regs.adc[3] >> 8) & 0xFF; + return 1; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_ADCREG: + return -ENOENT; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_BULK_READ_INST) { + switch (rx_buf[1]){ + case APALIS_TK1_K20_ADC_CH0L: + tx_buf[0] = gen_regs.adc[0] & 0xFF; + tx_buf[1] = (gen_regs.adc[0] >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_ADC_CH1L: + tx_buf[0] = gen_regs.adc[1] & 0xFF; + tx_buf[1] = (gen_regs.adc[1] >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_ADC_CH2L: + tx_buf[0] = gen_regs.adc[2] & 0xFF; + tx_buf[1] = (gen_regs.adc[2] >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_ADC_CH3L: + tx_buf[0] = gen_regs.adc[3] & 0xFF; + tx_buf[1] = (gen_regs.adc[3] >> 8) & 0xFF; + return 2; + + default: + return -ENOENT; + } + } + return -ENOENT; +} +#endif diff --git a/source/adc_task.h b/source/adc_task.h new file mode 100644 index 0000000..3dafddb --- /dev/null +++ b/source/adc_task.h @@ -0,0 +1,19 @@ +/* + * adc_task.h + * + */ + +#ifndef SOURCE_ADC_TASK_H_ +#define SOURCE_ADC_TASK_H_ +#include "board.h" + +#ifdef BOARD_USES_ADC +TaskHandle_t adc_task_handle; +TaskHandle_t tsc_task_handle; +void adc_task(void *pvParameters); +void tsc_task(void *pvParameters); +int adc_registers(uint8_t *rx_buf, uint8_t *tx_buf); +int tsc_registers(uint8_t *rx_buf, uint8_t *tx_buf); +#endif + +#endif /* SOURCE_ADC_TASK_H_ */ diff --git a/source/com_task.c b/source/com_task.c new file mode 100644 index 0000000..348c3e1 --- /dev/null +++ b/source/com_task.c @@ -0,0 +1,205 @@ + +#include "com_task.h" +#include "gpio_ext.h" +#include "adc_task.h" + +/* Put FW version at known address in binary. Make it 32-bit to have room for the future*/ +const uint32_t __attribute__((section(".FwVersion"))) fw_version = APALIS_TK1_K20_FW_VER; + +#define MAX_TRANSFER_SIZE 32U +static dspi_slave_handle_t spi_handle; +static uint8_t slaveRxData[MAX_TRANSFER_SIZE] = {0U}; +static uint8_t slaveTxData[MAX_TRANSFER_SIZE] = {0U}; + +void generate_irq(uint8_t irq) { + gen_regs.irq = gen_regs.irq | BIT(irq); + /* Toggle INT1 pin */ + GPIO_TogglePinsOutput(GPIOA, 1u << 16u); +} + +void clear_irq_flag(uint8_t irq) { + gen_regs.irq = ~irq & gen_regs.irq; +} + +uint8_t get_control_reg() +{ + return gen_regs.control; + +} + +void set_control_reg(uint8_t value) +{ + gen_regs.control = value; +} + +uint8_t get_status_reg() +{ + return gen_regs.status; + +} + +void set_status_reg(uint8_t value) +{ + gen_regs.status = value; +} + +uint8_t get_mask_reg() +{ + return gen_regs.irq_mask; + +} + +void set_mask_reg(uint8_t value) +{ + gen_regs.irq_mask = value; +} + +uint8_t get_irq_reg() +{ + return gen_regs.irq; + +} + +void set_irq_reg(uint8_t value) +{ + /* Clear IRQ flag on 1 */ + clear_irq_flag(value); + +} + +int inline general_registers(uint8_t *rx_buf, uint8_t * tx_buf) { + + if (rx_buf[0] == APALIS_TK1_K20_READ_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_STAREG: + tx_buf[0] = get_status_reg(); + return 1; + case APALIS_TK1_K20_REVREG: + tx_buf[0] = APALIS_TK1_K20_FW_VER; + return 1; + case APALIS_TK1_K20_IRQREG: + tx_buf[0] = get_irq_reg(); + return 1; + case APALIS_TK1_K20_CTRREG: + tx_buf[0] = get_control_reg(); + return 1; + case APALIS_TK1_K20_MSQREG: + tx_buf[0] = get_mask_reg(); + return 1; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_STAREG: + set_status_reg(rx_buf[2]); + return 0; + case APALIS_TK1_K20_REVREG: + return -ENOENT; + case APALIS_TK1_K20_IRQREG: + set_irq_reg(rx_buf[2]); + return 0; + case APALIS_TK1_K20_CTRREG: + set_control_reg(rx_buf[2]); + return 0; + case APALIS_TK1_K20_MSQREG: + set_mask_reg(rx_buf[2]); + return 0; + default: + return -ENOENT; + } + } + + + return -ENOENT; +} + +static void SPI_callback(SPI_Type *base, dspi_slave_handle_t *handle, status_t status, void *userData) +{ + callback_message_t * cb = (callback_message_t*) userData; + BaseType_t reschedule = pdFALSE; + + if (status == kStatus_Success) + { + xSemaphoreGiveFromISR(cb->sem, &reschedule); + } + + if (status == kStatus_DSPI_Error) + { + __NOP(); + } + portYIELD_FROM_ISR(reschedule); +} + +static void SPI_init() { + dspi_slave_config_t slaveConfig; + /* Slave config */ + slaveConfig.whichCtar = kDSPI_Ctar0; + slaveConfig.ctarConfig.bitsPerFrame = 8; + slaveConfig.ctarConfig.cpol = kDSPI_ClockPolarityActiveHigh; + slaveConfig.ctarConfig.cpha = kDSPI_ClockPhaseSecondEdge; + slaveConfig.enableContinuousSCK = true; + slaveConfig.enableRxFifoOverWrite = false; + slaveConfig.enableModifiedTimingFormat = false; + slaveConfig.samplePoint = kDSPI_SckToSin0Clock; + + DSPI_SlaveInit(SPI2, &slaveConfig); + DSPI_SlaveTransferCreateHandle(SPI2, &spi_handle, SPI_callback, spi_handle.userData); + + /* Set dspi slave interrupt priority higher. */ + NVIC_SetPriority(SPI2_IRQn, 5U); + GPIO_ClearPinsOutput(GPIOA, 1u << 29u); /* INT2 active */ + PRINTF("SPI init done \r\n"); + +} + +void spi_task(void *pvParameters) { + callback_message_t cb_msg; + dspi_transfer_t slaveXfer; + int ret; + + cb_msg.sem = xSemaphoreCreateBinary(); + spi_handle.userData = &cb_msg; + SPI_init(); + GPIO_SetPinsOutput(GPIOA, 1u << 29u); /* INT2 idle */ + + while(1){ + slaveXfer.txData = slaveTxData; + slaveXfer.rxData = slaveRxData; + slaveXfer.dataSize = 3; + slaveXfer.configFlags = kDSPI_SlaveCtar0; + /* Wait for instructions from SoC */ + DSPI_SlaveTransferNonBlocking(SPI2, &spi_handle, &slaveXfer); + xSemaphoreTake(cb_msg.sem, portMAX_DELAY); + if (slaveRxData[1] <= 0x05) { + ret = general_registers(slaveRxData, &slaveTxData[1]); +#ifdef BOARD_USES_ADC + } else if ((slaveRxData[1] >= APALIS_TK1_K20_ADCREG) && (slaveRxData[1] <= APALIS_TK1_K20_ADC_CH3H)) { + ret = adc_registers(slaveRxData, &slaveTxData[1]); + + } else if ((slaveRxData[1] >= APALIS_TK1_K20_TSCREG) && (slaveRxData[1] <= APALIS_TK1_K20_TSC_YPH)) { + ret = tsc_registers(slaveRxData, &slaveTxData[1]); +#endif + } else if ((slaveRxData[1] >= APALIS_TK1_K20_GPIOREG) && (slaveRxData[1] <= APALIS_TK1_K20_GPIO_STA)) { + ret = gpio_registers(slaveRxData, &slaveTxData[1]); + + } else { + /* Register not defined */ + ret = -EINVAL; + } + + if (ret < 0) { + slaveTxData[0] = TK1_K20_INVAL; + slaveTxData[1] = TK1_K20_INVAL; + } else { + slaveTxData[0] = TK1_K20_SENTINEL; + } + + if (slaveRxData[0] == APALIS_TK1_K20_READ_INST || slaveRxData[0] == APALIS_TK1_K20_BULK_READ_INST) + { + slaveXfer.dataSize = (ret >= 0) ? (ret + 1):2; /* Extra byte is for sentinel */ + DSPI_SlaveTransferNonBlocking(SPI2, &spi_handle, &slaveXfer); + xSemaphoreTake(cb_msg.sem, portMAX_DELAY); + } + } +} diff --git a/source/com_task.h b/source/com_task.h new file mode 100644 index 0000000..14c742e --- /dev/null +++ b/source/com_task.h @@ -0,0 +1,130 @@ +/* + * com_task.h + */ + +#ifndef COM_TASK_H_ +#define COM_TASK_H_ + +#include "board.h" +#include "fsl_debug_console.h" +#include "fsl_dspi.h" +#include "fsl_gpio.h" + +/* FreeRTOS kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "timers.h" +#include "semphr.h" +#include "errno.h" + +typedef struct _callback_message_t +{ + status_t async_status; + SemaphoreHandle_t sem; +} callback_message_t; + +TaskHandle_t spi_task_handle; +void generate_irq(uint8_t irq); +void clear_irq_flag(uint8_t irq); +void spi_task(void *pvParameters); + +#define BIT(nr) (1UL << (nr)) + + +/* Commands and registers used in SPI communication */ + +/* Commands*/ +#define APALIS_TK1_K20_READ_INST 0x0F +#define APALIS_TK1_K20_WRITE_INST 0xF0 +#define APALIS_TK1_K20_BULK_WRITE_INST 0x3C +#define APALIS_TK1_K20_BULK_READ_INST 0xC3 + +#define APALIS_TK1_K20_MAX_BULK (64) + +/* General registers*/ +#define APALIS_TK1_K20_STAREG 0x00 /* General status register RO */ +#define APALIS_TK1_K20_REVREG 0x01 /* FW revision register RO*/ +#define APALIS_TK1_K20_IRQREG 0x02 /* IRQ status RW(write of 1 will reset the bit) */ +#define APALIS_TK1_K20_CTRREG 0x03 /* General control register RW */ +#define APALIS_TK1_K20_MSQREG 0x04 /* IRQ mask register RW */ + +/* CAN Registers */ +#define APALIS_TK1_K20_CANREG 0x10 /* CAN control & status register RW */ +#define APALIS_TK1_K20_CAN_BAUD_REG 0x11 /* CAN Baud set register RW */ +#define APALIS_TK1_K20_CAN_IN_BUF_CNT 0x12 /* CAN IN BUF Received Data Count RO */ +#define APALIS_TK1_K20_CAN_IN_BUF 0x13 /* CAN IN BUF RO */ +#define APALIS_TK1_K20_CAN_OUT_BUF_CNT 0x14 /* CAN OUT BUF Data Count WO, must be written before bulk write to APALIS_TK1_K20_CAN0_OUT_BUF_CNT */ +#define APALIS_TK1_K20_CAN_OUT_FIF0 0x15 /* CAN OUT BUF WO */ + +#define APALIS_TK1_K20_CAN_DEV_OFFSET(x) (x ? 0:0x10) + +/* ADC Registers */ +#define APALIS_TK1_K20_ADCREG 0x30 /* ADC control & status register RW */ +#define APALIS_TK1_K20_ADC_CH0L 0x31 /* ADC Channel 0 LSB RO */ +#define APALIS_TK1_K20_ADC_CH0H 0x32 /* ADC Channel 0 MSB RO */ +#define APALIS_TK1_K20_ADC_CH1L 0x33 /* ADC Channel 1 LSB RO */ +#define APALIS_TK1_K20_ADC_CH1H 0x34 /* ADC Channel 1 MSB RO */ +#define APALIS_TK1_K20_ADC_CH2L 0x35 /* ADC Channel 2 LSB RO */ +#define APALIS_TK1_K20_ADC_CH2H 0x36 /* ADC Channel 2 MSB RO */ +#define APALIS_TK1_K20_ADC_CH3L 0x37 /* ADC Channel 3 LSB RO */ +#define APALIS_TK1_K20_ADC_CH3H 0x38 /* ADC Channel 3 MSB RO */ +/* Bulk read of LSB register can be use to read entire 16-bit in one command */ + +/* TSC Register */ +#define APALIS_TK1_K20_TSCREG 0x40 /* TSC control & status register RW */ +#define APALIS_TK1_K20_TSC_XML 0x41 /* TSC X- data LSB RO */ +#define APALIS_TK1_K20_TSC_XMH 0x42 /* TSC X- data MSB RO */ +#define APALIS_TK1_K20_TSC_XPL 0x43 /* TSC X+ data LSB RO */ +#define APALIS_TK1_K20_TSC_XPH 0x44 /* TSC X+ data MSB RO */ +#define APALIS_TK1_K20_TSC_YML 0x45 /* TSC Y- data LSB RO */ +#define APALIS_TK1_K20_TSC_YMH 0x46 /* TSC Y- data MSB RO */ +#define APALIS_TK1_K20_TSC_YPL 0x47 /* TSC Y+ data LSB RO */ +#define APALIS_TK1_K20_TSC_YPH 0x48 /* TSC Y+ data MSB RO */ +/* Bulk read of LSB register can be use to read entire 16-bit in one command */ +#define APALIS_TK1_K20_TSC_ENA BIT(0) +#define APALIS_TK1_K20_TSC_ENA_MASK 0xFE + +/* GPIO Registers */ +#define APALIS_TK1_K20_GPIOREG 0x50 /* GPIO control & status register RW */ +#define APALIS_TK1_K20_GPIO_NO 0x51 /* currently configured GPIO RW */ +#define APALIS_TK1_K20_GPIO_STA 0x52 /* Status register for the APALIS_TK1_K20_GPIO_NO GPIO RW */ +/* MSB | 0 ... 0 | VALUE | Output-1 / Input-0 | LSB */ +#define APALIS_TK1_K20_GPIO_STA_OE BIT(0) +#define APALIS_TK1_K20_GPIO_STA_VAL BIT(1) + +/* Interrupt flags */ +#define APALIS_TK1_K20_GEN_IRQ 0 +#define APALIS_TK1_K20_CAN0_IRQ 1 +#define APALIS_TK1_K20_CAN1_IRQ 2 +#define APALIS_TK1_K20_ADC_IRQ 3 +#define APALIS_TK1_K20_TSC_IRQ 4 +#define APALIS_TK1_K20_GPIO_IRQ 5 + +#define APALIS_TK1_K20_FW_VER 0x05 + +#define FW_MINOR (APALIS_TK1_K20_FW_VER & 0x0F) +#define FW_MAJOR ((APALIS_TK1_K20_FW_VER & 0xF0) >> 8) + +#define TK1_K20_SENTINEL 0x55 +#define TK1_K20_INVAL 0xAA + +#define ADC0_CHANNEL_CNT 4 + +#define TSC0_CHANNEL_CNT 4 + +/* Structure with general registers */ +struct register_struct { + uint8_t status; + uint8_t control; + uint8_t irq_mask; + uint8_t irq; + uint8_t gpio_no; + uint16_t adc[ADC0_CHANNEL_CNT]; + uint16_t tsc_xm; + uint16_t tsc_xp; + uint16_t tsc_ym; + uint16_t tsc_yp; +} gen_regs; + +#endif /* COM_TASK_H_ */ diff --git a/source/gpio_ext.c b/source/gpio_ext.c new file mode 100644 index 0000000..5741cb5 --- /dev/null +++ b/source/gpio_ext.c @@ -0,0 +1,141 @@ +/* + * gpio_ext.c + * + */ + +#include "gpio_ext.h" +#include "com_task.h" +#include "errno.h" + + +static inline int port_type_to_int(PORT_Type *port) +{ + switch ((int) port) { + case PORTA_BASE: + return 0; + case PORTB_BASE: + return 1; + case PORTC_BASE: + return 2; + case PORTD_BASE: + return 3; + case PORTE_BASE: + return 4; + default: + return -EINVAL; + } +} + +/* returns GPIO index in gpio_list table and -EINVAL + * if there is no entry for this gpio. + */ +int is_gpio_valid(uint8_t pin) +{ + uint16_t i; + int temp; + if (pin == 0xFF) + return -EINVAL; + + for (i = 0; i < sizeof(gpio_list)/sizeof(struct gpio_id); i++){ + temp = port_type_to_int(gpio_list[i].port) * 32; + temp += gpio_list[i].pin; + if ( temp == pin ) + return i; + } + + return -EINVAL; +} + +int set_gpio_status(uint8_t status, uint8_t pin) +{ + gpio_pin_config_t gpio_config; + int index; + + gpio_config.pinDirection = (status & APALIS_TK1_K20_GPIO_STA_OE) ? kGPIO_DigitalOutput : kGPIO_DigitalInput; + gpio_config.outputLogic = (status & APALIS_TK1_K20_GPIO_STA_VAL); + + index = is_gpio_valid(pin); + + if (index >= 0) + GPIO_PinInit(gpio_list[index].gpio, gpio_list[index].pin, &gpio_config); + else + return index; + + return 0; +} + + +uint8_t get_gpio_status(uint8_t pin) +{ + uint8_t status; + int index; + GPIO_Type *base; + uint32_t gpio_pin; + + index = is_gpio_valid(pin); + if (index == -EINVAL) + return 0xFF; + base = gpio_list[index].gpio; + gpio_pin = gpio_list[index].pin; + + if (((base->PDDR) >> gpio_pin) & 0x01U) { + status = APALIS_TK1_K20_GPIO_STA_OE; + status += (((base->PDOR) >> gpio_pin) & 0x01U) ? APALIS_TK1_K20_GPIO_STA_VAL : 0x00; + } else { + status = 0x00; + status += (((base->PDIR) >> gpio_pin) & 0x01U) ? APALIS_TK1_K20_GPIO_STA_VAL : 0x00; + } + + return status; +} + +int gpio_registers(uint8_t *rx_buf, uint8_t *tx_buf){ + if (rx_buf[0] == APALIS_TK1_K20_READ_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_GPIOREG: + return -ENOENT; + break; + case APALIS_TK1_K20_GPIO_NO: + if (gen_regs.gpio_no != 0xFF){ + tx_buf[0] = gen_regs.gpio_no; + return 1; + } else + return -ENOENT; + break; + case APALIS_TK1_K20_GPIO_STA: + if (gen_regs.gpio_no != 0xFF){ + tx_buf[0] = get_gpio_status(gen_regs.gpio_no); + return 1; + } else + return -ENOENT; + break; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_GPIOREG: + return -ENOENT; + break; + case APALIS_TK1_K20_GPIO_NO: + if (is_gpio_valid(rx_buf[2]) >= 0){ + gen_regs.gpio_no = rx_buf[2]; + return 0; + } else { + gen_regs.gpio_no = 0xFF; + return -ENOENT; + } + break; + case APALIS_TK1_K20_GPIO_STA: + return set_gpio_status(rx_buf[2], gen_regs.gpio_no); + break; + default: + return -ENOENT; + } + } + return -ENOENT; +} + + + + diff --git a/source/gpio_ext.h b/source/gpio_ext.h new file mode 100644 index 0000000..5edbf3a --- /dev/null +++ b/source/gpio_ext.h @@ -0,0 +1,73 @@ +/* + * gpio_ext.h + * + */ + +#ifndef SOURCE_GPIO_EXT_H_ +#define SOURCE_GPIO_EXT_H_ + +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" +#include "board.h" + +struct gpio_id{ + PORT_Type *port; + GPIO_Type *gpio; + uint32_t pin; +}; + +struct gpio_id gpio_list [] = { + {PORTA, GPIOA, 3}, + {PORTA, GPIOA, 5}, + {PORTA, GPIOA, 17}, +#ifndef BOARD_USES_ADC + {PORTB, GPIOB, 1}, + {PORTB, GPIOB, 2}, + {PORTB, GPIOB, 3}, +#endif +#ifndef SDK_DEBUGCONSOLE + {PORTB, GPIOB, 10}, + {PORTB, GPIOB, 11}, +#endif + {PORTB, GPIOB, 16}, + {PORTB, GPIOB, 17}, + {PORTB, GPIOB, 18}, + {PORTB, GPIOB, 19}, + {PORTC, GPIOC, 0}, + {PORTC, GPIOC, 1}, + {PORTC, GPIOC, 2}, + {PORTC, GPIOC, 3}, + {PORTC, GPIOC, 4}, + {PORTC, GPIOC, 6}, + {PORTC, GPIOC, 7}, + {PORTD, GPIOD, 0}, + {PORTD, GPIOD, 1}, + {PORTD, GPIOD, 2}, + {PORTD, GPIOD, 3}, + {PORTD, GPIOD, 4}, + {PORTD, GPIOD, 5}, + {PORTD, GPIOD, 6}, + {PORTD, GPIOD, 7}, + {PORTD, GPIOD, 8}, + {PORTD, GPIOD, 9}, + {PORTD, GPIOD, 11}, + {PORTD, GPIOD, 12}, + {PORTD, GPIOD, 13}, + {PORTD, GPIOD, 14}, + {PORTD, GPIOD, 15}, + {PORTE, GPIOE, 0}, + {PORTE, GPIOE, 1}, + {PORTE, GPIOE, 2}, + {PORTE, GPIOE, 3}, + {PORTE, GPIOE, 4}, + {PORTE, GPIOE, 5}, + {PORTE, GPIOE, 24}, + {PORTE, GPIOE, 25} +}; + +int is_gpio_valid(uint8_t pin); +int set_gpio_status(uint8_t status, uint8_t pin); +uint8_t get_gpio_status(uint8_t pin); +int gpio_registers(uint8_t *rx_buf, uint8_t *tx_buf); + +#endif /* SOURCE_GPIO_EXT_H_ */ diff --git a/source/main.c b/source/main.c index 094da3a..e035d4e 100644 --- a/source/main.c +++ b/source/main.c @@ -37,7 +37,9 @@ #include "board.h" #include "pin_mux.h" #include "clock_config.h" -/*#include "fsl_debug_console.h"*/ +#include "fsl_debug_console.h" +#include "com_task.h" +#include "adc_task.h" /* FreeRTOS kernel includes. */ #include "FreeRTOS.h" @@ -46,38 +48,77 @@ #include "timers.h" +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) +#define CONTROLLER_ID kUSB_ControllerKhci0 +#endif +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) +#define CONTROLLER_ID kUSB_ControllerEhci0 +#endif + /* Task priorities. */ -#define hello_task_PRIORITY (configMAX_PRIORITIES - 1) +#define debug_task_PRIORITY 1 +#define USB_HOST_INTERRUPT_PRIORITY (5U) + +/* Task handles */ + +TaskHandle_t usb_task_handle; +#ifdef SDK_DEBUGCONSOLE +TaskHandle_t debug_task_handle; +#endif + /*! - * @brief Task responsible for printing of "Hello world." message. + * @brief Debug task */ -static void hello_task(void *pvParameters) { - for (;;) { - /*PRINTF("Hello world.\r\n");*/ - /* Add your code here */ - vTaskSuspend(NULL); - } +#ifdef SDK_DEBUGCONSOLE +static void debug_task(void *pvParameters) { + for (;;) { + vTaskDelay(10000); + } } - +#endif /*! * @brief Application entry point. */ int main(void) { - /* Init board hardware. */ - BOARD_InitPins(); - BOARD_BootClockRUN(); - BOARD_InitDebugConsole(); - /* Add your code here */ + /* Init board hardware. */ + BOARD_InitPins(); + BOARD_BootClockRUN(); + BOARD_InitDebugConsole(); + PRINTF("Apalis K20 Firmware Version %d.%d\r\n", FW_MAJOR, FW_MINOR); + + /* Create RTOS task */ + if(xTaskCreate(spi_task, "SPI_task", 2000L / sizeof(portSTACK_TYPE), NULL, 4, &spi_task_handle) != pdPASS) + { + PRINTF("create SPI task error\r\n"); + } + +#ifdef BOARD_USES_ADC + if(xTaskCreate(adc_task, "ADC_task", 2000L / sizeof(portSTACK_TYPE), NULL, 2, &adc_task_handle) != pdPASS) + { + PRINTF("create ADC task error\r\n"); + } + + if(xTaskCreate(tsc_task, "TSC_task", 2000L / sizeof(portSTACK_TYPE), NULL, 2, &tsc_task_handle) != pdPASS) + { + PRINTF("create TSC task error\r\n"); + } +#endif + +#ifdef SDK_DEBUGCONSOLE + if(xTaskCreate(debug_task, "Debug_task", configMINIMAL_STACK_SIZE, NULL, debug_task_PRIORITY, &debug_task_handle) != pdPASS) + { + PRINTF("create hello task error\r\n"); + } +#endif - /* Create RTOS task */ - xTaskCreate(hello_task, "Hello_task", configMINIMAL_STACK_SIZE, NULL, hello_task_PRIORITY, NULL); - vTaskStartScheduler(); + NVIC_SetPriorityGrouping( 0 ); + vTaskStartScheduler(); - for(;;) { /* Infinite loop to avoid leaving the main function */ - __asm("NOP"); /* something to use as a breakpoint stop while looping */ - } + for(;;) { /* Infinite loop to avoid leaving the main function */ + __asm("NOP"); /* something to use as a breakpoint stop while looping */ + } } diff --git a/usb_1.1.0/device/usb_device.h b/usb_1.1.0/device/usb_device.h new file mode 100644 index 0000000..6301c97 --- /dev/null +++ b/usb_1.1.0/device/usb_device.h @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_DEVICE_H__ +#define __USB_DEVICE_H__ + +/*! + * @addtogroup usb_device_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines Get/Set status Types */ +typedef enum _usb_device_status +{ + kUSB_DeviceStatusTestMode = 1U, /*!< Test mode */ + kUSB_DeviceStatusSpeed, /*!< Current speed */ + kUSB_DeviceStatusOtg, /*!< OTG status */ + kUSB_DeviceStatusDevice, /*!< Device status */ + kUSB_DeviceStatusEndpoint, /*!< Endpoint state usb_device_endpoint_status_t */ + kUSB_DeviceStatusDeviceState, /*!< Device state */ + kUSB_DeviceStatusAddress, /*!< Device address */ + kUSB_DeviceStatusSynchFrame, /*!< Current frame */ + kUSB_DeviceStatusBus, /*!< Bus status */ +} usb_device_status_t; + +/*! @brief Defines USB 2.0 device state */ +typedef enum _usb_device_state +{ + kUSB_DeviceStateConfigured = 0U, /*!< Device state, Configured*/ + kUSB_DeviceStateAddress, /*!< Device state, Address*/ + kUSB_DeviceStateDefault, /*!< Device state, Default*/ + kUSB_DeviceStateAddressing, /*!< Device state, Address setting*/ + kUSB_DeviceStateTestMode, /*!< Device state, Test mode*/ +} usb_device_state_t; + +/*! @brief Defines endpoint state */ +typedef enum _usb_endpoint_status +{ + kUSB_DeviceEndpointStateIdle = 0U, /*!< Endpoint state, idle*/ + kUSB_DeviceEndpointStateStalled, /*!< Endpoint state, stalled*/ +} usb_device_endpoint_status_t; + +/*! @brief Control endpoint index */ +#define USB_CONTROL_ENDPOINT (0U) +/*! @brief Control endpoint maxPacketSize */ +#define USB_CONTROL_MAX_PACKET_SIZE (64U) + +#if (USB_DEVICE_CONFIG_EHCI && (USB_CONTROL_MAX_PACKET_SIZE != (64U))) +#error For high speed, USB_CONTROL_MAX_PACKET_SIZE must be 64!!! +#endif + +/*! @brief The setup packet size of USB control transfer. */ +#define USB_SETUP_PACKET_SIZE (8U) +/*! @brief USB endpoint mask */ +#define USB_ENDPOINT_NUMBER_MASK (0x0FU) + +/*! @brief Default invalid value or the endpoint callback length of cancelled transfer */ +#define USB_UNINITIALIZED_VAL_32 (0xFFFFFFFFU) + +/*! @brief Available common EVENT types in device callback */ +typedef enum _usb_device_event +{ + kUSB_DeviceEventBusReset = 1U, /*!< USB bus reset signal detected */ + kUSB_DeviceEventSuspend, /*!< USB bus suspend signal detected */ + kUSB_DeviceEventResume, /*!< USB bus resume signal detected. The resume signal is driven by itself or a host */ + kUSB_DeviceEventError, /*!< An error is happened in the bus. */ + kUSB_DeviceEventDetach, /*!< USB device is disconnected from a host. */ + kUSB_DeviceEventAttach, /*!< USB device is connected to a host. */ + kUSB_DeviceEventSetConfiguration, /*!< Set configuration. */ + kUSB_DeviceEventSetInterface, /*!< Set interface. */ + + kUSB_DeviceEventGetDeviceDescriptor, /*!< Get device descriptor. */ + kUSB_DeviceEventGetConfigurationDescriptor, /*!< Get configuration descriptor. */ + kUSB_DeviceEventGetStringDescriptor, /*!< Get string descriptor. */ + kUSB_DeviceEventGetHidDescriptor, /*!< Get HID descriptor. */ + kUSB_DeviceEventGetHidReportDescriptor, /*!< Get HID report descriptor. */ + kUSB_DeviceEventGetHidPhysicalDescriptor, /*!< Get HID physical descriptor. */ + kUSB_DeviceEventGetDeviceQualifierDescriptor, /*!< Get device qualifier descriptor. */ + kUSB_DeviceEventVendorRequest, /*!< Vendor request. */ + kUSB_DeviceEventSetRemoteWakeup, /*!< Enable or disable remote wakeup function. */ + kUSB_DeviceEventGetConfiguration, /*!< Get current configuration index */ + kUSB_DeviceEventGetInterface, /*!< Get current interface alternate setting value */ +} usb_device_event_t; + +/*! @brief Endpoint callback message structure */ +typedef struct _usb_device_endpoint_callback_message_struct +{ + uint8_t *buffer; /*!< Transferred buffer */ + uint32_t length; /*!< Transferred data length */ + uint8_t isSetup; /*!< Is in a setup phase */ +} usb_device_endpoint_callback_message_struct_t; + +/*! + * @brief Endpoint callback function typedef. + * + * This callback function is used to notify the upper layer what the transfer result is. + * This callback pointer is passed when a specified endpoint is initialized by calling API #USB_DeviceInitEndpoint. + * + * @param handle The device handle. It equals to the value returned from #USB_DeviceInit. + * @param message The result of a transfer, which includes transfer buffer, transfer length, and whether is in a + * setup phase. + * phase for control pipe. + * @param callbackParam The parameter for this callback. It is same with + * usb_device_endpoint_callback_struct_t::callbackParam. + * + * @return A USB error code or kStatus_USB_Success. + */ +typedef usb_status_t (*usb_device_endpoint_callback_t)(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam); + +/*! + * @brief Device callback function typedef. + * + * This callback function is used to notify the upper layer that the device status has changed. + * This callback pointer is passed by calling API #USB_DeviceInit. + * + * @param handle The device handle. It equals the value returned from #USB_DeviceInit. + * @param callbackEvent The callback event type. See enumeration #usb_device_event_t. + * @param eventParam The event parameter for this callback. The parameter type is determined by the callback event. + * + * @return A USB error code or kStatus_USB_Success. + */ +typedef usb_status_t (*usb_device_callback_t)(usb_device_handle handle, uint32_t callbackEvent, void *eventParam); + +/*! @brief Endpoint callback structure */ +typedef struct _usb_device_endpoint_callback_struct +{ + usb_device_endpoint_callback_t callbackFn; /*!< Endpoint callback function*/ + void *callbackParam; /*!< Parameter for callback function*/ +} usb_device_endpoint_callback_struct_t; + +/*! @brief Endpoint initialization structure */ +typedef struct _usb_device_endpoint_init_struct +{ + uint16_t maxPacketSize; /*!< Endpoint maximum packet size */ + uint8_t endpointAddress; /*!< Endpoint address*/ + uint8_t transferType; /*!< Endpoint transfer type*/ + uint8_t zlt; /*!< ZLT flag*/ +} usb_device_endpoint_init_struct_t; + +/*! @brief Endpoint status structure */ +typedef struct _usb_device_endpoint_status_struct +{ + uint8_t endpointAddress; /*!< Endpoint address */ + uint16_t endpointStatus; /*!< Endpoint status : idle or stalled */ +} usb_device_endpoint_status_struct_t; + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @name USB device APIs + * @{ + */ + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Initializes the USB device stack. + * + * This function initializes the USB device module specified by the controllerId. + * + * @param[in] controllerId The controller ID of the USB IP. See the enumeration #usb_controller_index_t. + * @param[in] deviceCallback Function pointer of the device callback. + * @param[out] handle It is an out parameter used to return the pointer of the device handle to the caller. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. + * @retval kStatus_USB_Busy Cannot allocate a device handle. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller according to the controller id. + * @retval kStatus_USB_InvalidControllerInterface The controller driver interfaces is invalid. There is an empty + * interface entity. + * @retval kStatus_USB_Error The macro USB_DEVICE_CONFIG_ENDPOINTS is more than the IP's endpoint number. + * Or, the device has been initialized. + * Or, the mutex or message queue is created failed. + */ +extern usb_status_t USB_DeviceInit(uint8_t controllerId, + usb_device_callback_t deviceCallback, + usb_device_handle *handle); + +/*! + * @brief Enables the device functionality. + * + * The function enables the device functionality, so that the device can be recognized by the host when the device + * detects that it has been connected to a host. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is run successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + * + */ +extern usb_status_t USB_DeviceRun(usb_device_handle handle); + +/*! + * @brief Disables the device functionality. + * + * The function disables the device functionality. After this function called, even if the device is detached to the + * host, + * it can't work. + * + * @param[in] handle The device handle received from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is stopped successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer or the controller handle is invalid. + */ +extern usb_status_t USB_DeviceStop(usb_device_handle handle); + +/*! + * @brief De-initializes the device controller. + * + * The function de-initializes the device controller specified by the handle. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is stopped successfully. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer or the controller handle is invalid. + */ +extern usb_status_t USB_DeviceDeinit(usb_device_handle handle); + +/*! + * @brief Sends data through a specified endpoint. + * + * The function is used to send data through a specified endpoint. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint index. + * @param[in] buffer The memory address to hold the data need to be sent. + * @param[in] length The data length need to be sent. + * + * @retval kStatus_USB_Success The send request is sent successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Busy Cannot allocate DTDS for current transfer in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error The device is doing reset. + * + * @note The return value indicates whether the sending request is successful or not. The transfer done is notified by + * the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue on the application level. + * The subsequent transfer can begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +extern usb_status_t USB_DeviceSendRequest(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Receives data through a specified endpoint. + * + * The function is used to receive data through a specified endpoint. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint index. + * @param[in] buffer The memory address to save the received data. + * @param[in] length The data length want to be received. + * + * @retval kStatus_USB_Success The receive request is sent successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Busy Cannot allocate DTDS for current transfer in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error The device is doing reset. + * + * @note The return value indicates whether the receiving request is successful or not. The transfer done is notified by + * the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue on the application level. + * The subsequent transfer can begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +extern usb_status_t USB_DeviceRecvRequest(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Cancels the pending transfer in a specified endpoint. + * + * The function is used to cancel the pending transfer in a specified endpoint. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, and 0U - OUT. + * + * @retval kStatus_USB_Success The transfer is cancelled. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer or the controller handle is invalid. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceCancel(usb_device_handle handle, uint8_t endpointAddress); + +/*! + * @brief Initializes a specified endpoint. + * + * The function is used to initialize a specified endpoint. The corresponding endpoint callback is also initialized. + * + * @param[in] handle The device handle received from #USB_DeviceInit. + * @param[in] epInit Endpoint initialization structure. See the structure usb_device_endpoint_init_struct_t. + * @param[in] endpointCallback Endpoint callback structure. See the structure + * usb_device_endpoint_callback_struct_t. + * + * @retval kStatus_USB_Success The endpoint is initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The epInit or endpointCallback is NULL pointer. Or the endpoint number is + * more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_Busy The endpoint is busy in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceInitEndpoint(usb_device_handle handle, + usb_device_endpoint_init_struct_t *epInit, + usb_device_endpoint_callback_struct_t *endpointCallback); + +/*! + * @brief Deinitializes a specified endpoint. + * + * The function is used to deinitializes a specified endpoint. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, and 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is de-initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_Busy The endpoint is busy in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceDeinitEndpoint(usb_device_handle handle, uint8_t endpointAddress); + +/*! + * @brief Stalls a specified endpoint. + * + * The function is used to stall a specified endpoint. + * + * @param[in] handle The device handle received from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, and 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is stalled successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceStallEndpoint(usb_device_handle handle, uint8_t endpointAddress); + +/*! + * @brief Unstalls a specified endpoint. + * + * The function is used to unstall a specified endpoint. + * + * @param[in] handle The device handle received from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, and 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is unstalled successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceUnstallEndpoint(usb_device_handle handle, uint8_t endpointAddress); + +/*! + * @brief Gets the status of the selected item. + * + * The function is used to get the status of the selected item. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] type The selected item. See the structure #usb_device_status_t. + * @param[out] param The parameter type is determined by the selected item. + * + * @retval kStatus_USB_Success Get status successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The parameter is NULL pointer. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error Unsupported type. + */ +extern usb_status_t USB_DeviceGetStatus(usb_device_handle handle, usb_device_status_t type, void *param); + +/*! + * @brief Sets the status of the selected item. + * + * The function is used to set the status of the selected item. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] type The selected item. See the structure #usb_device_status_t. + * @param[in] param The parameter type is determined by the selected item. + * + * @retval kStatus_USB_Success Set status successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error Unsupported type or the parameter is NULL pointer. + */ +extern usb_status_t USB_DeviceSetStatus(usb_device_handle handle, usb_device_status_t type, void *param); + +/*! + * @brief Device task function. + * + * The function is used to handle the controller message. + * This function should not be called in the application directly. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceTaskFunction(void *deviceHandle); + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) +/*! + * @brief Device KHCI task function. + * + * The function is used to handle the KHCI controller message. + * In the bare metal environment, this function should be called periodically in the main function. + * In the RTOS environment, this function should be used as a function entry to create a task. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +#define USB_DeviceKhciTaskFunction(deviceHandle) USB_DeviceTaskFunction(deviceHandle) +#endif + +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) +/*! + * @brief Device EHCI task function. + * + * The function is used to handle the EHCI controller message. + * In the bare metal environment, this function should be called periodically in the main function. + * In the RTOS environment, this function should be used as a function entry to create a task. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +#define USB_DeviceEhciTaskFunction(deviceHandle) USB_DeviceTaskFunction(deviceHandle) +#endif + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) +/*! + * @brief Device KHCI ISR function. + * + * The function is the KHCI interrupt service routine. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceKhciIsrFunction(void *deviceHandle); +#endif + +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) +/*! + * @brief Device EHCI ISR function. + * + * The function is the EHCI interrupt service routine. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceEhciIsrFunction(void *deviceHandle); +#endif + +/*! + * @brief Gets the device stack version function. + * + * The function is used to get the device stack version. + * + * @param[out] version The version structure pointer to keep the device stack version. + * + */ +extern void USB_DeviceGetVersion(uint32_t *version); + +/*! @}*/ + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/*! @}*/ + +#endif /* __USB_DEVICE_H__ */ diff --git a/usb_1.1.0/device/usb_device_dci.c b/usb_1.1.0/device/usb_device_dci.c new file mode 100644 index 0000000..e876c24 --- /dev/null +++ b/usb_1.1.0/device/usb_device_dci.c @@ -0,0 +1,1109 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" +#include "usb_device_dci.h" + +#include "fsl_device_registers.h" + +#if ((defined(USB_DEVICE_CONFIG_NUM)) && (USB_DEVICE_CONFIG_NUM > 0U)) + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) +#include "usb_device_khci.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) +#include "usb_device_ehci.h" +#endif + +#include "usb_device_ch9.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static usb_status_t USB_DeviceAllocateHandle(uint8_t controllerId, usb_device_struct_t **handle); +static usb_status_t USB_DeviceFreeHandle(usb_device_struct_t *handle); +static usb_status_t USB_DeviceGetControllerInterface( + uint8_t controllerId, const usb_device_controller_interface_struct_t **controllerInterface); +static usb_status_t USB_DeviceTransfer(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); +static usb_status_t USB_DeviceControl(usb_device_handle handle, usb_device_control_type_t type, void *param); +static usb_status_t USB_DeviceResetNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) || \ + (defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U))) +static usb_status_t USB_DeviceSuspendNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +static usb_status_t USB_DeviceSuspendNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +#endif +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) +static usb_status_t USB_DeviceDetachNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +static usb_status_t USB_DeviceAttachNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +#endif +static usb_status_t USB_DeviceNotification(usb_device_struct_t *handle, usb_device_callback_message_struct_t *message); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +USB_GLOBAL static usb_device_struct_t s_UsbDevice[USB_DEVICE_CONFIG_NUM]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief Allocate a device handle. + * + * This function allocates a device handle. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * @param handle It is out parameter, is used to return pointer of the device handle to the caller. + * + * @retval kStatus_USB_Success Get a device handle successfully. + * @retval kStatus_USB_Busy Cannot allocate a device handle. + * @retval kStatus_USB_Error The device has been initialized. + */ +static usb_status_t USB_DeviceAllocateHandle(uint8_t controllerId, usb_device_struct_t **handle) +{ + uint32_t count; + USB_OSA_SR_ALLOC(); + + USB_OSA_ENTER_CRITICAL(); + /* Check the controller is initialized or not. */ + for (count = 0U; count < USB_DEVICE_CONFIG_NUM; count++) + { + if ((NULL != s_UsbDevice[count].controllerHandle) && (controllerId == s_UsbDevice[count].controllerId)) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_Error; + } + } + /* Get a free device handle. */ + for (count = 0U; count < USB_DEVICE_CONFIG_NUM; count++) + { + if (NULL == s_UsbDevice[count].controllerHandle) + { + s_UsbDevice[count].controllerId = controllerId; + *handle = &s_UsbDevice[count]; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_Busy; +} + +/*! + * @brief Free a device handle. + * + * This function frees a device handle. + * + * @param handle The device handle. + * + * @retval kStatus_USB_Success Free device handle successfully. + */ +static usb_status_t USB_DeviceFreeHandle(usb_device_struct_t *handle) +{ + USB_OSA_SR_ALLOC(); + + USB_OSA_ENTER_CRITICAL(); + handle->controllerHandle = NULL; + handle->controllerId = 0U; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; +} + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) +/* KHCI device driver interface */ +static const usb_device_controller_interface_struct_t s_UsbDeviceKhciInterface = { + USB_DeviceKhciInit, USB_DeviceKhciDeinit, USB_DeviceKhciSend, + USB_DeviceKhciRecv, USB_DeviceKhciCancel, USB_DeviceKhciControl}; +#endif + +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) +/* EHCI device driver interface */ +static const usb_device_controller_interface_struct_t s_UsbDeviceEhciInterface = { + USB_DeviceEhciInit, USB_DeviceEhciDeinit, USB_DeviceEhciSend, + USB_DeviceEhciRecv, USB_DeviceEhciCancel, USB_DeviceEhciControl}; +#endif + +/*! + * @brief Get the controller interface handle. + * + * This function is used to get the controller interface handle. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * @param controllerInterface It is out parameter, is used to return pointer of the device controller handle to the + * caller. + * + * @retval kStatus_USB_Success Get a device handle successfully. + * @retval kStatus_USB_ControllerNotFound The controller id is invalided. + */ +static usb_status_t USB_DeviceGetControllerInterface( + uint8_t controllerId, const usb_device_controller_interface_struct_t **controllerInterface) +{ + usb_status_t error = kStatus_USB_ControllerNotFound; + switch (controllerId) + { +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) + /* Get the KHCI controller driver interface */ + case kUSB_ControllerKhci0: + case kUSB_ControllerKhci1: + *controllerInterface = (const usb_device_controller_interface_struct_t *)&s_UsbDeviceKhciInterface; + error = kStatus_USB_Success; + break; +#endif +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) + /* Get the EHCI controller driver interface */ + case kUSB_ControllerEhci0: + case kUSB_ControllerEhci1: + error = kStatus_USB_Success; + *controllerInterface = (const usb_device_controller_interface_struct_t *)&s_UsbDeviceEhciInterface; + break; +#endif + default: + break; + } + return error; +} + +/*! + * @brief Start a new transfer. + * + * This function is used to start a new transfer. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param endpointAddress Endpoint address. Bit7 is direction, 0U - USB_OUT, 1U - USB_IN. + * @param buffer The memory address to be transferred, or the memory address to hold the data need to be + * sent. + * @param length The length of the data. + * + * @retval kStatus_USB_Success Get a device handle successfully. + * @retval kStatus_USB_InvalidHandle The device handle is invalided. + * @retval kStatus_USB_ControllerNotFound The controller interface is not found. + * @retval kStatus_USB_Error The device is doing reset. + */ +static usb_status_t USB_DeviceTransfer(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + usb_status_t error = kStatus_USB_Error; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL != deviceHandle->controllerInterface) + { + if (endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) + { +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + if (length) + { + USB_CacheFlushLines((void *)buffer, length); + } +#endif + /* Call the controller send interface. */ + error = deviceHandle->controllerInterface->deviceSend(deviceHandle->controllerHandle, endpointAddress, + buffer, length); + } + else + { +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + if (length) + { + USB_CacheInvalidateLines((void *)buffer, length); + } +#endif + /* Call the controller receive interface. */ + error = deviceHandle->controllerInterface->deviceRecv(deviceHandle->controllerHandle, endpointAddress, + buffer, length); + } + } + else + { + error = kStatus_USB_ControllerNotFound; + } + return error; +} + +/*! + * @brief Control the status of the selected item. + * + * This function is used to control the status of the selected item.. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param type The control type, please refer to the enumeration usb_device_control_type_t. + * @param param The param type is determined by the selected item. + * + * @retval kStatus_USB_Success Get a device handle successfully. + * @retval kStatus_USB_InvalidHandle The device handle is invalided. + * @retval kStatus_USB_ControllerNotFound The controller interface is not found. + * @retval kStatus_USB_Error Unsupport type. + * Or, the param is NULL pointer. + */ +static usb_status_t USB_DeviceControl(usb_device_handle handle, usb_device_control_type_t type, void *param) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + usb_status_t error = kStatus_USB_Error; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL != deviceHandle->controllerInterface) + { + /* Call the controller control interface. */ + error = deviceHandle->controllerInterface->deviceControl(deviceHandle->controllerHandle, type, param); + } + else + { + error = kStatus_USB_ControllerNotFound; + } + return error; +} + +/*! + * @brief Handle the reset notification. + * + * This function is used to handle the reset notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @retval kStatus_USB_Success Get a device handle successfully. + */ +static usb_status_t USB_DeviceResetNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + handle->isResetting = 1U; + /* Set the controller to default status. */ + USB_DeviceControl(handle, kUSB_DeviceControlSetDefaultStatus, NULL); + + handle->state = kUSB_DeviceStateDefault; + handle->deviceAddress = 0U; + + for (uint32_t count = 0U; count < (USB_DEVICE_CONFIG_ENDPOINTS * 2U); count++) + { + handle->endpointCallback[count].callbackFn = (usb_device_endpoint_callback_t)NULL; + handle->endpointCallback[count].callbackParam = NULL; + } + + /* Call device callback to notify the application that the USB bus reset signal detected. */ + handle->deviceCallback(handle, kUSB_DeviceEventBusReset, NULL); + + handle->isResetting = 0U; + return kStatus_USB_Success; +} + +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) || \ + (defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U))) +/*! + * @brief Handle the suspend notification. + * + * This function is used to handle the suspend notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceSuspendNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the USB bus suspend signal detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventSuspend, NULL); +} + +/*! + * @brief Handle the resume notification. + * + * This function is used to handle the resume notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceResumeNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the USB bus resume signal detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventResume, NULL); +} + +#endif + +#if (defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) || \ + (defined(USB_DEVICE_CONFIG_EHCI_ERROR_HANDLING) && USB_DEVICE_CONFIG_EHCI_ERROR_HANDLING) +usb_status_t USB_DeviceErrorNotification(usb_device_struct_t *handle, usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the USB bus error signal detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventError, NULL); +} +#endif + +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) +/*! + * @brief Handle the detach notification. + * + * This function is used to handle the detach notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceDetachNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the device is disconnected from a host. */ + return handle->deviceCallback(handle, kUSB_DeviceEventDetach, NULL); +} + +/*! + * @brief Handle the attach notification. + * + * This function is used to handle the attach notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceAttachNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the device is connected to a host. */ + return handle->deviceCallback(handle, kUSB_DeviceEventAttach, NULL); +} +#endif + +/*! + * @brief Handle the attach notification. + * + * This function is used to handle the attach notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceNotification(usb_device_struct_t *handle, usb_device_callback_message_struct_t *message) +{ + uint8_t endpoint = message->code & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = (message->code & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + usb_status_t error = kStatus_USB_Error; + + switch (message->code) + { + case kUSB_DeviceNotifyBusReset: + error = USB_DeviceResetNotification(handle, message); + break; +#if ((USB_DEVICE_CONFIG_LOW_POWER_MODE) || (USB_DEVICE_CONFIG_REMOTE_WAKEUP)) + case kUSB_DeviceNotifySuspend: + error = USB_DeviceSuspendNotification(handle, message); + break; + case kUSB_DeviceNotifyResume: + error = USB_DeviceResumeNotification(handle, message); + break; +#endif + +#if (defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) || \ + (defined(USB_DEVICE_CONFIG_EHCI_ERROR_HANDLING) && USB_DEVICE_CONFIG_EHCI_ERROR_HANDLING) + case kUSB_DeviceNotifyError: + error = USB_DeviceErrorNotification(handle, message); + break; +#endif + +#if USB_DEVICE_CONFIG_DETACH_ENABLE + case kUSB_DeviceNotifyDetach: + error = USB_DeviceDetachNotification(handle, message); + break; + case kUSB_DeviceNotifyAttach: + error = USB_DeviceAttachNotification(handle, message); + break; +#endif + default: + if (endpoint < USB_DEVICE_CONFIG_ENDPOINTS) + { + if (handle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn) + { + usb_device_endpoint_callback_message_struct_t endpointCallbackMessage; + endpointCallbackMessage.buffer = message->buffer; + endpointCallbackMessage.length = message->length; + endpointCallbackMessage.isSetup = message->isSetup; + /* Call endpoint callback */ + error = handle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn( + handle, &endpointCallbackMessage, + handle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackParam); + } + } + break; + } + return error; +} + +/*! + * @brief Notify the device that the controller status changed. + * + * This function is used to notify the device that the controller status changed. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + usb_device_callback_message_struct_t *message = (usb_device_callback_message_struct_t *)msg; + + if ((NULL == msg) || (NULL == handle)) + { + return kStatus_USB_InvalidHandle; + } + + /* The device callback is invalid or not. */ + if (!deviceHandle->deviceCallback) + { + return kStatus_USB_Error; + } + +#if USB_DEVICE_CONFIG_USE_TASK + if (deviceHandle->isResetting) + { + if ((message->code & USB_ENDPOINT_NUMBER_MASK) && (!(message->code & 0x70U))) + { + return USB_DeviceNotification(deviceHandle, message); + } + } + + /* Add the message to message queue when the device task is enabled. */ + if (kStatus_USB_OSA_Success != USB_OsaMsgqSend(deviceHandle->notificationQueue, (void *)message)) + { + return kStatus_USB_Busy; + } + return kStatus_USB_Success; +#else + /* Handle the notification by calling USB_DeviceNotification. */ + return USB_DeviceNotification(deviceHandle, message); +#endif +} + +/*! + * @brief Initialize the USB device stack. + * + * This function initializes the USB device module specified by the controllerId. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * @param deviceCallback Function pointer of the device callback. + * @param handle It is out parameter, is used to return pointer of the device handle to the caller. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. + * @retval kStatus_USB_Busy Cannot allocate a device handle. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller according to the controller id. + * @retval kStatus_USB_InvalidControllerInterface The controller driver interfaces is invaild, There is an empty + * interface entity. + * @retval kStatus_USB_Error The macro USB_DEVICE_CONFIG_ENDPOINTS is more than IP's endpoint number. + * Or, the device has been initialized. + * Or, the message queue is created failed. + */ +usb_status_t USB_DeviceInit(uint8_t controllerId, usb_device_callback_t deviceCallback, usb_device_handle *handle) +{ + usb_device_struct_t *deviceHandle = NULL; + usb_status_t error; + uint32_t count; + + if (NULL == handle) + { + return kStatus_USB_InvalidHandle; + } + + /* Allocate a device handle by using the controller id. */ + error = USB_DeviceAllocateHandle(controllerId, &deviceHandle); + + if (kStatus_USB_Success != error) + { + return error; + } + + /* Save the device callback */ + deviceHandle->deviceCallback = deviceCallback; + /* Save the controller id */ + deviceHandle->controllerId = controllerId; + /* Clear the device address */ + deviceHandle->deviceAddress = 0U; + /* Clear the device reset state */ + deviceHandle->isResetting = 0U; + + /* Initialize the enpoints */ + for (count = 0U; count < (USB_DEVICE_CONFIG_ENDPOINTS * 2U); count++) + { + deviceHandle->endpointCallback[count].callbackFn = (usb_device_endpoint_callback_t)NULL; + deviceHandle->endpointCallback[count].callbackParam = NULL; + } + + /* Get the controller interface according to the controller id */ + error = USB_DeviceGetControllerInterface(controllerId, &deviceHandle->controllerInterface); + if (kStatus_USB_Success != error) + { + USB_DeviceFreeHandle(deviceHandle); + return error; + } + if (NULL == deviceHandle->controllerInterface) + { + USB_DeviceFreeHandle(deviceHandle); + return kStatus_USB_ControllerNotFound; + } + if (((usb_device_controller_init_t)NULL == deviceHandle->controllerInterface->deviceInit) || + ((usb_device_controller_deinit_t)NULL == deviceHandle->controllerInterface->deviceDeinit) || + ((usb_device_controller_send_t)NULL == deviceHandle->controllerInterface->deviceSend) || + ((usb_device_controller_recv_t)NULL == deviceHandle->controllerInterface->deviceRecv) || + ((usb_device_controller_cancel_t)NULL == deviceHandle->controllerInterface->deviceCancel) || + ((usb_device_controller_control_t)NULL == deviceHandle->controllerInterface->deviceControl)) + { + USB_DeviceFreeHandle(deviceHandle); + return kStatus_USB_InvalidControllerInterface; + } + +#if USB_DEVICE_CONFIG_USE_TASK + /* Create a message queue when the device handle is enabled. */ + if (kStatus_USB_OSA_Success != + USB_OsaMsgqCreate(&deviceHandle->notificationQueue, USB_DEVICE_CONFIG_MAX_MESSAGES, + (1U + (sizeof(usb_device_callback_message_struct_t) - 1U) / sizeof(uint32_t)))) + { + USB_DeviceDeinit(deviceHandle); + return kStatus_USB_Error; + } +#endif + /* Initialize the controller */ + error = deviceHandle->controllerInterface->deviceInit(controllerId, deviceHandle, &deviceHandle->controllerHandle); + if (kStatus_USB_Success != error) + { + USB_DeviceDeinit(deviceHandle); + return error; + } + /* Set the device to deafult state */ + deviceHandle->state = kUSB_DeviceStateDefault; + *handle = deviceHandle; + + return error; +} + +/*! + * @brief Enable the device functionality. + * + * The function enables the device functionality, so that the device can be recognized by the host when the device + * detects that it has been connected to a host. + * + * @param handle The device handle got from USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is run successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + * + */ +usb_status_t USB_DeviceRun(usb_device_handle handle) +{ + return USB_DeviceControl(handle, kUSB_DeviceControlRun, NULL); +} +/*! + * @brief Disable the device functionality. + * + * The function disables the device functionality, after this function called, even the device is detached to the host, + * and the device can't work. + * + * @param handle The device handle got from USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is stopped successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + */ +usb_status_t USB_DeviceStop(usb_device_handle handle) +{ + return USB_DeviceControl(handle, kUSB_DeviceControlStop, NULL); +} +/*! + * @brief De-initialize the device controller. + * + * The function de-initializes the device controller specified by the handle. + * + * @param handle The device handle got from USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is stopped successfully. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + */ +usb_status_t USB_DeviceDeinit(usb_device_handle handle) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + /* De-initialize the controller */ + if (NULL != deviceHandle->controllerInterface) + { + deviceHandle->controllerInterface->deviceDeinit(deviceHandle->controllerHandle); + deviceHandle->controllerInterface = (usb_device_controller_interface_struct_t *)NULL; + } + +#if USB_DEVICE_CONFIG_USE_TASK + /* Destroy the message queue. */ + if (NULL != deviceHandle->notificationQueue) + { + USB_OsaMsgqDestroy(deviceHandle->notificationQueue); + deviceHandle->notificationQueue = NULL; + } +#endif + + /* Free the device handle. */ + USB_DeviceFreeHandle(deviceHandle); + return kStatus_USB_Success; +} + +/*! + * @brief Send data through a specified endpoint. + * + * The function is used to send data through a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint index. + * @param buffer The memory address to hold the data need to be sent. + * @param length The data length need to be sent. + * + * @retval kStatus_USB_Success The send request is sent successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Busy Cannot allocate dtds for current tansfer in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error The device is doing reset. + * + * @note The return value just means if the sending request is successful or not; the transfer done is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +usb_status_t USB_DeviceSendRequest(usb_device_handle handle, uint8_t endpointAddress, uint8_t *buffer, uint32_t length) +{ + return USB_DeviceTransfer(handle, (endpointAddress & USB_ENDPOINT_NUMBER_MASK) | + (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT), + buffer, length); +} + +/*! + * @brief Receive data through a specified endpoint. + * + * The function is used to receive data through a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint index. + * @param buffer The memory address to save the received data. + * @param length The data length want to be received. + * + * @retval kStatus_USB_Success The receive request is sent successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Busy Cannot allocate dtds for current tansfer in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error The device is doing reset. + * + * @note The return value just means if the receiving request is successful or not; the transfer done is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +usb_status_t USB_DeviceRecvRequest(usb_device_handle handle, uint8_t endpointAddress, uint8_t *buffer, uint32_t length) +{ + return USB_DeviceTransfer(handle, (endpointAddress & USB_ENDPOINT_NUMBER_MASK) | + (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT), + buffer, length); +} + +/*! + * @brief Cancel the pending transfer in a specified endpoint. + * + * The function is used to cancel the pending transfer in a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @retval kStatus_USB_Success The transfer is cancelled. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceCancel(usb_device_handle handle, uint8_t endpointAddress) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + usb_status_t error = kStatus_USB_Error; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL != deviceHandle->controllerInterface) + { + error = deviceHandle->controllerInterface->deviceCancel(deviceHandle->controllerHandle, endpointAddress); + } + else + { + error = kStatus_USB_ControllerNotFound; + } + return error; +} + +/*! + * @brief Initialize a specified endpoint. + * + * The function is used to initialize a specified endpoint and the corresponding endpoint callback is also initialized. + * + * @param handle The device handle got from USB_DeviceInit. + * @param epInit Endpoint initizlization structure. Please refer to the structure usb_device_endpoint_init_struct_t. + * @param endpointCallback Endpoint callback structure. Please refer to the structure + * usb_device_endpoint_callback_struct_t. + * + * @retval kStatus_USB_Success The endpoint is initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The epInit or endpointCallback is NULL pointer. Or the endpoint number is + * more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_Busy The endpoint is busy in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceInitEndpoint(usb_device_handle handle, + usb_device_endpoint_init_struct_t *epInit, + usb_device_endpoint_callback_struct_t *endpointCallback) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + uint8_t endpoint; + uint8_t direction; + + if (!deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if ((!epInit) || (!endpointCallback)) + { + return kStatus_USB_InvalidParameter; + } + + endpoint = epInit->endpointAddress & USB_ENDPOINT_NUMBER_MASK; + direction = (epInit->endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + + if (endpoint < USB_DEVICE_CONFIG_ENDPOINTS) + { + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn = + endpointCallback->callbackFn; + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackParam = + endpointCallback->callbackParam; + } + else + { + return kStatus_USB_InvalidParameter; + } + return USB_DeviceControl(handle, kUSB_DeviceControlEndpointInit, epInit); +} + +/*! + * @brief De-initizlize a specified endpoint. + * + * The function is used to de-initizlize a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is de-initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_Busy The endpoint is busy in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceDeinitEndpoint(usb_device_handle handle, uint8_t endpointAddress) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + uint8_t endpoint = endpointAddress & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = (endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + usb_status_t error = kStatus_USB_Error; + + if (!deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + error = USB_DeviceControl(handle, kUSB_DeviceControlEndpointDeinit, &endpointAddress); + if (endpoint < USB_DEVICE_CONFIG_ENDPOINTS) + { + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn = + (usb_device_endpoint_callback_t)NULL; + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackParam = NULL; + } + else + { + return kStatus_USB_InvalidParameter; + } + return error; +} + +/*! + * @brief Stall a specified endpoint. + * + * The function is used to stall a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is stalled successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceStallEndpoint(usb_device_handle handle, uint8_t endpointAddress) +{ + if ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) < USB_DEVICE_CONFIG_ENDPOINTS) + { + return USB_DeviceControl(handle, kUSB_DeviceControlEndpointStall, &endpointAddress); + } + else + { + return kStatus_USB_InvalidParameter; + } +} + +/*! + * @brief Un-stall a specified endpoint. + * + * The function is used to un-stall a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is un-stalled successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceUnstallEndpoint(usb_device_handle handle, uint8_t endpointAddress) +{ + if ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) < USB_DEVICE_CONFIG_ENDPOINTS) + { + return USB_DeviceControl(handle, kUSB_DeviceControlEndpointUnstall, &endpointAddress); + } + else + { + return kStatus_USB_InvalidParameter; + } +} + +/*! + * @brief Get the status of the selected item. + * + * The function is used to get the status of the selected item. + * + * @param handle The device handle got from USB_DeviceInit. + * @param type The selected item. Please refer to the structure usb_device_status_t. + * @param param The param type is determined by the selected item. + * + * @retval kStatus_USB_Success Get status successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The param is NULL pointer. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error Unsupported type. + */ +usb_status_t USB_DeviceGetStatus(usb_device_handle handle, usb_device_status_t type, void *param) +{ + uint8_t *temp8; + usb_status_t error = kStatus_USB_Error; + + if (NULL == param) + { + return kStatus_USB_InvalidParameter; + } + switch (type) + { + case kUSB_DeviceStatusSpeed: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetSpeed, param); + break; + case kUSB_DeviceStatusOtg: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetOtgStatus, param); + break; + case kUSB_DeviceStatusDeviceState: + temp8 = (uint8_t *)param; + error = kStatus_USB_Success; + *temp8 = ((usb_device_struct_t *)handle)->state; + break; + case kUSB_DeviceStatusAddress: + temp8 = (uint8_t *)param; + error = kStatus_USB_Success; + *temp8 = ((usb_device_struct_t *)handle)->deviceAddress; + break; + case kUSB_DeviceStatusDevice: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetDeviceStatus, param); + break; + case kUSB_DeviceStatusEndpoint: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetEndpointStatus, param); + break; + case kUSB_DeviceStatusSynchFrame: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetSynchFrame, param); + break; + default: + break; + } + return error; +} + +/*! + * @brief Set the status of the selected item. + * + * The function is used to set the status of the selected item. + * + * @param handle The device handle got from USB_DeviceInit. + * @param type The selected item. Please refer to the structure usb_device_status_t. + * @param param The param type is determined by the selected item. + * + * @retval kStatus_USB_Success Set status successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error Unsupported type, or the param is NULL pointer. + */ +usb_status_t USB_DeviceSetStatus(usb_device_handle handle, usb_device_status_t type, void *param) +{ + usb_status_t error = kStatus_USB_Error; + switch (type) + { +#if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) && \ + (defined(USB_DEVICE_CONFIG_EHCI_TEST_MODE) && (USB_DEVICE_CONFIG_EHCI_TEST_MODE > 0U)) + case kUSB_DeviceStatusTestMode: + error = USB_DeviceControl(handle, kUSB_DeviceControlSetTestMode, param); + break; +#endif + case kUSB_DeviceStatusOtg: + error = USB_DeviceControl(handle, kUSB_DeviceControlSetOtgStatus, param); + break; + case kUSB_DeviceStatusDeviceState: + if (NULL != param) + { + error = kStatus_USB_Success; + ((usb_device_struct_t *)handle)->state = (uint8_t)(*(uint8_t *)param); + } + break; + case kUSB_DeviceStatusAddress: + if (kUSB_DeviceStateAddressing != ((usb_device_struct_t *)handle)->state) + { + if (NULL != param) + { + error = kStatus_USB_Success; + ((usb_device_struct_t *)handle)->deviceAddress = (uint8_t)(*(uint8_t *)param); + ((usb_device_struct_t *)handle)->state = kUSB_DeviceStateAddressing; + } + } + else + { + error = USB_DeviceControl(handle, kUSB_DeviceControlSetDeviceAddress, + &((usb_device_struct_t *)handle)->deviceAddress); + } + break; + case kUSB_DeviceStatusBus: + error = USB_DeviceControl(handle, kUSB_DeviceControlResume, param); + break; + default: + break; + } + return error; +} + +#if USB_DEVICE_CONFIG_USE_TASK +/*! + * @brief Device task function. + * + * The function is used to handle controller message. + * This function should not be called in applicartion directly. + * + * @param handle The device handle got from USB_DeviceInit. + */ +void USB_DeviceTaskFunction(void *deviceHandle) +{ + usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle; + static usb_device_callback_message_struct_t message; + + if (deviceHandle) + { + /* Get the message from the queue */ + if (kStatus_USB_OSA_Success == USB_OsaMsgqRecv(handle->notificationQueue, (uint32_t *)&message, 0U)) + { + /* Handle the message */ + USB_DeviceNotification(handle, &message); + } + } +} +#endif + +/*! + * @brief Get dvice stack version function. + * + * The function is used to get dvice stack version. + * + * @param[out] version The version structure pointer to keep the device stack version. + * + */ +void USB_DeviceGetVersion(uint32_t *version) +{ + if (version) + { + *version = + (uint32_t)USB_MAKE_VERSION(USB_STACK_VERSION_MAJOR, USB_STACK_VERSION_MINOR, USB_STACK_VERSION_BUGFIX); + } +} +#endif /* USB_DEVICE_CONFIG_NUM */ diff --git a/usb_1.1.0/device/usb_device_dci.h b/usb_1.1.0/device/usb_device_dci.h new file mode 100644 index 0000000..03f3618 --- /dev/null +++ b/usb_1.1.0/device/usb_device_dci.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_DEVICE_DCI_H__ +#define __USB_DEVICE_DCI_H__ + +/*! + * @addtogroup usb_device_controller_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Macro to define controller handle */ +#define usb_device_controller_handle usb_device_handle + +/*! @brief Available notify types for device notification */ +typedef enum _usb_device_notification +{ + kUSB_DeviceNotifyBusReset = 0x10U, /*!< Reset signal detected */ + kUSB_DeviceNotifySuspend, /*!< Suspend signal detected */ + kUSB_DeviceNotifyResume, /*!< Resume signal detected */ + kUSB_DeviceNotifyError, /*!< Errors happened in bus */ + kUSB_DeviceNotifyDetach, /*!< Device disconnected from a host */ + kUSB_DeviceNotifyAttach, /*!< Device connected to a host */ +} usb_device_notification_t; + +/*! @brief Device notification message structure */ +typedef struct _usb_device_callback_message_struct +{ + uint8_t *buffer; /*!< Transferred buffer */ + uint32_t length; /*!< Transferred data length */ + uint8_t code; /*!< Notification code */ + uint8_t isSetup; /*!< Is in a setup phase */ +} usb_device_callback_message_struct_t; + +/*! @brief Control type for controller */ +typedef enum _usb_device_control_type +{ + kUSB_DeviceControlRun = 0U, /*!< Enable the device functionality */ + kUSB_DeviceControlStop, /*!< Disable the device functionality */ + kUSB_DeviceControlEndpointInit, /*!< Initialize a specified endpoint */ + kUSB_DeviceControlEndpointDeinit, /*!< De-initialize a specified endpoint */ + kUSB_DeviceControlEndpointStall, /*!< Stall a specified endpoint */ + kUSB_DeviceControlEndpointUnstall, /*!< Unstall a specified endpoint */ + kUSB_DeviceControlGetDeviceStatus, /*!< Get device status */ + kUSB_DeviceControlGetEndpointStatus, /*!< Get endpoint status */ + kUSB_DeviceControlSetDeviceAddress, /*!< Set device address */ + kUSB_DeviceControlGetSynchFrame, /*!< Get current frame */ + kUSB_DeviceControlResume, /*!< Drive controller to generate a resume signal in USB bus */ + kUSB_DeviceControlSetDefaultStatus, /*!< Set controller to default status */ + kUSB_DeviceControlGetSpeed, /*!< Get current speed */ + kUSB_DeviceControlGetOtgStatus, /*!< Get OTG status */ + kUSB_DeviceControlSetOtgStatus, /*!< Set OTG status */ + kUSB_DeviceControlSetTestMode, /*!< Drive xCHI into test mode */ +} usb_device_control_type_t; + +/*! @brief USB device controller initialization function typedef */ +typedef usb_status_t (*usb_device_controller_init_t)(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *controllerHandle); + +/*! @brief USB device controller de-initialization function typedef */ +typedef usb_status_t (*usb_device_controller_deinit_t)(usb_device_controller_handle controllerHandle); + +/*! @brief USB device controller send data function typedef */ +typedef usb_status_t (*usb_device_controller_send_t)(usb_device_controller_handle controllerHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! @brief USB device controller receive data function typedef */ +typedef usb_status_t (*usb_device_controller_recv_t)(usb_device_controller_handle controllerHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! @brief USB device controller cancel transfer function in a specified endpoint typedef */ +typedef usb_status_t (*usb_device_controller_cancel_t)(usb_device_controller_handle controllerHandle, + uint8_t endpointAddress); + +/*! @brief USB device controller control function typedef */ +typedef usb_status_t (*usb_device_controller_control_t)(usb_device_controller_handle controllerHandle, + usb_device_control_type_t command, + void *param); + +/*! @brief USB device controller interface structure */ +typedef struct _usb_device_controller_interface_struct +{ + usb_device_controller_init_t deviceInit; /*!< Controller initialization */ + usb_device_controller_deinit_t deviceDeinit; /*!< Controller de-initialization */ + usb_device_controller_send_t deviceSend; /*!< Controller send data */ + usb_device_controller_recv_t deviceRecv; /*!< Controller receive data */ + usb_device_controller_cancel_t deviceCancel; /*!< Controller cancel transfer */ + usb_device_controller_control_t deviceControl; /*!< Controller control */ +} usb_device_controller_interface_struct_t; + +/*! @brief USB device status structure */ +typedef struct _usb_device_struct +{ + usb_device_controller_handle controllerHandle; /*!< Controller handle */ + const usb_device_controller_interface_struct_t *controllerInterface; /*!< Controller interface handle */ +#if USB_DEVICE_CONFIG_USE_TASK + usb_osa_msgq_handle notificationQueue; /*!< Message queue */ +#endif + usb_device_callback_t deviceCallback; /*!< Device callback function pointer */ + usb_device_endpoint_callback_struct_t + endpointCallback[USB_DEVICE_CONFIG_ENDPOINTS << 1U]; /*!< Endpoint callback function structure */ + uint8_t deviceAddress; /*!< Current device address */ + uint8_t controllerId; /*!< Controller ID */ + uint8_t state; /*!< Current device state */ + uint8_t isResetting; /*!< Is doing device reset or not */ +} usb_device_struct_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! @}*/ + +#endif /* __USB_DEVICE_DCI_H__ */ diff --git a/usb_1.1.0/device/usb_device_khci.c b/usb_1.1.0/device/usb_device_khci.c new file mode 100644 index 0000000..fcafe97 --- /dev/null +++ b/usb_1.1.0/device/usb_device_khci.c @@ -0,0 +1,1355 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" + +#include "fsl_device_registers.h" + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) + +#include "usb_khci.h" +#include "usb_device_dci.h" + +#include "usb_device_khci.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static usb_status_t USB_DeviceKhciEndpointTransfer( + usb_device_khci_state_struct_t *khciState, uint8_t endpoint, uint8_t direction, uint8_t *buffer, uint32_t length); +static void USB_DeviceKhciPrimeNextSetup(usb_device_khci_state_struct_t *khciState); +static void USB_DeviceKhciSetDefaultState(usb_device_khci_state_struct_t *khciState); +static usb_status_t USB_DeviceKhciEndpointInit(usb_device_khci_state_struct_t *khciState, + usb_device_endpoint_init_struct_t *epInit); +static usb_status_t USB_DeviceKhciEndpointDeinit(usb_device_khci_state_struct_t *khciState, uint8_t ep); +static usb_status_t USB_DeviceKhciEndpointStall(usb_device_khci_state_struct_t *khciState, uint8_t ep); +static usb_status_t USB_DeviceKhciEndpointUnstall(usb_device_khci_state_struct_t *khciState, uint8_t ep); +static void USB_DeviceKhciInterruptTokenDone(usb_device_khci_state_struct_t *khciState); +static void USB_DeviceKhciInterruptReset(usb_device_khci_state_struct_t *khciState); +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) || \ + (defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U))) +static void USB_DeviceKhciInterruptSleep(usb_device_khci_state_struct_t *khciState); +static void USB_DeviceKhciInterruptResume(usb_device_khci_state_struct_t *khciState); +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE || USB_DEVICE_CONFIG_REMOTE_WAKEUP */ +static void USB_DeviceKhciInterruptStall(usb_device_khci_state_struct_t *khciState); +#if defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && (USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING > 0U) +static void USB_DeviceKhciInterruptError(usb_device_khci_state_struct_t *khciState); +#endif /* USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING */ + +extern usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* Apply for BDT buffer, 512-byte alignment */ +USB_RAM_ADDRESS_ALGINMENT_512 USB_BDT static uint8_t s_UsbDeviceKhciBdtBuffer[USB_DEVICE_CONFIG_KHCI][512U]; + +/* Apply for khci device state structure */ +USB_GLOBAL static usb_device_khci_state_struct_t s_UsbDeviceKhciState[USB_DEVICE_CONFIG_KHCI]; +/* Apply for KHCI DMA aligned buffer when marco USB_DEVICE_CONFIG_KHCI_DMA_ALIGN enabled */ +USB_GLOBAL static uint32_t s_UsbDeviceKhciDmaAlignBuffer + [USB_DEVICE_CONFIG_KHCI][((USB_DEVICE_CONFIG_KHCI_DMA_ALIGN_BUFFER_LENGTH - 1U) >> 2U) + 1U]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief Write the BDT to start a transfer. + * + * The function is used to start a transfer by writing the BDT. + * + * @param khciState Pointer of the device KHCI state structure. + * @param endpoint Endpoint number. + * @param direction The direction of the endpoint, 0U - USB_OUT, 1U - USB_IN. + * @param buffer The memory address to save the received data, or the memory address to hold the data need to + * be sent. + * @param length The length of the data. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointTransfer( + usb_device_khci_state_struct_t *khciState, uint8_t endpoint, uint8_t direction, uint8_t *buffer, uint32_t length) +{ + uint32_t index = ((uint32_t)endpoint << 1U) | (uint32_t)direction; + USB_OSA_SR_ALLOC(); + + /* Enter critical */ + USB_OSA_ENTER_CRITICAL(); + + /* Flag the endpoint is busy. */ + khciState->endpointState[index].stateUnion.stateBitField.transferring = 1U; + + /* Add the data buffer address to the BDT. */ + USB_KHCI_BDT_SET_ADDRESS((uint32_t)khciState->bdt, endpoint, direction, + khciState->endpointState[index].stateUnion.stateBitField.bdtOdd, (uint32_t)buffer); + + /* Change the BDT control field to start the transfer. */ + USB_KHCI_BDT_SET_CONTROL( + (uint32_t)khciState->bdt, endpoint, direction, khciState->endpointState[index].stateUnion.stateBitField.bdtOdd, + USB_LONG_TO_LITTLE_ENDIAN(USB_KHCI_BDT_BC(length) | USB_KHCI_BDT_OWN | USB_KHCI_BDT_DTS | + USB_KHCI_BDT_DATA01(khciState->endpointState[index].stateUnion.stateBitField.data0))); + + /* Exit critical */ + USB_OSA_EXIT_CRITICAL(); + + /* Clear the token busy state */ + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; + return kStatus_USB_Success; +} + +/*! + * @brief Prime a next setup transfer. + * + * The function is used to prime a buffer in control out pipe to wait for receiving the host's setup packet. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciPrimeNextSetup(usb_device_khci_state_struct_t *khciState) +{ +/* Update the endpoint state */ +/* Save the buffer address used to receive the setup packet. */ +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) \ +&& defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && \ + (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && defined(FSL_FEATURE_USB_KHCI_USB_RAM) && \ + (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + /* In case of lowpower mode enabled, it requires to put the setup packet buffer(16 bytes) into the USB RAM so + * that the setup packet would wake up the USB. + */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferBuffer = + (uint8_t *)(khciState->bdt + 0x200U - 0x10U) + + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.bdtOdd * + USB_SETUP_PACKET_SIZE; +#else + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferBuffer = + (uint8_t *)&khciState->setupPacketBuffer[0] + + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.bdtOdd * + USB_SETUP_PACKET_SIZE; +#endif + /* Clear the transferred length. */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferDone = 0U; + /* Save the data length expected to get from a host. */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferLength = USB_SETUP_PACKET_SIZE; + /* Save the data buffer DMA align flag. */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.dmaAlign = 1U; + /* Set the DATA0/1 to DATA0. */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.data0 = 0U; + + USB_DeviceKhciEndpointTransfer(khciState, USB_CONTROL_ENDPOINT, USB_OUT, + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferBuffer, + USB_SETUP_PACKET_SIZE); +} + +/*! + * @brief Set device controller state to default state. + * + * The function is used to set device controller state to default state. + * The function will be called when USB_DeviceKhciInit called or the control type kUSB_DeviceControlGetEndpointStatus + * received in USB_DeviceKhciControl. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciSetDefaultState(usb_device_khci_state_struct_t *khciState) +{ + uint8_t interruptFlag; + + /* Clear the error state register */ + khciState->registerBase->ERRSTAT = 0xFFU; + + /* Setting this bit to 1U resets all the BDT ODD ping/pong fields to 0U, which then specifies the EVEN BDT bank. */ + khciState->registerBase->CTL |= USB_CTL_ODDRST_MASK; + + /* Clear the device address */ + khciState->registerBase->ADDR = 0U; + + /* Clear the endpoint state and disable the endpoint */ + for (uint8_t count = 0U; count < USB_DEVICE_CONFIG_ENDPOINTS; count++) + { + USB_KHCI_BDT_SET_CONTROL((uint32_t)khciState->bdt, count, USB_OUT, 0U, 0U); + USB_KHCI_BDT_SET_CONTROL((uint32_t)khciState->bdt, count, USB_OUT, 1U, 0U); + USB_KHCI_BDT_SET_CONTROL((uint32_t)khciState->bdt, count, USB_IN, 0U, 0U); + USB_KHCI_BDT_SET_CONTROL((uint32_t)khciState->bdt, count, USB_IN, 1U, 0U); + + khciState->endpointState[((uint32_t)count << 1U) | USB_OUT].stateUnion.state = 0U; + khciState->endpointState[((uint32_t)count << 1U) | USB_IN].stateUnion.state = 0U; + khciState->registerBase->ENDPOINT[count].ENDPT = 0x00U; + } + khciState->isDmaAlignBufferInusing = 0U; + + /* Clear the BDT odd reset flag */ + khciState->registerBase->CTL &= ~USB_CTL_ODDRST_MASK; + + /* Enable all error */ + khciState->registerBase->ERREN = 0xFFU; + + /* Enable reset, sof, token, stall interrupt */ + interruptFlag = kUSB_KhciInterruptReset +#if 0U + | kUSB_KhciInterruptSofToken +#endif + | kUSB_KhciInterruptTokenDone | kUSB_KhciInterruptStall; + +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) || \ + (defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U))) + /* Enable suspend interruprt */ + interruptFlag |= kUSB_KhciInterruptSleep; +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE || USB_DEVICE_CONFIG_REMOTE_WAKEUP */ + +#if defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && (USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING > 0U) + /* Enable error interruprt */ + interruptFlag |= kUSB_KhciInterruptError; +#endif /* USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING */ + /* Write the interrupt enable register */ + khciState->registerBase->INTEN = interruptFlag; + + /* Clear reset flag */ + khciState->isResetting = 0U; + + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; +} + +/*! + * @brief Initialize a specified endpoint. + * + * The function is used to initialize a specified endpoint. + * + * @param khciState Pointer of the device KHCI state structure. + * @param epInit The endpoint initialization structure pointer. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointInit(usb_device_khci_state_struct_t *khciState, + usb_device_endpoint_init_struct_t *epInit) +{ + uint16_t maxPacketSize = epInit->maxPacketSize; + uint8_t endpoint = (epInit->endpointAddress & USB_ENDPOINT_NUMBER_MASK); + uint8_t direction = (epInit->endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + uint8_t index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + /* Make the endpoint max packet size align with USB Specification 2.0. */ + if (USB_ENDPOINT_ISOCHRONOUS == epInit->transferType) + { + if (maxPacketSize > USB_DEVICE_MAX_FS_ISO_MAX_PACKET_SIZE) + { + maxPacketSize = USB_DEVICE_MAX_FS_ISO_MAX_PACKET_SIZE; + } + } + else + { + if (maxPacketSize > USB_DEVICE_MAX_FS_NONE_ISO_MAX_PACKET_SIZE) + { + maxPacketSize = USB_DEVICE_MAX_FS_NONE_ISO_MAX_PACKET_SIZE; + } + /* Enable an endpoint to perform handshaking during a transaction to this endpoint. */ + khciState->registerBase->ENDPOINT[endpoint].ENDPT |= USB_ENDPT_EPHSHK_MASK; + } + /* Set the endpoint idle */ + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + /* Save the max packet size of the endpoint */ + khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize = maxPacketSize; + /* Set the data toggle to DATA0 */ + khciState->endpointState[index].stateUnion.stateBitField.data0 = 0U; + /* Clear the endpoint stalled state */ + khciState->endpointState[index].stateUnion.stateBitField.stalled = 0U; + /* Enable the endpoint. */ + khciState->registerBase->ENDPOINT[endpoint].ENDPT |= + (USB_IN == direction) ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK; + + /* Prime a transfer to receive next setup packet when the endpoint is control out endpoint. */ + if ((USB_CONTROL_ENDPOINT == endpoint) && (USB_OUT == direction)) + { + USB_DeviceKhciPrimeNextSetup(khciState); + } + + return kStatus_USB_Success; +} + +/*! + * @brief De-initialize a specified endpoint. + * + * The function is used to de-initialize a specified endpoint. + * Current transfer of the endpoint will be canceled and the specified endpoint will be disabled. + * + * @param khciState Pointer of the device KHCI state structure. + * @param ep The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointDeinit(usb_device_khci_state_struct_t *khciState, uint8_t ep) +{ + uint8_t endpoint = (ep & USB_ENDPOINT_NUMBER_MASK); + uint8_t direction = + (ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + uint8_t index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + /* Cancel the transfer of the endpoint */ + USB_DeviceKhciCancel(khciState, ep); + + /* Disable the endpoint */ + khciState->registerBase->ENDPOINT[endpoint].ENDPT = 0x00U; + /* Clear the max packet size */ + khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize = 0U; + + return kStatus_USB_Success; +} + +/*! + * @brief Stall a specified endpoint. + * + * The function is used to stall a specified endpoint. + * Current transfer of the endpoint will be canceled and the specified endpoint will be stalled. + * + * @param khciState Pointer of the device KHCI state structure. + * @param ep The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointStall(usb_device_khci_state_struct_t *khciState, uint8_t ep) +{ + uint8_t endpoint = ep & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = + (ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + uint8_t index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + /* Cancel the transfer of the endpoint */ + USB_DeviceKhciCancel(khciState, ep); + + /* Set endpoint stall flag. */ + khciState->endpointState[index].stateUnion.stateBitField.stalled = 1U; + + /* Set endpoint stall in BDT. And then if the host send a IN/OUT tanscation, the device will response a STALL state. + */ + USB_KHCI_BDT_SET_CONTROL( + (uint32_t)khciState->bdt, endpoint, direction, khciState->endpointState[index].stateUnion.stateBitField.bdtOdd, + USB_LONG_TO_LITTLE_ENDIAN( + (uint32_t)(USB_KHCI_BDT_BC(khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize) | + USB_KHCI_BDT_DTS | USB_KHCI_BDT_STALL | USB_KHCI_BDT_OWN))); + + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; + + return kStatus_USB_Success; +} + +/*! + * @brief Un-stall a specified endpoint. + * + * The function is used to un-stall a specified endpoint. + * Current transfer of the endpoint will be canceled and the specified endpoint will be un-stalled. + * + * @param khciState Pointer of the device KHCI state structure. + * @param ep The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointUnstall(usb_device_khci_state_struct_t *khciState, uint8_t ep) +{ + uint32_t control; + uint8_t endpoint = ep & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = + (ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + uint8_t index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + /* Clear the endpoint stall state */ + khciState->endpointState[index].stateUnion.stateBitField.stalled = 0U; + /* Reset the endpoint data toggle to DATA0 */ + khciState->endpointState[index].stateUnion.stateBitField.data0 = 0U; + + /* Clear stall state in BDT */ + for (uint8_t i = 0U; i < 2U; i++) + { + control = USB_KHCI_BDT_GET_CONTROL((uint32_t)khciState->bdt, endpoint, direction, i); + if (control & USB_KHCI_BDT_STALL) + { + USB_KHCI_BDT_SET_CONTROL( + (uint32_t)khciState->bdt, endpoint, direction, i, + USB_LONG_TO_LITTLE_ENDIAN( + (uint32_t)(USB_KHCI_BDT_BC(khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize) | + USB_KHCI_BDT_DTS | USB_KHCI_BDT_DATA01(0U)))); + } + } + + /* Clear stall state in endpoint control register */ + khciState->registerBase->ENDPOINT[endpoint].ENDPT &= ~USB_ENDPT_EPSTALL_MASK; + + /* Prime a transfer to receive next setup packet when the endpoint is a control out endpoint. */ + if ((USB_CONTROL_ENDPOINT == endpoint) && (USB_OUT == direction)) + { + USB_DeviceKhciPrimeNextSetup(khciState); + } + + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; + + return kStatus_USB_Success; +} + +/*! + * @brief Handle the token done interrupt. + * + * The function is used to handle the token done interrupt. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptTokenDone(usb_device_khci_state_struct_t *khciState) +{ + uint32_t control; + uint32_t length; + uint32_t remainingLength; + usb_device_callback_message_struct_t message; + uint8_t endpoint; + uint8_t direction; + uint8_t bdtOdd; + uint8_t isSetup; + uint8_t index; + uint8_t stateRegister = khciState->registerBase->STAT; + + /* Get the endpoint number to identify which one triggers the token done interrupt. */ + endpoint = (stateRegister & USB_STAT_ENDP_MASK) >> USB_STAT_ENDP_SHIFT; + + /* Get the direction of the endpoint number. */ + direction = (stateRegister & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT; + + /* Get the finished BDT ODD. */ + bdtOdd = (stateRegister & USB_STAT_ODD_MASK) >> USB_STAT_ODD_SHIFT; + + /* Clear token done interrupt flag. */ + khciState->registerBase->ISTAT = kUSB_KhciInterruptTokenDone; + + /* Get the Control field of the BDT element according to the endpoint number, the direction and finished BDT ODD. */ + control = USB_KHCI_BDT_GET_CONTROL((uint32_t)khciState->bdt, endpoint, direction, bdtOdd); + + /* Get the transferred length. */ + length = ((USB_LONG_FROM_LITTLE_ENDIAN(control)) >> 16U) & 0x3FFU; + + /* Get the transferred length. */ + isSetup = (USB_KHCI_BDT_DEVICE_SETUP_TOKEN == ((uint8_t)(((USB_LONG_FROM_LITTLE_ENDIAN(control)) >> 2U) & 0x0FU))) ? + 1U : + 0U; + + index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + if (0U == khciState->endpointState[index].stateUnion.stateBitField.transferring) + { + return; + } + + if (isSetup) + { + khciState->setupBufferIndex = bdtOdd; + } + + /* USB_IN, Send completed */ + if (direction == USB_IN) + { + /* The transferred length */ + khciState->endpointState[index].transferDone += length; + + /* Remaining length */ + remainingLength = khciState->endpointState[index].transferLength - khciState->endpointState[index].transferDone; + + /* Change the data toggle flag */ + khciState->endpointState[index].stateUnion.stateBitField.data0 ^= 1U; + /* Change the BDT odd toggle flag */ + khciState->endpointState[index].stateUnion.stateBitField.bdtOdd ^= 1U; + + /* Whether the transfer is completed or not. */ + /* + * The transfer is completed when one of the following conditions meet: + * 1. The remaining length is zero. + * 2. The length of current transcation is less than the max packet size of the current pipe. + */ + if ((0U == remainingLength) || + (khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize > length)) + { + message.length = khciState->endpointState[index].transferDone; + message.buffer = khciState->endpointState[index].transferBuffer; + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + + /* + * Whether need to send ZLT when the pipe is control in pipe and the transferred length of current + * transaction equals to max packet size. + */ + if ((length == khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize) && + (USB_CONTROL_ENDPOINT == endpoint)) + { + usb_setup_struct_t *setup_packet = + (usb_setup_struct_t + *)(&khciState->setupPacketBuffer[(USB_SETUP_PACKET_SIZE * khciState->setupBufferIndex)]); + /* + * Send the ZLT and terminate the token done interrupt service when the tranferred length in data phase + * is less than the host request. + */ + if (USB_SHORT_FROM_LITTLE_ENDIAN(setup_packet->wLength) > + khciState->endpointState[index].transferLength) + { + (void)USB_DeviceSendRequest(khciState->deviceHandle, endpoint, (uint8_t *)NULL, 0U); + return; + } + } + } + else + { + /* Send remaining data and terminate the token done interrupt service. */ + (void)USB_DeviceKhciSend(khciState, endpoint | (USB_IN << 0x07U), + khciState->endpointState[index].transferBuffer, remainingLength); + return; + } + } + else + { + if ((USB_CONTROL_ENDPOINT == endpoint) && (0U == length)) + { + message.length = 0U; + message.buffer = (uint8_t *)NULL; + } + else + { + if (0U == khciState->endpointState[index].stateUnion.stateBitField.dmaAlign) + { + uint8_t *buffer = (uint8_t *)USB_LONG_FROM_LITTLE_ENDIAN( + USB_KHCI_BDT_GET_ADDRESS((uint32_t)khciState->bdt, endpoint, USB_OUT, + khciState->endpointState[index].stateUnion.stateBitField.bdtOdd)); + uint8_t *transferBuffer = + khciState->endpointState[index].transferBuffer + khciState->endpointState[index].transferDone; + if (buffer != transferBuffer) + { + for (uint32_t i = 0U; i < length; i++) + { + transferBuffer[i] = buffer[i]; + } + } + khciState->isDmaAlignBufferInusing = 0U; + } + /* The transferred length */ + khciState->endpointState[index].transferDone += length; + /* Remaining length */ + remainingLength = + khciState->endpointState[index].transferLength - khciState->endpointState[index].transferDone; + + if ((USB_CONTROL_ENDPOINT == endpoint) && isSetup) + { + USB_DeviceKhciCancel(khciState, + (endpoint | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))); + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.data0 = 1U; + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_IN].stateUnion.stateBitField.data0 = 1U; + } + else + { + khciState->endpointState[index].stateUnion.stateBitField.data0 ^= 1U; + } + khciState->endpointState[index].stateUnion.stateBitField.bdtOdd ^= 1U; + if ((!khciState->endpointState[index].transferLength) || (!remainingLength) || + (khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize > length)) + { + message.length = khciState->endpointState[index].transferDone; + message.buffer = khciState->endpointState[index].transferBuffer; + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + } + else + { + /* Receive remaining data and terminate the token done interrupt service. */ + USB_DeviceKhciRecv(khciState, (endpoint) | (USB_OUT << 0x07U), + khciState->endpointState[index].transferBuffer, remainingLength); + return; + } + } + } + + message.isSetup = isSetup; + message.code = (endpoint) | (uint8_t)(((uint32_t)direction << 0x07U)); + + /* Notify the up layer the KHCI status changed. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); + + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; +} + +/*! + * @brief Handle the USB bus reset interrupt. + * + * The function is used to handle the USB bus reset interrupt. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptReset(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + /* Set KHCI reset flag */ + khciState->isResetting = 1U; + + /* Clear the reset interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptReset); + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyBusReset; + message.length = 0U; + message.isSetup = 0U; + /* Notify up layer the USB bus reset signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} + +/* The USB suspend and resume signals need to be detected and handled when the low power or remote wakeup function + * enabled. */ +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) || \ + (defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U))) + +/*! + * @brief Handle the suspend interrupt. + * + * The function is used to handle the suspend interrupt when the suspend signal detected. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptSleep(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + /* Enable the resume interrupt */ + khciState->registerBase->INTEN |= kUSB_KhciInterruptResume; + /* Disable the suspend interrupt */ + khciState->registerBase->INTEN &= ~kUSB_KhciInterruptSleep; + + /* Clear the suspend interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptSleep); + /* Clear the resume interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptResume); + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifySuspend; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB suspend signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} + +/*! + * @brief Handle the resume interrupt. + * + * The function is used to handle the resume interrupt when the resume signal detected. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptResume(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + /* Enable the suspend interrupt */ + khciState->registerBase->INTEN |= kUSB_KhciInterruptSleep; + /* Disable the resume interrupt */ + khciState->registerBase->INTEN &= ~kUSB_KhciInterruptResume; + + /* Clear the resume interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptResume); + /* Clear the suspend interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptSleep); + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyResume; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB resume signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE || USB_DEVICE_CONFIG_REMOTE_WAKEUP */ + +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED) && (FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED > 0U)) +/*! + * @brief Handle the VBUS rising interrupt. + * + * The function is used to handle the VBUS rising interrupt when the VBUS rising signal detected. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptVbusRising(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + /* Disable the VBUS rising interrupt */ + khciState->registerBase->MISCCTRL &= ~USB_MISCCTRL_VREDG_EN_MASK; + /* Enable the VBUS rising interrupt */ + khciState->registerBase->MISCCTRL |= USB_MISCCTRL_VREDG_EN_MASK; + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyAttach; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB VBUS rising signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} + +/*! + * @brief Handle the VBUS falling interrupt. + * + * The function is used to handle the VBUS falling interrupt when the VBUS falling signal detected. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptVbusFalling(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + /* Disable the VBUS rising interrupt */ + khciState->registerBase->MISCCTRL &= ~USB_MISCCTRL_VFEDG_EN_MASK; + /* Enable the VBUS rising interrupt */ + khciState->registerBase->MISCCTRL |= USB_MISCCTRL_VFEDG_EN_MASK; + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyDetach; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB VBUS falling signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} +#endif /* USB_DEVICE_CONFIG_DETACH_ENABLE || FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED */ + +#if 0U +/*! + * @brief Handle the sof interrupt. + * + * The function is used to handle the sof interrupt. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +void USB_DeviceKhciInterruptSof(usb_device_khci_state_struct_t *khciState) +{ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptSofToken); + + khciState->registerBase->ISTAT = (kUSB_KhciInterruptResume); +} +#endif + +/*! + * @brief Handle endpoint stalled interrupt. + * + * The function is used to handle endpoint stalled interrupt. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptStall(usb_device_khci_state_struct_t *khciState) +{ + /* Clear the endpoint stalled interrupt flag */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptStall); + + /* Un-stall the control in and out pipe when the control in or out pipe stalled. */ + if ((khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_IN].stateUnion.stateBitField.stalled) || + (khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.stalled)) + { + USB_DeviceKhciEndpointUnstall( + khciState, (USB_CONTROL_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))); + USB_DeviceKhciEndpointUnstall( + khciState, (USB_CONTROL_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))); + } +} + +#if defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && (USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING > 0U) +static void USB_DeviceKhciInterruptError(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + khciState->registerBase->ISTAT = (kUSB_KhciInterruptError); + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyError; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB error detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} +#endif /* USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING */ + +/*! + * @brief Initialize the USB device KHCI instance. + * + * This function initizlizes the USB device KHCI module specified by the controllerId. + * + * @param controllerId The controller id of the USB IP. Please refer to enumeration type usb_controller_index_t. + * @param handle Pointer of the device handle, used to identify the device object is belonged to. + * @param khciHandle It is out parameter, is used to return pointer of the device KHCI handle to the caller. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciInit(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *khciHandle) +{ + usb_device_khci_state_struct_t *khciState; + uint32_t khci_base[] = USB_BASE_ADDRS; + + if (((controllerId - kUSB_ControllerKhci0) >= (uint8_t)USB_DEVICE_CONFIG_KHCI) || + ((controllerId - kUSB_ControllerKhci0) >= (sizeof(khci_base) / sizeof(uint32_t)))) + { + return kStatus_USB_ControllerNotFound; + } + khciState = &s_UsbDeviceKhciState[controllerId - kUSB_ControllerKhci0]; + + khciState->controllerId = controllerId; + + khciState->registerBase = (USB_Type *)khci_base[controllerId - kUSB_ControllerKhci0]; + + khciState->dmaAlignBuffer = (uint8_t *)&s_UsbDeviceKhciDmaAlignBuffer[controllerId - kUSB_ControllerKhci0][0]; + + /* Clear all interrupt flags. */ + khciState->registerBase->ISTAT = 0xFFU; + + /* Disable the device functionality. */ + USB_DeviceKhciControl(khciState, kUSB_DeviceControlStop, NULL); + + khciState->bdt = s_UsbDeviceKhciBdtBuffer[controllerId - kUSB_ControllerKhci0]; + + /* Set BDT buffer address */ + khciState->registerBase->BDTPAGE1 = (uint8_t)((((uint32_t)khciState->bdt) >> 8U) & 0xFFU); + khciState->registerBase->BDTPAGE2 = (uint8_t)((((uint32_t)khciState->bdt) >> 16U) & 0xFFU); + khciState->registerBase->BDTPAGE3 = (uint8_t)((((uint32_t)khciState->bdt) >> 24U) & 0xFFU); + +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED) && (FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED > 0U)) + khciState->registerBase->MISCCTRL |= USB_MISCCTRL_VREDG_EN_MASK | USB_MISCCTRL_VFEDG_EN_MASK; +#endif + +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) \ +&& defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && \ + (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && defined(FSL_FEATURE_USB_KHCI_USB_RAM) && \ + (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + khciState->registerBase->CLK_RECOVER_CTRL |= USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK; + khciState->registerBase->KEEP_ALIVE_CTRL = + USB_KEEP_ALIVE_CTRL_KEEP_ALIVE_EN_MASK | USB_KEEP_ALIVE_CTRL_OWN_OVERRD_EN_MASK | + USB_KEEP_ALIVE_CTRL_WAKE_INT_EN_MASK | FSL_FEATURE_USB_KHCI_KEEP_ALIVE_MODE_CONTROL; + /* wake on out and setup transaction */ + khciState->registerBase->KEEP_ALIVE_WKCTRL = 0x1U; + PMC->REGSC |= PMC_REGSC_BGEN_MASK | PMC_REGSC_VLPO_MASK; +#endif + /* Set KHCI device state to default value. */ + USB_DeviceKhciSetDefaultState(khciState); + + *khciHandle = khciState; + khciState->deviceHandle = (usb_device_struct_t *)handle; + + return kStatus_USB_Success; +} + +/*! + * @brief De-initialize the USB device KHCI instance. + * + * This function de-initizlizes the USB device KHCI module. + * + * @param khciHandle Pointer of the device KHCI handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciDeinit(usb_device_controller_handle khciHandle) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + + if (!khciHandle) + { + return kStatus_USB_InvalidHandle; + } + /* Clear all interrupt flags. */ + khciState->registerBase->ISTAT = 0xFFU; + /* Disable all interrupts. */ + khciState->registerBase->INTEN &= ~(0xFFU); + /* Clear device address. */ + khciState->registerBase->ADDR = (0U); + + /* Clear USB_CTL register */ + khciState->registerBase->CTL = 0x00U; + khciState->registerBase->USBCTRL |= USB_USBCTRL_PDE_MASK | USB_USBCTRL_SUSP_MASK; + + return kStatus_USB_Success; +} + +/*! + * @brief Send data through a specified endpoint. + * + * This function sends data through a specified endpoint. + * + * @param khciHandle Pointer of the device KHCI handle. + * @param endpointAddress Endpoint index. + * @param buffer The memory address to hold the data need to be sent. + * @param length The data length need to be sent. + * + * @return A USB error code or kStatus_USB_Success. + * + * @note The return value just means if the sending request is successful or not; the transfer done is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +usb_status_t USB_DeviceKhciSend(usb_device_controller_handle khciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + uint32_t index = ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) << 1U) | USB_IN; + usb_status_t error = kStatus_USB_Error; + + /* Save the tansfer information */ + if (0U == khciState->endpointState[index].stateUnion.stateBitField.transferring) + { + khciState->endpointState[index].transferDone = 0U; + khciState->endpointState[index].transferBuffer = buffer; + khciState->endpointState[index].transferLength = length; + khciState->endpointState[index].stateUnion.stateBitField.dmaAlign = 1U; + } + + /* Data length needs to less than max packet size in each call. */ + if (length > khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize) + { + length = khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize; + } + + /* Send data when the device is not resetting. */ + if (0U == khciState->isResetting) + { + error = USB_DeviceKhciEndpointTransfer(khciState, endpointAddress & USB_ENDPOINT_NUMBER_MASK, USB_IN, + (uint8_t *)((uint32_t)khciState->endpointState[index].transferBuffer + + (uint32_t)khciState->endpointState[index].transferDone), + length); + } + + /* Prime a transfer to receive next setup packet if the dat length is zero in a control in endpoint. */ + if ((0U == khciState->endpointState[index].transferDone) && (0U == length) && + (USB_CONTROL_ENDPOINT == (endpointAddress & USB_ENDPOINT_NUMBER_MASK))) + { + USB_DeviceKhciPrimeNextSetup(khciState); + } + return error; +} + +/*! + * @brief Receive data through a specified endpoint. + * + * This function Receives data through a specified endpoint. + * + * @param khciHandle Pointer of the device KHCI handle. + * @param endpointAddress Endpoint index. + * @param buffer The memory address to save the received data. + * @param length The data length want to be received. + * + * @return A USB error code or kStatus_USB_Success. + * + * @note The return value just means if the receiving request is successful or not; the transfer done is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +usb_status_t USB_DeviceKhciRecv(usb_device_controller_handle khciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + uint32_t index = ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) << 1U) | USB_OUT; + usb_status_t error = kStatus_USB_Error; + + /* Save the tansfer information */ + if (0U == khciState->endpointState[index].stateUnion.stateBitField.transferring) + { + khciState->endpointState[index].transferDone = 0U; + khciState->endpointState[index].transferBuffer = buffer; + khciState->endpointState[index].transferLength = length; + } + khciState->endpointState[index].stateUnion.stateBitField.dmaAlign = 1U; + + /* Data length needs to less than max packet size in each call. */ + if (length > khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize) + { + length = khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize; + } + + buffer = (uint8_t *)((uint32_t)buffer + (uint32_t)khciState->endpointState[index].transferDone); + + if ((khciState->dmaAlignBuffer) && (0U == khciState->isDmaAlignBufferInusing) && + (USB_DEVICE_CONFIG_KHCI_DMA_ALIGN_BUFFER_LENGTH >= length) && + ((length & 0x03U) || (((uint32_t)buffer) & 0x03U))) + { + khciState->endpointState[index].stateUnion.stateBitField.dmaAlign = 0U; + buffer = khciState->dmaAlignBuffer; + khciState->isDmaAlignBufferInusing = 1U; + } + + /* Receive data when the device is not resetting. */ + if (0U == khciState->isResetting) + { + error = USB_DeviceKhciEndpointTransfer(khciState, endpointAddress & USB_ENDPOINT_NUMBER_MASK, USB_OUT, buffer, + length); + } + + /* Prime a transfer to receive next setup packet if the dat length is zero in a control out endpoint. */ + if ((0U == length) && (USB_CONTROL_ENDPOINT == (endpointAddress & USB_ENDPOINT_NUMBER_MASK))) + { + khciState->endpointState[index].stateUnion.stateBitField.bdtOdd ^= 1U; + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + USB_DeviceKhciPrimeNextSetup(khciState); + } + return error; +} + +/*! + * @brief Cancel the pending transfer in a specified endpoint. + * + * The function is used to cancel the pending transfer in a specified endpoint. + * + * @param khciHandle Pointer of the device KHCI handle. + * @param ep Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciCancel(usb_device_controller_handle khciHandle, uint8_t ep) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + usb_device_callback_message_struct_t message; + uint8_t index = ((ep & USB_ENDPOINT_NUMBER_MASK) << 1U) | ((ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + + /* Cancel the transfer and notify the up layer when the endpoint is busy. */ + if (khciState->endpointState[index].stateUnion.stateBitField.transferring) + { + message.length = USB_UNINITIALIZED_VAL_32; + message.buffer = khciState->endpointState[index].transferBuffer; + message.code = ep; + message.isSetup = 0U; + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); + } + return kStatus_USB_Success; +} + +/*! + * @brief Control the status of the selected item. + * + * The function is used to control the status of the selected item. + * + * @param khciHandle Pointer of the device KHCI handle. + * @param type The selected item. Please refer to enumeration type usb_device_control_type_t. + * @param param The param type is determined by the selected item. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciControl(usb_device_controller_handle khciHandle, usb_device_control_type_t type, void *param) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + usb_status_t error = kStatus_USB_Error; + uint16_t *temp16; + uint8_t *temp8; +#if defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U) + USB_OSA_SR_ALLOC(); +#endif /* USB_DEVICE_CONFIG_REMOTE_WAKEUP */ + + if (!khciHandle) + { + return kStatus_USB_InvalidHandle; + } + + switch (type) + { + case kUSB_DeviceControlRun: + khciState->registerBase->USBCTRL = 0U; +#if defined(FSL_FEATURE_USB_KHCI_OTG_ENABLED) && (FSL_FEATURE_USB_KHCI_OTG_ENABLED > 0U) + if (khciState->registerBase->OTGCTL & USB_OTGCTL_OTGEN_MASK) + { + khciState->registerBase->OTGCTL |= USB_OTGCTL_DPHIGH_MASK; + } +#endif /* FSL_FEATURE_USB_KHCI_OTG_ENABLED */ + khciState->registerBase->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK; + khciState->registerBase->CTL |= USB_CTL_USBENSOFEN_MASK; + + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlStop: +#if defined(FSL_FEATURE_USB_KHCI_OTG_ENABLED) && (FSL_FEATURE_USB_KHCI_OTG_ENABLED > 0U) + if (khciState->registerBase->OTGCTL & USB_OTGCTL_OTGEN_MASK) + { + khciState->registerBase->OTGCTL &= ~USB_OTGCTL_DPHIGH_MASK; + } +#endif /* FSL_FEATURE_USB_KHCI_OTG_ENABLED */ + khciState->registerBase->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK; + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlEndpointInit: + if (param) + { + error = USB_DeviceKhciEndpointInit(khciState, (usb_device_endpoint_init_struct_t *)param); + } + break; + case kUSB_DeviceControlEndpointDeinit: + if (param) + { + temp8 = (uint8_t *)param; + error = USB_DeviceKhciEndpointDeinit(khciState, *temp8); + } + break; + case kUSB_DeviceControlEndpointStall: + if (param) + { + temp8 = (uint8_t *)param; + error = USB_DeviceKhciEndpointStall(khciState, *temp8); + } + break; + case kUSB_DeviceControlEndpointUnstall: + if (param) + { + temp8 = (uint8_t *)param; + error = USB_DeviceKhciEndpointUnstall(khciState, *temp8); + } + break; + case kUSB_DeviceControlGetDeviceStatus: + if (param) + { + temp16 = (uint16_t *)param; + *temp16 = + (USB_DEVICE_CONFIG_SELF_POWER << (USB_REQUEST_STANDARD_GET_STATUS_DEVICE_SELF_POWERED_SHIFT)) | + (USB_DEVICE_CONFIG_REMOTE_WAKEUP << (USB_REQUEST_STANDARD_GET_STATUS_DEVICE_REMOTE_WARKUP_SHIFT)); + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlGetEndpointStatus: + if (param) + { + usb_device_endpoint_status_struct_t *endpointStatus = (usb_device_endpoint_status_struct_t *)param; + + if (((endpointStatus->endpointAddress) & USB_ENDPOINT_NUMBER_MASK) < USB_DEVICE_CONFIG_ENDPOINTS) + { + endpointStatus->endpointStatus = + (uint16_t)( + khciState + ->endpointState[(((endpointStatus->endpointAddress) & USB_ENDPOINT_NUMBER_MASK) << 1U) | + (((endpointStatus->endpointAddress) & + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)] + .stateUnion.stateBitField.stalled == 1U) ? + kUSB_DeviceEndpointStateStalled : + kUSB_DeviceEndpointStateIdle; + error = kStatus_USB_Success; + } + } + break; + case kUSB_DeviceControlSetDeviceAddress: + if (param) + { + temp8 = (uint8_t *)param; + khciState->registerBase->ADDR = (*temp8); + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlGetSynchFrame: + break; + case kUSB_DeviceControlResume: +#if defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U) + USB_OSA_ENTER_CRITICAL(); + khciState->registerBase->CTL |= USB_CTL_RESUME_MASK; + for (uint32_t i = 500U; i > 0U; i--) + { + __ASM("nop"); + } + khciState->registerBase->CTL &= ~USB_CTL_RESUME_MASK; + USB_OSA_EXIT_CRITICAL(); + error = kStatus_USB_Success; +#endif /* USB_DEVICE_CONFIG_REMOTE_WAKEUP */ + break; + case kUSB_DeviceControlSetDefaultStatus: + for (uint8_t count = 0U; count < USB_DEVICE_CONFIG_ENDPOINTS; count++) + { + USB_DeviceKhciEndpointDeinit(khciState, (count | (USB_IN << 0x07U))); + USB_DeviceKhciEndpointDeinit(khciState, (count | (USB_OUT << 0x07U))); + } + USB_DeviceKhciSetDefaultState(khciState); + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlGetSpeed: + if (param) + { + temp8 = (uint8_t *)param; + *temp8 = USB_SPEED_FULL; + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlGetOtgStatus: + break; + case kUSB_DeviceControlSetOtgStatus: + break; + case kUSB_DeviceControlSetTestMode: + break; + default: + break; + } + + return error; +} + +/*! + * @brief Handle the KHCI device interrupt. + * + * The function is used to handle the KHCI device interrupt. + * + * @param deviceHandle The device handle got from USB_DeviceInit. + * + */ +void USB_DeviceKhciIsrFunction(void *deviceHandle) +{ + usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle; + usb_device_khci_state_struct_t *khciState; + uint8_t status; + + if (NULL == deviceHandle) + { + return; + } + + khciState = (usb_device_khci_state_struct_t *)(handle->controllerHandle); + + status = khciState->registerBase->ISTAT; +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) \ +&& defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && \ + (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && defined(FSL_FEATURE_USB_KHCI_USB_RAM) && \ + (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + /* Clear EEP_ALIVE_CTRL_WAKE_INT interrupt state */ + if (khciState->registerBase->KEEP_ALIVE_CTRL & USB_KEEP_ALIVE_CTRL_WAKE_INT_STS_MASK) + { + khciState->registerBase->KEEP_ALIVE_CTRL |= USB_KEEP_ALIVE_CTRL_WAKE_INT_STS_MASK; + } + /* Clear SOFTOK interrupt state */ + if (khciState->registerBase->ISTAT & USB_ISTAT_SOFTOK_MASK) + { + khciState->registerBase->ISTAT = USB_ISTAT_SOFTOK_MASK; + } +#endif +#if defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && (USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING > 0U) + /* Error interrupt */ + if (status & kUSB_KhciInterruptError) + { + USB_DeviceKhciInterruptError(khciState); + } +#endif /* USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING */ + /* Token done interrupt */ + if (status & kUSB_KhciInterruptTokenDone) + { + USB_DeviceKhciInterruptTokenDone(khciState); + } + + /* Reset interrupt */ + if (status & kUSB_KhciInterruptReset) + { + USB_DeviceKhciInterruptReset(khciState); + } + +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) || \ + (defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U))) + /* Suspend interrupt */ + if (status & kUSB_KhciInterruptSleep) + { + USB_DeviceKhciInterruptSleep(khciState); + } + + /* Resume interrupt */ + if (status & kUSB_KhciInterruptResume) + { + USB_DeviceKhciInterruptResume(khciState); + } +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE || USB_DEVICE_CONFIG_REMOTE_WAKEUP */ + + /* Endpoint stalled interrupt */ + if (status & kUSB_KhciInterruptStall) + { + USB_DeviceKhciInterruptStall(khciState); + } + +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED) && (FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED > 0U)) + if (khciState->registerBase->USBTRC0 & USB_USBTRC0_VREDG_DET_MASK) + { + USB_DeviceKhciInterruptVbusRising(khciState); + } + + if (khciState->registerBase->USBTRC0 & USB_USBTRC0_VFEDG_DET_MASK) + { + USB_DeviceKhciInterruptVbusFalling(khciState); + } +#endif /* USB_DEVICE_CONFIG_DETACH_ENABLE && FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED */ + +#if 0U + /* Sof token interrupt */ + if (status & kUSB_KhciInterruptSofToken) + { + USB_DeviceKhciInterruptSof(khciState); + } +#endif + +#if ((defined FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && \ + (FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED > 0U)) + status = khciState->registerBase->CLK_RECOVER_INT_STATUS; + if (status) + { + /* USB RECOVER interrupt is happenned */ + if (USB_CLK_RECOVER_INT_STATUS_OVF_ERROR_MASK & status) + { + /* Indicates that the USB clock recovery algorithm has detected that the frequency trim adjustment needed + * for the IRC48M output clock is outside the available TRIM_FINE adjustment range for the IRC48M + * module. + */ + } + khciState->registerBase->CLK_RECOVER_INT_STATUS = status; + } +#endif +} + +#endif /* USB_DEVICE_CONFIG_KHCI */ diff --git a/usb_1.1.0/device/usb_device_khci.h b/usb_1.1.0/device/usb_device_khci.h new file mode 100644 index 0000000..2b0bf9f --- /dev/null +++ b/usb_1.1.0/device/usb_device_khci.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_DEVICE_KHCI_H__ +#define __USB_DEVICE_KHCI_H__ + +/*! + * @addtogroup usb_device_controller_khci_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief The maximum value of ISO maximum packet size for FS in USB specification 2.0 */ +#define USB_DEVICE_MAX_FS_ISO_MAX_PACKET_SIZE (1023U) + +/*! @brief The maximum value of non-ISO maximum packet size for FS in USB specification 2.0 */ +#define USB_DEVICE_MAX_FS_NONE_ISO_MAX_PACKET_SIZE (64U) + +/*! @brief Set BDT buffer address */ +#define USB_KHCI_BDT_SET_ADDRESS(bdt_base, ep, direction, odd, address) \ + *((volatile uint32_t *)((bdt_base & 0xfffffe00U) | (((uint32_t)ep & 0x0fU) << 5U) | \ + (((uint32_t)direction & 1U) << 4U) | (((uint32_t)odd & 1U) << 3U)) + \ + 1U) = address + +/*! @brief Set BDT control fields*/ +#define USB_KHCI_BDT_SET_CONTROL(bdt_base, ep, direction, odd, control) \ + *(volatile uint32_t *)((bdt_base & 0xfffffe00U) | (((uint32_t)ep & 0x0fU) << 5U) | \ + (((uint32_t)direction & 1U) << 4U) | (((uint32_t)odd & 1U) << 3U)) = control + +/*! @brief Get BDT buffer address*/ +#define USB_KHCI_BDT_GET_ADDRESS(bdt_base, ep, direction, odd) \ + (*((volatile uint32_t *)((bdt_base & 0xfffffe00U) | (((uint32_t)ep & 0x0fU) << 5U) | \ + (((uint32_t)direction & 1U) << 4U) | (((uint32_t)odd & 1U) << 3U)) + \ + 1U)) + +/*! @brief Get BDT control fields*/ +#define USB_KHCI_BDT_GET_CONTROL(bdt_base, ep, direction, odd) \ + (*(volatile uint32_t *)((bdt_base & 0xfffffe00U) | (((uint32_t)ep & 0x0fU) << 5U) | \ + (((uint32_t)direction & 1U) << 4U) | (((uint32_t)odd & 1U) << 3U))) + +/*! @brief Endpoint state structure */ +typedef struct _usb_device_khci_endpoint_state_struct +{ + uint8_t *transferBuffer; /*!< Address of buffer containing the data to be transmitted */ + uint32_t transferLength; /*!< Length of data to transmit. */ + uint32_t transferDone; /*!< The data length has been transferred*/ + union + { + uint32_t state; /*!< The state of the endpoint */ + struct + { + uint32_t maxPacketSize : 10U; /*!< The maximum packet size of the endpoint */ + uint32_t stalled : 1U; /*!< The endpoint is stalled or not */ + uint32_t data0 : 1U; /*!< The data toggle of the transaction */ + uint32_t bdtOdd : 1U; /*!< The BDT toggle of the endpoint */ + uint32_t dmaAlign : 1U; /*!< Whether the transferBuffer is DMA aligned or not */ + uint32_t transferring : 1U; /*!< The endpoint is transferring */ + uint32_t resersed : 1U; /*!< Reversed */ + } stateBitField; + } stateUnion; +} usb_device_khci_endpoint_state_struct_t; + +/*! @brief KHCI state structure */ +typedef struct _usb_device_khci_state_struct +{ + usb_device_struct_t *deviceHandle; /*!< Device handle used to identify the device object belongs to */ + uint8_t *bdt; /*!< BDT buffer address */ + USB_Type *registerBase; /*!< The base address of the register */ + uint8_t setupPacketBuffer[USB_SETUP_PACKET_SIZE * 2]; /*!< The setup request buffer */ + uint8_t + *dmaAlignBuffer; /*!< This buffer is used to fix the transferBuffer or transferLength does + not align to 4-bytes when the function USB_DeviceKhciRecv is called. + The macro USB_DEVICE_CONFIG_KHCI_DMA_ALIGN is used to enable or disable this feature. + If the feature is enabled, when the transferBuffer or transferLength does not align to 4-bytes, + the transferLength is not more than USB_DEVICE_CONFIG_KHCI_DMA_ALIGN_BUFFER_LENGTH, and + the flag isDmaAlignBufferInusing is zero, the dmaAlignBuffer is used to receive data + and the flag isDmaAlignBufferInusing is set to 1. + When the transfer is done, the received data, kept in dmaAlignBuffer, is copied + to the transferBuffer, and the flag isDmaAlignBufferInusing is cleared. + */ + usb_device_khci_endpoint_state_struct_t + endpointState[USB_DEVICE_CONFIG_ENDPOINTS * 2]; /*!< Endpoint state structures */ + uint8_t isDmaAlignBufferInusing; /*!< The dmaAlignBuffer is used or not */ + uint8_t isResetting; /*!< Is doing device reset or not */ + uint8_t controllerId; /*!< Controller ID */ + uint8_t setupBufferIndex; /*!< A valid setup buffer flag */ +} usb_device_khci_state_struct_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name USB device KHCI functions + * @{ + */ + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Initializes the USB device KHCI instance. + * + * This function initializes the USB device KHCI module specified by the controllerId. + * + * @param[in] controllerId The controller ID of the USB IP. See the enumeration type usb_controller_index_t. + * @param[in] handle Pointer of the device handle used to identify the device object belongs to. + * @param[out] khciHandle An out parameter used to return the pointer of the device KHCI handle to the caller. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciInit(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *khciHandle); + +/*! + * @brief Deinitializes the USB device KHCI instance. + * + * This function deinitializes the USB device KHCI module. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciDeinit(usb_device_controller_handle khciHandle); + +/*! + * @brief Sends data through a specified endpoint. + * + * This function sends data through a specified endpoint. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * @param[in] endpointAddress Endpoint index. + * @param[in] buffer The memory address to hold the data need to be sent. + * @param[in] length The data length need to be sent. + * + * @return A USB error code or kStatus_USB_Success. + * + * @note The return value indicates whether the sending request is successful or not. The transfer completion is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for a specific endpoint. + * If there is a specific requirement to support multiple transfer requests for a specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer can begin only when the previous transfer is done (a notification is obtained through the endpoint + * callback). + */ +usb_status_t USB_DeviceKhciSend(usb_device_controller_handle khciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Receives data through a specified endpoint. + * + * This function receives data through a specified endpoint. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * @param[in] endpointAddress Endpoint index. + * @param[in] buffer The memory address to save the received data. + * @param[in] length The data length to be received. + * + * @return A USB error code or kStatus_USB_Success. + * + * @note The return value indicates whether the receiving request is successful or not. The transfer completion is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for a specific endpoint. + * If there is a specific requirement to support multiple transfer requests for a specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer can begin only when the previous transfer is done (a notification is obtained through the endpoint + * callback). + */ +usb_status_t USB_DeviceKhciRecv(usb_device_controller_handle khciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Cancels the pending transfer in a specified endpoint. + * + * The function is used to cancel the pending transfer in a specified endpoint. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * @param[in] ep Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciCancel(usb_device_controller_handle khciHandle, uint8_t ep); + +/*! + * @brief Controls the status of the selected item. + * + * The function is used to control the status of the selected item. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * @param[in] type The selected item. See enumeration type usb_device_control_type_t. + * @param[in,out] param The parameter type is determined by the selected item. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciControl(usb_device_controller_handle khciHandle, + usb_device_control_type_t type, + void *param); + +/*! @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @} */ + +#endif /* __USB_DEVICE_KHCI_H__ */ diff --git a/usb_1.1.0/host/class/usb_host_audio.c b/usb_1.1.0/host/class/usb_host_audio.c new file mode 100644 index 0000000..798d7ef --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_audio.c @@ -0,0 +1,1051 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_AUDIO) && (USB_HOST_CONFIG_AUDIO)) +#include "usb_host.h" +#include "usb_host_audio.h" + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* usb audio feature uint command request declaration */ +static usb_audio_request_t s_usbAudioFuRequests[NUMBER_OF_FEATURE_COMMANDS] = { + /* Mute command request */ + {AUDIO_FU_MUTE_MASK, ITF_REQUEST, CUR_REQUEST, AUDIO_FU_MUTE, 1U}, + /* Volume command request */ + {AUDIO_FU_VOLUME_MASK, ITF_REQUEST, CUR_REQUEST, AUDIO_FU_VOLUME, 2U}, + {AUDIO_FU_VOLUME_MASK, ITF_REQUEST, MIN_REQUEST, AUDIO_FU_VOLUME, 2U}, + {AUDIO_FU_VOLUME_MASK, ITF_REQUEST, MAX_REQUEST, AUDIO_FU_VOLUME, 2U}, + {AUDIO_FU_VOLUME_MASK, ITF_REQUEST, RES_REQUEST, AUDIO_FU_VOLUME, 2U}, +}; +/* USB audio endpoint command declaration */ +static usb_audio_request_t s_usbAudioEpRequests[NUMBER_OF_ENDPOINT_COMMANDS] = { + /* USB audio Pitch command request */ + {AUDIO_PITCH_MASK, EP_REQUEST, CUR_REQUEST, AUDIO_PITCH_CONTROL, 1U}, + + /* USB audio Sampling frequency command request */ + {AUDIO_SAMPLING_FREQ_MASK, EP_REQUEST, CUR_REQUEST, AUDIO_SAMPLING_FREQ_CONTROL, 3U}, + {AUDIO_SAMPLING_FREQ_MASK, EP_REQUEST, MIN_REQUEST, AUDIO_SAMPLING_FREQ_CONTROL, 3U}, + {AUDIO_SAMPLING_FREQ_MASK, EP_REQUEST, MAX_REQUEST, AUDIO_SAMPLING_FREQ_CONTROL, 3U}, + {AUDIO_SAMPLING_FREQ_MASK, EP_REQUEST, RES_REQUEST, AUDIO_SAMPLING_FREQ_CONTROL, 3U}, +}; + +/******************************************************************************* + * Code + ******************************************************************************/ +/*! + * @brief initialize the audio instance. + * + * This function allocate the resource for audio instance. + * + * @param deviceHandle The device handle. + * @param classHandlePtr return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +usb_status_t USB_HostAudioInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandlePtr) +{ + audio_instance_t *audioPtr = (audio_instance_t *)USB_OsaMemoryAllocate(sizeof(audio_instance_t)); + uint32_t info_value; + + if (audioPtr == NULL) + { + return kStatus_USB_AllocFail; + } + + audioPtr->deviceHandle = deviceHandle; + audioPtr->controlIntfHandle = NULL; + audioPtr->streamIntfHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &info_value); + audioPtr->hostHandle = (usb_host_handle)info_value; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &info_value); + audioPtr->controlPipe = (usb_host_pipe_handle)info_value; + + *classHandlePtr = audioPtr; + return kStatus_USB_Success; +} + +/*! + * @brief de-initialize the audio instance. + * + * This function release the resource for audio instance. + * + * @param deviceHandle the device handle. + * @param classHandle the class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +usb_status_t USB_HostAudioDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_status_t status; + audio_instance_t *audioPtr = (audio_instance_t *)classHandle; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (classHandle != NULL) + { + if (audioPtr->isoInPipe != NULL) + { + status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->isoInPipe, NULL); + status = USB_HostClosePipe(audioPtr->hostHandle, audioPtr->isoInPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + audioPtr->isoInPipe = NULL; + } + if (audioPtr->isoOutPipe != NULL) + { + status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->isoOutPipe, NULL); + status = USB_HostClosePipe(audioPtr->hostHandle, audioPtr->isoOutPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + audioPtr->isoOutPipe = NULL; + } + USB_HostCloseDeviceInterface(deviceHandle, audioPtr->streamIntfHandle); + + if ((audioPtr->controlPipe != NULL) && (audioPtr->controlTransfer != NULL)) + { + status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->controlPipe, audioPtr->controlTransfer); + } + USB_HostCloseDeviceInterface(deviceHandle, audioPtr->controlIntfHandle); + USB_OsaMemoryFree(audioPtr); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +/*! + * @brief audiostream iso in pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void _USB_HostAudioStreamIsoInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + audio_instance_t *audioPtr = (audio_instance_t *)param; + + if (audioPtr->inCallbackFn != NULL) + { + audioPtr->inCallbackFn(audioPtr->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, status); + } + USB_HostFreeTransfer(audioPtr->hostHandle, transfer); +} + +/*! + * @brief audiostream iso out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void _USB_HostAudioStreamIsoOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + audio_instance_t *audioPtr = (audio_instance_t *)param; + + if (audioPtr->outCallbackFn != NULL) + { + audioPtr->outCallbackFn(audioPtr->outCallbackParam, transfer->transferBuffer, transfer->transferSofar, status); + } + USB_HostFreeTransfer(audioPtr->hostHandle, transfer); +} + +/*! + * @brief audiocontrol pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void _USB_HostAudioControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + audio_instance_t *audioPtr = (audio_instance_t *)param; + + audioPtr->controlTransfer = NULL; + if (audioPtr->controlCallbackFn != NULL) + { + audioPtr->controlCallbackFn(audioPtr->controlCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); + } + USB_HostFreeTransfer(audioPtr->hostHandle, transfer); + audioPtr->isSetup = 0U; +} + +/*! + * @brief hid send control transfer common code. + * + * @param classHandle the class handle. + * @param typeRequest setup packet request type. + * @param request setup packet request value. + * @param wvalue setup packet wvalue value. + * @param windex setup packet index value. + * @param wlength setup packet wlength value. + * @param data data buffer pointer will be transfer. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t _USB_HostAudioControl(usb_host_class_handle classHandle, + uint8_t typeRequest, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint16_t wlength, + uint8_t *data, + transfer_callback_t callbackFn, + void *callbackParam) +{ + audio_instance_t *audioPtr = (audio_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + audioPtr->controlCallbackFn = callbackFn; + audioPtr->controlCallbackParam = callbackParam; + + transfer->transferBuffer = data; + transfer->transferLength = wlength; + transfer->callbackFn = _USB_HostAudioControlCallback; + transfer->callbackParam = audioPtr; + transfer->setupPacket.bmRequestType = typeRequest; + transfer->setupPacket.bRequest = request; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(wvalue); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(windex); + + transfer->setupPacket.wLength = USB_SHORT_TO_LITTLE_ENDIAN(wlength); + audioPtr->isSetup = 1; + + if (USB_HostSendSetup(audioPtr->hostHandle, audioPtr->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failt for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(audioPtr->hostHandle, transfer); + return kStatus_USB_Error; + } + audioPtr->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +/*! + * @brief audio open interface. + * + * @param audioPtr audio instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t _USB_HostAudioOpenInterface(audio_instance_t *audioPtr) +{ + usb_status_t status; + uint8_t ep_index = 0U; + usb_host_pipe_init_t pipe_init; + usb_descriptor_endpoint_t *ep_desc = NULL; + usb_host_interface_t *interface_ptr; + + if (audioPtr->isoInPipe != NULL) + { + status = USB_HostClosePipe(audioPtr->hostHandle, audioPtr->isoInPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + audioPtr->isoInPipe = NULL; + } + if (audioPtr->isoOutPipe != NULL) + { + status = USB_HostClosePipe(audioPtr->hostHandle, audioPtr->isoOutPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + audioPtr->isoOutPipe = NULL; + } + + /* open interface pipes */ + interface_ptr = (usb_host_interface_t *)audioPtr->streamIntfHandle; + for (ep_index = 0U; ep_index < interface_ptr->epCount; ++ep_index) + { + ep_desc = interface_ptr->epList[ep_index].epDesc; + if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_ISOCHRONOUS)) + { + pipe_init.devInstance = audioPtr->deviceHandle; + pipe_init.pipeType = USB_ENDPOINT_ISOCHRONOUS; + pipe_init.direction = USB_IN; + pipe_init.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipe_init.interval = ep_desc->bInterval; + pipe_init.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipe_init.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK; + + audioPtr->inPacketSize = pipe_init.maxPacketSize; + audioPtr->isoEpNum = pipe_init.endpointAddress; + status = USB_HostOpenPipe(audioPtr->hostHandle, &audioPtr->isoInPipe, &pipe_init); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_audio_stream_set_interface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_ISOCHRONOUS)) + { + pipe_init.devInstance = audioPtr->deviceHandle; + pipe_init.pipeType = USB_ENDPOINT_ISOCHRONOUS; + pipe_init.direction = USB_OUT; + pipe_init.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipe_init.interval = ep_desc->bInterval; + pipe_init.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipe_init.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK; + + audioPtr->outPacketSize = pipe_init.maxPacketSize; + audioPtr->isoEpNum = pipe_init.endpointAddress; + status = USB_HostOpenPipe(audioPtr->hostHandle, &audioPtr->isoOutPipe, &pipe_init); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_audio_stream_set_interface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else + { + return kStatus_USB_Error; + } + } + + return kStatus_USB_Success; +} + +/*! + * @brief audio set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void _USB_HostAudioSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + audio_instance_t *audioPtr = (audio_instance_t *)param; + + audioPtr->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = _USB_HostAudioOpenInterface(audioPtr); + } + + if (audioPtr->controlCallbackFn != NULL) + { + audioPtr->controlCallbackFn(audioPtr->controlCallbackParam, NULL, 0U, status); + } + USB_HostFreeTransfer(audioPtr->hostHandle, transfer); +} + +/*! + * @brief set audioclass stream interface. + * + * This function bind the interface with the audio instance. + * + * @param classHandle The class handle. + * @param interfaceHandle The interface handle. + * @param alternateSetting The alternate setting value. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error send transfer fail, please reference to USB_HostSendSetup. + * @retval kStatus_USB_Busy callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall callback return status, the transfer is stall by device. + * @retval kStatus_USB_Error callback return status, open pipe fail, please reference to USB_HostOpenPipe. + */ +usb_status_t USB_HostAudioStreamSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status; + audio_instance_t *audioPtr = (audio_instance_t *)classHandle; + usb_host_interface_t *interface_ptr; + usb_host_transfer_t *transfer; + audio_descriptor_union_t ptr1; + uint32_t length = 0U, ep = 0U; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + audioPtr->streamIntfHandle = interfaceHandle; + + status = USB_HostOpenDeviceInterface(audioPtr->deviceHandle, interfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + + if (audioPtr->isoInPipe != NULL) + { + status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->isoInPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (audioPtr->isoOutPipe != NULL) + { + status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->isoOutPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + /* open interface pipes */ + interface_ptr = (usb_host_interface_t *)interfaceHandle; + ptr1.bufr = interface_ptr->interfaceExtension; + + length = 0U; + while (length < interface_ptr->interfaceExtensionLength) + { + if ((ptr1.common->bDescriptorType == 0x04U) && (ptr1.interface->bAlternateSetting == alternateSetting)) + { + interface_ptr->epCount = ptr1.interface->bNumEndpoints; + break; + } + ptr1.bufr += ptr1.common->bLength; + length += ptr1.common->bLength; + } + while (ep < interface_ptr->epCount) + { + if (ptr1.common->bDescriptorType == 0x24U) + { + if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AS_CS_GENERAL) + { + audioPtr->asIntfDesc = (usb_audio_stream_spepific_as_intf_desc_t *)ptr1.bufr; + } + else if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AS_CS_FORMAT_TYPE) + { + audioPtr->formatTypeDesc = (usb_audio_stream_format_type_desc_t *)ptr1.bufr; + } + else + { + } + } + if (ptr1.common->bDescriptorType == 0x05U) + { + interface_ptr->epList[ep].epDesc = (usb_descriptor_endpoint_t *)ptr1.bufr; + audioPtr->isoEndpDesc = (usb_audio_stream_specific_iso_endp_desc_t *)ptr1.bufr; + ep++; + ptr1.bufr += ptr1.common->bLength; + interface_ptr->epList[ep].epExtension = ptr1.bufr; + interface_ptr->epList[ep].epExtensionLength = ptr1.common->bLength; + break; + } + ptr1.bufr += ptr1.common->bLength; + } + + if (alternateSetting == 0U) + { + if (callbackFn != NULL) + { + status = _USB_HostAudioOpenInterface(audioPtr); + callbackFn(callbackParam, NULL, 0U, kStatus_USB_Success); + } + } + else + { + if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + audioPtr->controlCallbackFn = callbackFn; + audioPtr->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = _USB_HostAudioSetInterfaceCallback; + transfer->callbackParam = audioPtr; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_INTERFACE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)audioPtr->streamIntfHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(audioPtr->hostHandle, audioPtr->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + audioPtr->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(audioPtr->hostHandle, transfer); + } + } + + return status; +} + +/*! + * @brief set audioclass control interface. + * + * This function bind the interface with the audio instance. + * + * @param classHandle The class handle. + * @param interfaceHandle The interface handle. + * @param alternateSetting The alternate setting value. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error send transfer fail, please reference to USB_HostSendSetup. + * @retval kStatus_USB_Busy callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall callback return status, the transfer is stall by device. + * @retval kStatus_USB_Error callback return status, open pipe fail, please reference to USB_HostOpenPipe. + */ +usb_status_t USB_HostAudioControlSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status; + audio_instance_t *audioPtr = (audio_instance_t *)classHandle; + usb_host_interface_t *interface_ptr; + usb_host_transfer_t *transfer; + audio_descriptor_union_t ptr1; + uint32_t length = 0U; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + audioPtr->controlIntfHandle = interfaceHandle; + interface_ptr = (usb_host_interface_t *)interfaceHandle; + + status = USB_HostOpenDeviceInterface(audioPtr->deviceHandle, interfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + ptr1.bufr = interface_ptr->interfaceExtension; + + length = 0U; + + while (length < interface_ptr->interfaceExtensionLength) + { + if (((interface_ptr->interfaceDesc->bDescriptorType == 0x04U) && + (interface_ptr->interfaceDesc->bAlternateSetting == alternateSetting)) || + ((ptr1.common->bDescriptorType == 0x04U) && (ptr1.interface->bAlternateSetting == alternateSetting))) + { + break; + } + + ptr1.bufr += ptr1.common->bLength; + length += ptr1.common->bLength; + } + while (length < interface_ptr->interfaceExtensionLength) + { + if (ptr1.common->bDescriptorType == 0x24U) + { + if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AUDIO_CS_HEADER) + { + audioPtr->headerDesc = (usb_audio_ctrl_header_desc_t *)ptr1.bufr; + } + else if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AUDIO_CS_IT) + { + audioPtr->itDesc = (usb_audio_ctrl_it_desc_t *)ptr1.bufr; + } + else if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AUDIO_CS_OT) + { + audioPtr->otDesc = (usb_audio_ctrl_ot_desc_t *)ptr1.bufr; + } + else if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AUDIO_CS_FU) + { + audioPtr->fuDesc = (usb_audio_ctrl_fu_desc_t *)ptr1.bufr; + } + else + { + } + } + ptr1.bufr += ptr1.common->bLength; + length += ptr1.common->bLength; + } + + if (alternateSetting == 0U) + { + if (callbackFn != NULL) + { + callbackFn(callbackParam, NULL, 0U, kStatus_USB_Success); + } + } + else + { + if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + audioPtr->controlCallbackFn = callbackFn; + audioPtr->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = _USB_HostAudioControlCallback; + transfer->callbackParam = audioPtr; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_INTERFACE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)audioPtr->controlIntfHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(audioPtr->hostHandle, audioPtr->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + audioPtr->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(audioPtr->hostHandle, transfer); + } + } + + return status; +} + +/*! + * @brief get pipe max packet size. + * + * @param classHandle the class handle. + * @param pipeType It's value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or + * USB_ENDPOINT_INTERRUPT. + * Please reference to usb_spec.h + * @param direction pipe direction. + * + * @retval 0 The classHandle is NULL. + * @retval max packet size. + */ +uint16_t USB_HostAudioPacketSize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction) +{ + audio_instance_t *audioPtr = (audio_instance_t *)classHandle; + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (pipeType == USB_ENDPOINT_ISOCHRONOUS) + { + if (direction == USB_IN) + { + return audioPtr->inPacketSize; + } + else + { + return audioPtr->outPacketSize; + } + } + return 0U; +} + +/*! + * @brief audio stream receive data. + * + * This function implements audioreceiving data. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLen The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostRecv. + */ +usb_status_t USB_HostAudioStreamRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLen, + transfer_callback_t callbackFn, + void *callbackParam) +{ + audio_instance_t *audioPtr = (audio_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (audioPtr->isoInPipe == NULL) + { + return kStatus_USB_Error; + } + + if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + audioPtr->inCallbackFn = callbackFn; + audioPtr->inCallbackParam = callbackParam; + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLen; + transfer->callbackFn = _USB_HostAudioStreamIsoInPipeCallback; + transfer->callbackParam = audioPtr; + + if (USB_HostRecv(audioPtr->hostHandle, audioPtr->isoInPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(audioPtr->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +/*! + * @brief audio stream send data. + * + * This function implements audio sending data. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLen The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSend. + */ +usb_status_t USB_HostAudioStreamSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLen, + transfer_callback_t callbackFn, + void *callbackParam) +{ + audio_instance_t *audioPtr = (audio_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (audioPtr->isoOutPipe == NULL) + { + return kStatus_USB_Error; + } + + if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + audioPtr->outCallbackFn = callbackFn; + audioPtr->outCallbackParam = callbackParam; + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLen; + transfer->callbackFn = _USB_HostAudioStreamIsoOutPipeCallback; + transfer->callbackParam = audioPtr; + + if (USB_HostSend(audioPtr->hostHandle, audioPtr->isoOutPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostSend\r\n"); +#endif + USB_HostFreeTransfer(audioPtr->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +/*! + * @brief get audio stream current altsetting descriptor. + * + * This function implements get audio stream current altsetting descriptor. + * + * @param classHandle The class handle. + * @param asIntfDesc The pointer of class specific AS interface descriptor. + * @param formatTypeDesc The pointer of format type descriptor. + * @param isoEndpDesc The pointer of specific iso endp descriptor. + * + * @retval kStatus_USB_Success Get audio stream current altsetting descriptor request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * + */ +usb_status_t USB_HostAudioStreamGetCurrentAltsettingDescriptors( + + usb_host_class_handle classHandle, + usb_audio_stream_spepific_as_intf_desc_t **asIntfDesc, + usb_audio_stream_format_type_desc_t **formatTypeDesc, + usb_audio_stream_specific_iso_endp_desc_t **isoEndpDesc) +{ + audio_instance_t *audioPtr = (audio_instance_t *)classHandle; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + *asIntfDesc = audioPtr->asIntfDesc; + *formatTypeDesc = audioPtr->formatTypeDesc; + *isoEndpDesc = audioPtr->isoEndpDesc; + + return kStatus_USB_Success; +} + +/*! + * @brief usb audio feature unit request. + * + * This function implements usb audio feature unit request. + * + * @param classHandle The class handle. + * @param channelNo The channel number of audio feature unit. + * @param buf The feature unit request buffer pointer. + * @param cmdCode The feature unit command code, for example USB_AUDIO_GET_CUR_MUTE etc. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Feature unit request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail, please reference to USB_HostSendSetup. + * + */ +usb_status_t USB_HostAudioFeatureUnitRequest(usb_host_class_handle classHandle, + uint8_t channelNo, + void *buf, + uint32_t cmdCode, + transfer_callback_t callbackFn, + void *callbackParam) +{ /* Body */ + uint16_t windex; + uint16_t request_value; + audio_instance_t *if_ptr; + usb_audio_request_t *p_feature_request; + uint8_t *bmacontrols = NULL; + uint8_t atribute_index; + usb_status_t status = kStatus_USB_Error; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if_ptr = (audio_instance_t *)classHandle; + + /* pointer to command */ + p_feature_request = &(s_usbAudioFuRequests[cmdCode & 0xfU]); + /* get request value */ + request_value = (uint16_t)((uint16_t)((uint16_t)p_feature_request->requestValue << 8U) | channelNo); + + /* Check whether this attribute valid or not */ + if (if_ptr->fuDesc == NULL) + { + return kStatus_USB_Error; + } + windex = (uint16_t)((uint16_t)((uint16_t)(if_ptr->fuDesc->bunitid) << 8U) | (if_ptr->streamIfnum)); + atribute_index = if_ptr->fuDesc->bcontrolsize * channelNo; + + if (atribute_index < (if_ptr->fuDesc->blength - 7)) + { + bmacontrols = &(if_ptr->fuDesc->bcontrolsize); + } + + if (bmacontrols == NULL) + { + return kStatus_USB_Error; + } + + bmacontrols++; + if (bmacontrols[atribute_index] & p_feature_request->controlMask) + { + status = kStatus_USB_Success; + } + + if (kStatus_USB_Success == status) + { + status = _USB_HostAudioControl(classHandle, (p_feature_request->typeRequest | (cmdCode & 0x80U)), + (p_feature_request->codeRequest | (cmdCode & 0x80U)), request_value, windex, + p_feature_request->length, (uint8_t *)buf, callbackFn, callbackParam); + } + return status; +} + +/*! + * @brief usb audio endpoint request. + * + * This function implements usb audio endpoint request. + * + * @param classHandle The class handle. + * @param buf The feature unit buffer pointer. + * @param cmdCode The feature unit command code, for example USB_AUDIO_GET_CUR_PITCH etc . + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Endpoint request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail, please reference to USB_HostSendSetup. + * + */ +usb_status_t USB_HostAudioEndpointRequest( + usb_host_class_handle classHandle, void *buf, uint32_t cmdCode, transfer_callback_t callbackFn, void *callbackParam) +{ + uint8_t endp_num; + usb_status_t status = kStatus_USB_Error; + uint16_t request_value; + usb_audio_request_t *p_endpoint_request; + audio_instance_t *audioPtr; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + audioPtr = (audio_instance_t *)classHandle; + + /* pointer to command */ + p_endpoint_request = &(s_usbAudioEpRequests[cmdCode & 0xfU]); + /* get request value */ + request_value = (uint16_t)((uint16_t)((uint16_t)p_endpoint_request->requestValue << 8U)); + + /* Check whether this attribute valid or not */ + if (audioPtr->isoEndpDesc == NULL) + { + return kStatus_USB_Error; + } + if ((audioPtr->isoEndpDesc->bmattributes) && (p_endpoint_request->controlMask)) + { + status = kStatus_USB_Success; + } + else + { + status = kStatus_USB_InvalidRequest; + } + + if (kStatus_USB_Success == status) + { + /* Any isochronous pipe is supported? */ + if ((NULL == audioPtr->isoInPipe) && (NULL == audioPtr->isoOutPipe)) + { + return kStatus_USB_InvalidParameter; + } + else if (NULL != audioPtr->isoInPipe) + { + endp_num = (audioPtr->isoEpNum | 0x80U); + } + else + { + endp_num = audioPtr->isoEpNum; + } /* Endif */ + + status = _USB_HostAudioControl(classHandle, (p_endpoint_request->typeRequest | (cmdCode & 0x80U)), + (p_endpoint_request->codeRequest | (cmdCode & 0x80U)), request_value, endp_num, + p_endpoint_request->length, (uint8_t *)buf, callbackFn, callbackParam); + } + + return status; +} +#endif /* USB_HOST_CONFIG_AUDIO */ diff --git a/usb_1.1.0/host/class/usb_host_audio.h b/usb_1.1.0/host/class/usb_host_audio.h new file mode 100644 index 0000000..e6728fd --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_audio.h @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_HOST_AUDIO_H__ +#define __USB_HOST_AUDIO_H__ + +/******************************************************************************* + * Audio class private structure, enumerations, macros + ******************************************************************************/ +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* Structure for an AUDIO class descriptor according to the 6.2.1 in Audio specification*/ +#define AUDIO_FU_MUTE 0x01 +#define AUDIO_FU_VOLUME 0x02 +#define AUDIO_FU_BASS 0x03 +#define AUDIO_FU_MID 0x04 +#define AUDIO_FU_TREBLE 0x05 +#define AUDIO_FU_GRAPHIC_EQ 0x06 +#define AUDIO_FU_AGC 0x07 +#define AUDIO_FU_DELAY 0x08 +#define AUDIO_FU_BASS_BOOST 0x09 + +/* Audio class codes */ +#define SET_COMMAND (0x00) +#define GET_COMMAND (0x80) +#define CUR_REQUEST (0x01) +#define MIN_REQUEST (0x02) +#define MAX_REQUEST (0x03) +#define RES_REQUEST (0x04) +#define MEM_REQUEST (0x05) +#define GET_STATUS (0xFF) + +#define ITF_REQUEST (0x21) +#define EP_REQUEST (0x22) + +#define AUDIO_FU_MUTE_MASK 0x01 +#define AUDIO_FU_VOLUME_MASK 0x02 +#define AUDIO_FU_BASS_MASK 0x04 +#define AUDIO_FU_MID_MASK 0x08 +#define AUDIO_FU_TREBLE_MASK 0x10 +#define AUDIO_FU_GRAPHIC_EQ_MASK 0x20 +#define AUDIO_FU_AGC_MASK 0x40 +#define AUDIO_FU_DELAY_MASK 0x80 +#define AUDIO_FU_BASS_BOOST_MASK 0x01 + +/* USB audio Endpoint Control Selectors */ +#define AUDIO_EP_CONTROL_UNDEFINED (0x00) +#define AUDIO_SAMPLING_FREQ_CONTROL (0x01) +#define AUDIO_PITCH_CONTROL (0x02) + +#define AUDIO_SAMPLING_FREQ_MASK (0x01) +#define AUDIO_PITCH_MASK (0x02) +typedef enum _fu_request_code +{ + kUSB_AudioCurMute = 0, + kUSB_AudioCurVolume, + kUSB_AudioMinVolume, + kUSB_AudioMaxVolume, + kUSB_AudioResVolume, + NUMBER_OF_FEATURE_COMMANDS, +} fu_request_code_t; + +typedef enum _ep_request_code +{ + kUSB_AudioCurPitch = 0, + kUSB_AudioCurSamplingFreq, + kUSB_AudioMinSamplingFreq, + kUSB_AudioMaxSamplingFreq, + kUSB_AudioResSamplingFreq, + NUMBER_OF_ENDPOINT_COMMANDS, +} ep_request_code_t; + +typedef union _audio_descriptor_union +{ + uint8_t *bufr; + usb_descriptor_common_t *common; + usb_descriptor_device_t *device; + usb_descriptor_configuration_t *configuration; + usb_descriptor_interface_t *interface; + usb_descriptor_endpoint_t *endpoint; +} audio_descriptor_union_t; + +/* Audio command structure */ +typedef struct _usb_audio_request +{ + uint8_t controlMask; + uint8_t typeRequest; + uint8_t codeRequest; + uint8_t requestValue; + uint8_t length; +} usb_audio_request_t; + +#define USB_DESC_SUBTYPE_AUDIO_CS_HEADER 0x01 +#define USB_DESC_SUBTYPE_AUDIO_CS_IT 0x02 +#define USB_DESC_SUBTYPE_AUDIO_CS_OT 0x03 +#define USB_DESC_SUBTYPE_AUDIO_CS_FU 0x06 +#define USB_DESC_CLASS_ENDPOINT_GENERAL 0x01 +#define USB_DESC_SUBTYPE_AS_CS_GENERAL 0X01 +#define USB_DESC_SUBTYPE_AS_CS_FORMAT_TYPE 0X02 + +/******************************************************************************* + * Audio class public structure, enumeration, macros, functions + ******************************************************************************/ +/*! + * @addtogroup usb_host_audio_drv + * @{ + */ +/*! @brief Audio class code */ +#define USB_AUDIO_CLASS_CODE 1 +/*! @brief Audio class control interface code*/ +#define USB_AUDIO_SUBCLASS_CODE_CONTROL 1 +/*! @brief Audio class stream interface code*/ +#define USB_AUDIO_SUBCLASS_CODE_AUDIOSTREAMING 2 + +/*! @brief AUDIO class-specific feature unit get current mute command*/ +#define USB_AUDIO_GET_CUR_MUTE 0x80 +/*! @brief AUDIO class-specific feature unit set current mute command*/ +#define USB_AUDIO_SET_CUR_MUTE 0x00 +/*! @brief AUDIO class-specific feature unit get current volume command*/ +#define USB_AUDIO_GET_CUR_VOLUME 0x81 +/*! @brief AUDIO class-specific feature unit set current volume command*/ +#define USB_AUDIO_SET_CUR_VOLUME 0x01 +/*! @brief AUDIO class-specific feature unit get minimum volume command*/ +#define USB_AUDIO_GET_MIN_VOLUME 0x82 +/*! @brief AUDIO class-specific feature unit set minimum volume command*/ +#define USB_AUDIO_SET_MIN_VOLUME 0x02 +/*! @brief AUDIO class-specific feature unit get maximum volume command*/ +#define USB_AUDIO_GET_MAX_VOLUME 0x83 +/*! @brief AUDIO class-specific feature unit set maximum volume command*/ +#define USB_AUDIO_SET_MAX_VOLUME 0x03 +/*! @brief AUDIO class-specific feature unit get resolution volume command*/ +#define USB_AUDIO_GET_RES_VOLUME 0x84 +/*! @brief AUDIO class-specific feature unit set resolution volume command*/ +#define USB_AUDIO_SET_RES_VOLUME 0x04 + +/*! @brief AUDIO class-specific endpoint get current pitch control command*/ +#define USB_AUDIO_GET_CUR_PITCH 0x80 +/*! @brief AUDIO class-specific endpoint set current pitch control command*/ +#define USB_AUDIO_SET_CUR_PITCH 0x00 +/*! @brief AUDIO class-specific endpoint get current sampling frequency command*/ +#define USB_AUDIO_GET_CUR_SAMPLING_FREQ 0x81 +/*! @brief AUDIO class-specific endpoint set current sampling frequency command*/ +#define USB_AUDIO_SET_CUR_SAMPLING_FREQ 0x01 +/*! @brief AUDIO class-specific endpoint get minimum sampling frequency command*/ +#define USB_AUDIO_GET_MIN_SAMPLING_FREQ 0x82 +/*! @brief AUDIO class-specific endpoint set minimum sampling frequency command*/ +#define USB_AUDIO_SET_MIN_SAMPLING_FREQ 0x02 +/*! @brief AUDIO class-specific endpoint get maximum sampling frequency command*/ +#define USB_AUDIO_GET_MAX_SAMPLING_FREQ 0x83 +/*! @brief AUDIO class-specific endpoint set maximum sampling frequency command*/ +#define USB_AUDIO_SET_MAX_SAMPLING_FREQ 0x03 +/*! @brief AUDIO class-specific endpoint get resolution sampling frequency command*/ +#define USB_AUDIO_GET_RES_SAMPLING_FREQ 0x84 +/*! @brief AUDIO class-specific endpoint set resolution sampling frequency command*/ +#define USB_AUDIO_SET_RES_SAMPLING_FREQ 0x04 + +/*! @brief Audio control interface header descriptor structure */ +typedef struct _usb_audio_ctrl_header_desc +{ + uint8_t blength; /*!< Total size of the header descriptor*/ + uint8_t bdescriptortype; /*!< Descriptor type of audio header descriptor*/ + uint8_t bdescriptorsubtype; /*!< Subtype of an audio header descriptor*/ + uint8_t bcdcdc[2]; /*!< Audio Device Class Specification Release Number in Binary-Coded Decimal*/ + uint8_t wtotallength[2]; /*!< Total number of bytes returned for the class-specific AudioControl interface + descriptor. Includes the combined length of this descriptor header and all unit and + terminal descriptors.*/ + uint8_t bincollection; /*!< The number of AudioStreaming and MIDIStreaming interfaces in the Audio Interface + Collection to which this AudioControl interface belongs to*/ +} usb_audio_ctrl_header_desc_t; + +/*! @brief Audio control interface input terminal descriptor structure */ +typedef struct _usb_audio_ctrl_it_desc +{ + uint8_t blength; /*!< Total size of the input terminal descriptor*/ + uint8_t bdescriptortype; /*!< Descriptor type of audio input terminal descriptor*/ + uint8_t bdescriptorsubtype; /*!< Subtype of audio input terminal descriptor*/ + uint8_t bterminalid; /*!< Constant uniquely identifying the Terminal within the audio function. This value is used + in all requests to address this Terminal*/ + uint8_t wterminaltype[2]; /*!< Constant characterizing the type of Terminal*/ + uint8_t bassocterminal; /*!< ID of the Output Terminal to which this Input Terminal is associated*/ + uint8_t bnrchannels; /*!< Number of logical output channels in the Terminal's output audio channel cluster*/ + uint8_t wchannelconfig[2]; /*!< Describes the spatial location of the logical channels.*/ + uint8_t ichannelnames; /*!< Index of a string descriptor, describing the name of the first logical channel*/ + uint8_t iterminal; /*!controlTransfer = NULL; + if (cdcInstance->inCallbackFn != NULL) + { + /* callback to application */ + cdcInstance->inCallbackFn(cdcInstance->inCallbackParam, cdcInstance->stallDataBuffer, + cdcInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); +} + +static void USB_HostCdcClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; + + cdcInstance->controlTransfer = NULL; + if (cdcInstance->outCallbackFn != NULL) + { + /* callback to application */ + cdcInstance->outCallbackFn(cdcInstance->outCallbackParam, cdcInstance->stallDataBuffer, + cdcInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); +} +static void USB_HostCdcClearInterruptHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; + + cdcInstance->controlTransfer = NULL; + if (cdcInstance->interruptCallbackFn != NULL) + { + /* callback to application */ + cdcInstance->interruptCallbackFn(cdcInstance->interruptCallbackParam, cdcInstance->stallDataBuffer, + cdcInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostCdcClearHalt(usb_host_cdc_instance_struct_t *cdcInstance, + usb_host_transfer_t *stallTransfer, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint) +{ + usb_status_t status; + usb_host_transfer_t *transfer; + + /* malloc one transfer */ + status = USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + cdcInstance->stallDataBuffer = stallTransfer->transferBuffer; + cdcInstance->stallDataLength = stallTransfer->transferSofar; + /* save the application callback function */ + cdcInstance->controlCallbackFn = NULL; + cdcInstance->controlCallbackParam = NULL; + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = cdcInstance; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_CLEAR_FEATURE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(endpoint); + transfer->setupPacket.wLength = 0; + status = USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + } + cdcInstance->controlTransfer = transfer; + + return status; +} +#endif + +/*! + * @brief cdc data in pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostCdcDataInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostCdcClearHalt(cdcInstance, transfer, USB_HostCdcClearInHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | + ((usb_host_pipe_t *)cdcInstance->inPipe)->endpointAddress)) == kStatus_USB_Success) + { + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + return; + } + } +#endif + + if (cdcInstance->inCallbackFn != NULL) + { + cdcInstance->inCallbackFn(cdcInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); + } + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); +} + +/*! + * @brief cdc data out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostCdcDataOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostCdcClearHalt(cdcInstance, transfer, USB_HostCdcClearOutHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | + ((usb_host_pipe_t *)cdcInstance->outPipe)->endpointAddress)) == kStatus_USB_Success) + { + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + return; + } + } +#endif + if (cdcInstance->outCallbackFn != NULL) + { + cdcInstance->outCallbackFn(cdcInstance->outCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); + } + + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); +} + +/*! + * @brief cdc data out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostCdcInterruptPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostCdcClearHalt( + cdcInstance, transfer, USB_HostCdcClearInterruptHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)cdcInstance->interruptPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + return; + } + } +#endif + + if (cdcInstance->interruptCallbackFn != NULL) + { + cdcInstance->interruptCallbackFn(cdcInstance->interruptCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); +} + +/*! + * @brief cdc data out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostCdcControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; + + if (cdcInstance->controlCallbackFn != NULL) + { + cdcInstance->controlCallbackFn(cdcInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); +} + +/*! + * @brief cdc open data interface. + * + * @param cdcInstance cdc instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostCdcOpenDataInterface(usb_host_cdc_instance_struct_t *cdcInstance) +{ + usb_status_t status; + uint8_t ep_index = 0; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *ep_desc = NULL; + usb_host_interface_t *interfaceHandle; + + if (cdcInstance->inPipe != NULL) + { + status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->inPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + cdcInstance->inPipe = NULL; + } + + if (cdcInstance->outPipe != NULL) + { + status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->outPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + cdcInstance->outPipe = NULL; + } + status = USB_HostOpenDeviceInterface(cdcInstance->deviceHandle, cdcInstance->dataInterfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + /* open interface pipes */ + interfaceHandle = (usb_host_interface_t *)cdcInstance->dataInterfaceHandle; + + for (ep_index = 0; ep_index < interfaceHandle->epCount; ++ep_index) + { + ep_desc = interfaceHandle->epList[ep_index].epDesc; + if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = cdcInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = ep_desc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + cdcInstance->bulkInPacketSize = pipeInit.maxPacketSize; + status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->inPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_audio_set_interface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = cdcInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = ep_desc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + cdcInstance->bulkOutPacketSize = pipeInit.maxPacketSize; + status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->outPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_cdc_set_dat_interface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else + { + } + } + return kStatus_USB_Success; +} + +/*! + * @brief cdc set data interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostCdcSetDataInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; + + cdcInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = USB_HostCdcOpenDataInterface(cdcInstance); + } + + if (cdcInstance->controlCallbackFn != NULL) + { + cdcInstance->controlCallbackFn(cdcInstance->controlCallbackParam, NULL, 0, status); + } + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); +} + +/*! + * @brief cdc open control interface. + * + * @param cdcInstance cdc instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostCdcOpenControlInterface(usb_host_cdc_instance_struct_t *cdcInstance) +{ + usb_status_t status; + uint8_t ep_index = 0; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *ep_desc = NULL; + usb_host_interface_t *interfaceHandle; + + if (cdcInstance->interruptPipe != NULL) + { + status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->interruptPipe, NULL); + status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->interruptPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + cdcInstance->interruptPipe = NULL; + } + + status = USB_HostOpenDeviceInterface(cdcInstance->deviceHandle, cdcInstance->controlInterfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + /* open interface pipes */ + interfaceHandle = (usb_host_interface_t *)cdcInstance->controlInterfaceHandle; + + for (ep_index = 0; ep_index < interfaceHandle->epCount; ++ep_index) + { + ep_desc = interfaceHandle->epList[ep_index].epDesc; + if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + pipeInit.devInstance = cdcInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = ep_desc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + cdcInstance->packetSize = pipeInit.maxPacketSize; + + status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->interruptPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostCdcSetControlInterface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + } + return kStatus_USB_Success; +} + +/*! + * @brief cdc set control interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostCdcSetContorlInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; + + cdcInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = USB_HostCdcOpenControlInterface(cdcInstance); + } + + if (cdcInstance->controlCallbackFn != NULL) + { + cdcInstance->controlCallbackFn(cdcInstance->controlCallbackParam, NULL, 0, status); + } + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); +} + +/*! + * @brief initialize the cdc instance. + * + * This function allocate the resource for cdc instance. + * + * @param deviceHandle the device handle. + * @param classHandle return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +usb_status_t USB_HostCdcInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + usb_host_cdc_instance_struct_t *control_ptr = + (usb_host_cdc_instance_struct_t *)USB_OsaMemoryAllocate(sizeof(usb_host_cdc_instance_struct_t)); + uint32_t info_value; + + if (control_ptr == NULL) + { + return kStatus_USB_AllocFail; + } + + control_ptr->deviceHandle = deviceHandle; + control_ptr->controlInterfaceHandle = NULL; + control_ptr->dataInterfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &info_value); + control_ptr->hostHandle = (usb_host_handle)info_value; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &info_value); + control_ptr->controlPipe = (usb_host_pipe_handle)info_value; + + *classHandle = control_ptr; + return kStatus_USB_Success; +} + +/*! + * @brief set control interface. + * + * This function bind the control interface with the cdc instance. + * + * @param classHandle the class handle. + * @param interfaceHandle the control interface handle. + * @param alternateSetting the alternate setting value. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error send transfer fail, please reference to USB_HostSendSetup. + * @retval kStatus_USB_Busy callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall callback return status, the transfer is stall by device. + * @retval kStatus_USB_Error callback return status, open pipe fail, please reference to USB_HostOpenPipe. + */ +usb_status_t USB_HostCdcSetControlInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status; + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + usb_host_transfer_t *transfer; + + status = kStatus_USB_Success; + if (classHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + cdcInstance->controlInterfaceHandle = interfaceHandle; + + /* cancel transfers */ + if (cdcInstance->interruptPipe != NULL) + { + status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->interruptPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (alternateSetting == 0) + { + if (callbackFn != NULL) + { + status = USB_HostCdcOpenControlInterface(cdcInstance); + callbackFn(callbackParam, NULL, 0, status); + } + } + else + { + if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + cdcInstance->controlCallbackFn = callbackFn; + cdcInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = USB_HostCdcSetContorlInterfaceCallback; + transfer->callbackParam = cdcInstance; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_INTERFACE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)cdcInstance->controlInterfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + cdcInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + } + } + + return status; +} + +/*! + * @brief set data interface. + * + * This function bind the control interface with the cdc instance. + * + * @param classHandle the class handle. + * @param interfaceHandle the data interface handle. + * @param alternateSetting the alternate setting value. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error send transfer fail, please reference to USB_HostSendSetup. + * @retval kStatus_USB_Busy callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall callback return status, the transfer is stall by device. + * @retval kStatus_USB_Error callback return status, open pipe fail, please reference to USB_HostOpenPipe. + */ +usb_status_t USB_HostCdcSetDataInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status; + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + usb_host_transfer_t *transfer; + + status = kStatus_USB_Success; + if (classHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + cdcInstance->dataInterfaceHandle = interfaceHandle; + + /* cancel transfers */ + if (cdcInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->inPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (cdcInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->outPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (alternateSetting == 0) + { + if (callbackFn != NULL) + { + status = USB_HostCdcOpenDataInterface(cdcInstance); + callbackFn(callbackParam, NULL, 0, status); + } + } + else + { + if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + cdcInstance->controlCallbackFn = callbackFn; + cdcInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = USB_HostCdcSetDataInterfaceCallback; + transfer->callbackParam = cdcInstance; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_INTERFACE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)cdcInstance->dataInterfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + cdcInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + } + } + + return status; +} + +/*! + * @brief de-initialize the cdc instance. + * + * This function release the resource for cdc instance. + * + * @param deviceHandle the device handle. + * @param classHandle the class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +usb_status_t USB_HostCdcDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_status_t status; + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (classHandle != NULL) + { + if (cdcInstance->interruptPipe != NULL) + { + status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->interruptPipe, NULL); + status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->interruptPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + cdcInstance->interruptPipe = NULL; + } + + USB_HostCloseDeviceInterface(deviceHandle, cdcInstance->controlInterfaceHandle); + + if (cdcInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->inPipe, NULL); + status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->inPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + cdcInstance->inPipe = NULL; + } + if (cdcInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->outPipe, NULL); + status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->outPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + cdcInstance->outPipe = NULL; + } + if ((cdcInstance->controlPipe != NULL) && (cdcInstance->controlTransfer != NULL)) + { + status = + USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->controlPipe, cdcInstance->controlTransfer); + } + USB_HostCloseDeviceInterface(deviceHandle, cdcInstance->dataInterfaceHandle); + + USB_OsaMemoryFree(cdcInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +/*! + * @brief receive data. + * + * This function implements cdc receiving data. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostRecv. + */ +usb_status_t USB_HostCdcDataRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (cdcInstance->inPipe == NULL) + { + return kStatus_USB_Error; + } + + if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + cdcInstance->inCallbackFn = callbackFn; + cdcInstance->inCallbackParam = callbackParam; + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostCdcDataInPipeCallback; + transfer->callbackParam = cdcInstance; + + if (USB_HostRecv(cdcInstance->hostHandle, cdcInstance->inPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +/*! + * @brief send data. + * + * This function implements cdc sending data. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSend. + */ +usb_status_t USB_HostCdcDataSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (cdcInstance->outPipe == NULL) + { + return kStatus_USB_Error; + } + + if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + cdcInstance->outCallbackFn = callbackFn; + cdcInstance->outCallbackParam = callbackParam; + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostCdcDataOutPipeCallback; + transfer->callbackParam = cdcInstance; + + if (USB_HostSend(cdcInstance->hostHandle, cdcInstance->outPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostSend\r\n"); +#endif + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} + +/*! + * @brief interrupt receive data. + * + * This function implements interrupt receiving data. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostRecv. + */ +usb_status_t USB_HostCdcInterruptRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (cdcInstance->interruptPipe == NULL) + { + return kStatus_USB_Error; + } + + if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + cdcInstance->interruptCallbackFn = callbackFn; + cdcInstance->interruptCallbackParam = callbackParam; + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostCdcInterruptPipeCallback; + transfer->callbackParam = cdcInstance; + + if (USB_HostRecv(cdcInstance->hostHandle, cdcInstance->interruptPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failt to usb_interrupt_recv\r\n"); +#endif + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} +/*! + * @brief get pipe max packet size. + * + * @param[in] classHandle the class handle. + * @param[in] pipeType It's value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or + * USB_ENDPOINT_INTERRUPT. + * Please reference to usb_spec.h + * @param[in] direction pipe direction. + * + * @retval 0 The classHandle is NULL. + * @retval max packet size. + */ +uint16_t USB_HostCdcGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + if (classHandle == NULL) + { + return 0; + } + + if (pipeType == USB_ENDPOINT_BULK) + { + if (direction == USB_IN) + { + return cdcInstance->bulkInPacketSize; + } + else + { + return cdcInstance->bulkOutPacketSize; + } + } + + return 0; +} + +/*! + * @brief cdc send control transfer common code. + * + * @param classHandle the class handle. + * @param request_type setup packet request type. + * @param request setup packet request value. + * @param wvalue_l setup packet wvalue low byte. + * @param wvalue_h setup packet wvalue high byte. + * @param wlength setup packet wlength value. + * @param data data buffer pointer + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @return An error code or kStatus_USB_Success. + */ +usb_status_t USB_HostCdcControl(usb_host_class_handle classHandle, + uint8_t request_type, + uint8_t request, + uint8_t wvalue_l, + uint8_t wvalue_h, + uint16_t wlength, + uint8_t *data, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + cdcInstance->controlCallbackFn = callbackFn; + cdcInstance->controlCallbackParam = callbackParam; + + transfer->transferBuffer = data; + transfer->transferLength = wlength; + transfer->callbackFn = USB_HostCdcControlPipeCallback; + transfer->callbackParam = cdcInstance; + transfer->setupPacket.bmRequestType = request_type; + transfer->setupPacket.bRequest = request; + transfer->setupPacket.wValue = (wvalue_l | (uint16_t)((uint16_t)wvalue_h << 8)); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)cdcInstance->controlInterfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wLength = USB_SHORT_TO_LITTLE_ENDIAN(wlength); + + if (USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failt for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + cdcInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +/*! + * @brief cdc get line coding. + * + * This function implements cdc GetLineCoding request.refer to pstn spec. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostCdcGetAcmLineCoding(usb_host_class_handle classHandle, + usb_host_cdc_line_coding_struct_t *uartLineCoding, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostCdcControl( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_CDC_GET_LINE_CODING, 0, 0, 7, (uint8_t *)uartLineCoding, callbackFn, callbackParam); +} + +/*! + * @brief cdc setControlLineState. + * + * This function implements cdc etControlLineState request.refer to pstn spec. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostCdcSetAcmCtrlState( + usb_host_class_handle classHandle, uint8_t dtr, uint8_t rts, transfer_callback_t callbackFn, void *callbackParam) +{ + uint16_t lineState = 0; + + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + + lineState = dtr ? USB_HOST_CDC_CONTROL_LINE_STATE_DTR : 0; + lineState |= rts ? USB_HOST_CDC_CONTROL_LINE_STATE_RTS : 0; + return USB_HostCdcControl( + cdcInstance, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_CDC_SET_CONTROL_LINE_STATE, USB_SHORT_GET_LOW(lineState), USB_SHORT_GET_HIGH(lineState), 0, NULL, + callbackFn, callbackParam); +} + +/*! + * @brief cdc get acm descriptor. + * + * This function is hunting for class specific acm decriptor in the configuration ,get the corresponding + * descriptor . + * + * @param classHandle the class handle. + * @param headDesc the head function descriptor pointer. + * @param callManageDesc the call management functional descriptor pointer. + * @param abstractControlDesc the abstract control management functional pointer. + * @param unionInterfaceDesc the union functional descriptor pointer. + * + * @retval kStatus_USB_Error analyse descriptor error. + */ +usb_status_t USB_HostCdcGetAcmDescriptor(usb_host_class_handle classHandle, + usb_host_cdc_head_function_desc_struct_t **headDesc, + usb_host_cdc_call_manage_desc_struct_t **callManageDesc, + usb_host_cdc_abstract_control_desc_struct_t **abstractControlDesc, + usb_host_cdc_union_interface_desc_struct_t **unionInterfaceDesc) +{ + usb_status_t status; + usb_descriptor_union_t *ptr1; + uint32_t end_address; + usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; + usb_cdc_func_desc_struct_t *cdc_common_ptr; + usb_host_interface_t *interface_handle; + + status = kStatus_USB_Success; + interface_handle = (usb_host_interface_t *)cdcInstance->controlInterfaceHandle; + ptr1 = (usb_descriptor_union_t *)interface_handle->interfaceExtension; + end_address = (uint32_t)(interface_handle->interfaceExtension + interface_handle->interfaceExtensionLength); + + while ((uint32_t)ptr1 < end_address) + { + cdc_common_ptr = (usb_cdc_func_desc_struct_t *)&ptr1->common; + switch (cdc_common_ptr->common.bDescriptorSubtype) + { + case USB_HOST_DESC_SUBTYPE_HEADER: + *headDesc = &cdc_common_ptr->head; + if ((((uint32_t)((*headDesc)->bcdCDC[1]) << 8) + (*headDesc)->bcdCDC[0]) > 0x0110) + { + status = kStatus_USB_Error; + } + break; + case USB_HOST_DESC_SUBTYPE_UNION: + if (cdc_common_ptr->unionDesc.bControlInterface == interface_handle->interfaceDesc->bInterfaceNumber) + { + *unionInterfaceDesc = &cdc_common_ptr->unionDesc; + } + else + { + status = kStatus_USB_Error; + } + break; + case USB_HOST_DESC_SUBTYPE_CM: + *callManageDesc = &cdc_common_ptr->callManage; + break; + case USB_HOST_DESC_SUBTYPE_ACM: + *abstractControlDesc = &cdc_common_ptr->acm; + break; + default: + break; + } + + if (kStatus_USB_Success != status) + { + break; + } + ptr1 = (usb_descriptor_union_t *)((uint8_t *)ptr1 + ptr1->common.bLength); + } + cdcInstance->headDesc = *headDesc; + cdcInstance->callManageDesc = *callManageDesc; + cdcInstance->abstractControlDesc = *abstractControlDesc; + cdcInstance->unionInterfaceDesc = *unionInterfaceDesc; + return status; +} + +#endif diff --git a/usb_1.1.0/host/class/usb_host_cdc.h b/usb_1.1.0/host/class/usb_host_cdc.h new file mode 100644 index 0000000..0acc181 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_cdc.h @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_HOST_CDC_H__ +#define __USB_HOST_CDC_H__ + +/*! + * @addtogroup usb_host_cdc_drv + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Class-specific request PSTN*/ +/*! @brief CDC class-specific request (SET_LINE_CODING) */ +#define USB_HOST_CDC_SET_LINE_CODING 0x20U +/*! @brief CDC class-specific request (GET_LINE_CODING) */ +#define USB_HOST_CDC_GET_LINE_CODING 0x21U +/*! @brief CDC class-specific request (SET_CONTROL_LINE_STATE) */ +#define USB_HOST_CDC_SET_CONTROL_LINE_STATE 0x22U + +/*! @brief CDC class-specific notifications(SerialState) bitmap*/ +#define USB_HOST_ACM_UART_STATE_BITMAP_BTXCARRITER 0x01U +/*! @brief CDC class-specific notifications(SerialState) bitmap*/ +#define USB_HOST_ACM_UART_STATE_BITMAP_BRXCARRITER 0x02U +/*! @brief CDC class-specific notifications(SerialState) bitmap*/ +#define USB_HOST_ACM_UART_STATE_BITMAP_BBREAK 0x04U +/*! @brief CDC class-specific notifications(SerialState) bitmap*/ +#define USB_HOST_ACM_UART_STATE_BITMAP_BBRINGSIGNAL 0x10U + +/*! @brief CDC class-specific request (SET_CONTROL_LINE_STATE) bitmap*/ +#define USB_HOST_CDC_CONTROL_LINE_STATE_DTR 0x01U +/*! @brief CDC class-specific request (SET_CONTROL_LINE_STATE) bitmap*/ +#define USB_HOST_CDC_CONTROL_LINE_STATE_RTS 0x02U + +/*CDC SPEC*/ +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_HEADER 0x00U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_CM 0x01U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_ACM 0x02U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_DLM 0x03U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_TR 0x04U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_TC_LSR 0x05U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_UNION 0x06U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_CS 0x07U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_TOM 0x08U + +/*See the CDC specification page20*/ +/*! @brief CDC class-specific code, Communications Interface Class Code*/ +#define USB_HOST_CDC_COMMUNICATIONS_CLASS_CODE 0x02U +/*! @brief CDC class-specific code,Communications Class Subclass Codes*/ +#define USB_HOST_CDC_SUBCLASS_ACM_CODE 0x02U +/*No class specific protocol required. See the CDC specification page22*/ +#define USB_HOST_CDC_PROTOCOL_CODE 0x00U +/*! @brief CDC class-specific code,Data Class Interface Codes*/ +#define USB_HOST_CDC_DATA_CLASS_CODE 0x0AU +/* This field is unused for Data Class interfaces and should have a value of 00h.*/ +#define USB_HOST_CDC_DATA_SUBCLASS_CODE 0x00U +/*No class-specific protocol required. See the CDC specification page22*/ +#define USB_HOST_CDC_DATA_PROTOCOL_CODE 0x00U + +/*! @brief CDC GetLineCoding structure according to the 6.3 in PSTN specification */ +typedef struct _usb_host_cdc_line_coding_struct +{ + uint32_t dwDTERate; /*!< Data terminal rate, in bits per second*/ + uint8_t bCharFormat; /*!< Stop bits*/ + uint8_t bParityType; /*!< Parity*/ + uint8_t bDataBits; /*!< Data bits (5, 6, 7, 8 or 16).*/ +} usb_host_cdc_line_coding_struct_t; + +/*! @brief CDC GetLineCoding structure according to the 6.3 in PSTN specification */ +typedef struct _usb_host_cdc_control_line_state_struct +{ + uint16_t line_state; /*!< D1, This signal corresponds to V.24 signal 105 and RS-232 signal RTS*/ + /*!< D0, This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR*/ +} usb_host_cdc_control_line_state_struct_t; + +/*! @brief CDC SerialState structure according to the 6.5.4 in PSTN specification */ +typedef struct _usb_host_cdc_acm_state_struct +{ + uint8_t reserved[8]; /*!< Notify response by the device, this is used as notification header, which is returned by the + device */ + uint8_t bmstate; /*!< UART State Bitmap Values*/ + uint8_t reserved1[1]; /*!< Fix 4B align issue*/ + uint8_t reserved2[2]; /*!< Fix 4B align issue*/ +} usb_host_cdc_acm_state_struct_t; + +/*! @brief CDC Header Functional Descriptor structure according to the 5.2.3 in CDC specification */ +typedef struct _usb_host_cdc_head_function_desc_struct +{ + uint8_t bFunctionLength; /*!controlTransfer = NULL; + if (hidInstance->inCallbackFn != NULL) + { + /* callback to application */ + hidInstance->inCallbackFn(hidInstance->inCallbackParam, hidInstance->stallDataBuffer, + hidInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static void USB_HostHidClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)param; + + hidInstance->controlTransfer = NULL; + if (hidInstance->outCallbackFn != NULL) + { + /* callback to application */ + hidInstance->outCallbackFn(hidInstance->outCallbackParam, hidInstance->stallDataBuffer, + hidInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostHidClearHalt(usb_host_hid_instance_t *hidInstance, + usb_host_transfer_t *stallTransfer, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint) +{ + usb_status_t status; + usb_host_transfer_t *transfer; + + /* malloc one transfer */ + status = USB_HostMallocTransfer(hidInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + hidInstance->stallDataBuffer = stallTransfer->transferBuffer; + hidInstance->stallDataLength = stallTransfer->transferSofar; + /* save the application callback function */ + hidInstance->controlCallbackFn = NULL; + hidInstance->controlCallbackParam = NULL; + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = hidInstance; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_CLEAR_FEATURE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(endpoint); + transfer->setupPacket.wLength = 0; + status = USB_HostSendSetup(hidInstance->hostHandle, hidInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + } + hidInstance->controlTransfer = transfer; + + return status; +} +#endif + +static void USB_HostHidInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)param; + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostHidClearHalt(hidInstance, transfer, USB_HostHidClearInHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | + ((usb_host_pipe_t *)hidInstance->inPipe)->endpointAddress)) == kStatus_USB_Success) + { + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return; + } + } +#endif + if (hidInstance->inCallbackFn != NULL) + { + hidInstance->inCallbackFn(hidInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); /* callback to application */ + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static void USB_HostHidOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)param; + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostHidClearHalt(hidInstance, transfer, USB_HostHidClearOutHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | + ((usb_host_pipe_t *)hidInstance->outPipe)->endpointAddress)) == kStatus_USB_Success) + { + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return; + } + } +#endif + if (hidInstance->outCallbackFn != NULL) + { + hidInstance->outCallbackFn(hidInstance->outCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); /* callback to application */ + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static void USB_HostHidControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)param; + + hidInstance->controlTransfer = NULL; + if (hidInstance->controlCallbackFn != NULL) + { + hidInstance->controlCallbackFn(hidInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); /* callback to application */ + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostHidOpenInterface(usb_host_hid_instance_t *hidInstance) +{ + usb_status_t status; + uint8_t epIndex = 0; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_interface_t *interfacePointer; + + if (hidInstance->inPipe != NULL) /* close interrupt in pipe if it is open */ + { + status = USB_HostClosePipe(hidInstance->hostHandle, hidInstance->inPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hidInstance->inPipe = NULL; + } + if (hidInstance->outPipe != NULL) /* close interrupt out pipe if it is open */ + { + status = USB_HostClosePipe(hidInstance->hostHandle, hidInstance->outPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hidInstance->outPipe = NULL; + } + + /* open interface pipes */ + interfacePointer = (usb_host_interface_t *)hidInstance->interfaceHandle; + for (epIndex = 0; epIndex < interfacePointer->epCount; ++epIndex) + { + epDesc = interfacePointer->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + pipeInit.devInstance = hidInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + hidInstance->inPacketSize = pipeInit.maxPacketSize; + + status = USB_HostOpenPipe(hidInstance->hostHandle, &hidInstance->inPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostHidSetInterface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + pipeInit.devInstance = hidInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + hidInstance->outPacketSize = pipeInit.maxPacketSize; + + status = USB_HostOpenPipe(hidInstance->hostHandle, &hidInstance->outPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostHidSetInterface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else + { + } + } + + return kStatus_USB_Success; +} + +static void USB_HostHidSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)param; + + hidInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = USB_HostHidOpenInterface(hidInstance); /* hid open interface */ + } + + if (hidInstance->controlCallbackFn != NULL) + { + hidInstance->controlCallbackFn(hidInstance->controlCallbackParam, NULL, 0, + status); /* callback to application */ + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +usb_status_t USB_HostHidInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + uint32_t infoValue; + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)USB_OsaMemoryAllocate( + sizeof(usb_host_hid_instance_t)); /* malloc hid class instance */ + + if (hidInstance == NULL) + { + return kStatus_USB_AllocFail; + } + + /* initialize hid instance */ + hidInstance->deviceHandle = deviceHandle; + hidInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + hidInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + hidInstance->controlPipe = (usb_host_pipe_handle)infoValue; + + *classHandle = hidInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostHidSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status; + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + hidInstance->interfaceHandle = interfaceHandle; + status = USB_HostOpenDeviceInterface(hidInstance->deviceHandle, + interfaceHandle); /* notify host driver the interface is open */ + if (status != kStatus_USB_Success) + { + return status; + } + + /* cancel transfers */ + if (hidInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->inPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + if (hidInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->outPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (alternateSetting == 0) /* open interface directly */ + { + if (callbackFn != NULL) + { + status = USB_HostHidOpenInterface(hidInstance); + callbackFn(callbackParam, NULL, 0, status); + } + } + else /* send setup transfer */ + { + /* malloc one transfer */ + if (USB_HostMallocTransfer(hidInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save the application callback function */ + hidInstance->controlCallbackFn = callbackFn; + hidInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = USB_HostHidSetInterfaceCallback; + transfer->callbackParam = hidInstance; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_INTERFACE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)hidInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(hidInstance->hostHandle, hidInstance->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + hidInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + } + } + + return status; +} + +usb_status_t USB_HostHidDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_status_t status; + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (classHandle != NULL) /* class instance has initialized */ + { + if (hidInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->inPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(hidInstance->hostHandle, hidInstance->inPipe); /* close pipe */ + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hidInstance->inPipe = NULL; + } + if (hidInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->outPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(hidInstance->hostHandle, hidInstance->outPipe); /* close pipe */ + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hidInstance->outPipe = NULL; + } + if ((hidInstance->controlPipe != NULL) && + (hidInstance->controlTransfer != NULL)) /* cancel control transfer if there is on-going control transfer */ + { + status = + USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->controlPipe, hidInstance->controlTransfer); + } + USB_HostCloseDeviceInterface(deviceHandle, + hidInstance->interfaceHandle); /* notify host driver the interface is closed */ + USB_OsaMemoryFree(hidInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +uint16_t USB_HostHidGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + if (classHandle == NULL) + { + return 0; + } + + if (pipeType == USB_ENDPOINT_INTERRUPT) + { + if (direction == USB_IN) + { + return hidInstance->inPacketSize; + } + else + { + return hidInstance->outPacketSize; + } + } + + return 0; +} + +usb_status_t USB_HostHidRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (hidInstance->inPipe == NULL) + { + return kStatus_USB_Error; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(hidInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + hidInstance->inCallbackFn = callbackFn; + hidInstance->inCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHidInPipeCallback; + transfer->callbackParam = hidInstance; + + if (USB_HostRecv(hidInstance->hostHandle, hidInstance->inPipe, transfer) != + kStatus_USB_Success) /* call host driver api */ + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHidSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (hidInstance->outPipe == NULL) + { + return kStatus_USB_Error; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(hidInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* save the application callback function */ + hidInstance->outCallbackFn = callbackFn; + hidInstance->outCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHidOutPipeCallback; + transfer->callbackParam = hidInstance; + + if (USB_HostSend(hidInstance->hostHandle, hidInstance->outPipe, transfer) != + kStatus_USB_Success) /* call host driver api */ + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostSend\r\n"); +#endif + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostHidControl(usb_host_class_handle classHandle, + uint8_t requestType, + uint8_t request, + uint8_t wvalueL, + uint8_t wvalueH, + uint16_t wlength, + uint8_t *data, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(hidInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + hidInstance->controlCallbackFn = callbackFn; + hidInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = data; + transfer->transferLength = wlength; + transfer->callbackFn = USB_HostHidControlCallback; + transfer->callbackParam = hidInstance; + transfer->setupPacket.bmRequestType = requestType; + transfer->setupPacket.bRequest = request; + transfer->setupPacket.wValue = (wvalueL | (uint16_t)((uint16_t)wvalueH << 8)); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)hidInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wLength = USB_SHORT_TO_LITTLE_ENDIAN(wlength); + + if (USB_HostSendSetup(hidInstance->hostHandle, hidInstance->controlPipe, transfer) != + kStatus_USB_Success) /* call host driver api */ + { +#ifdef HOST_ECHO + usb_echo("failt for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + hidInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHidGetReportDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t buffer_len, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_STANDARD | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_REQUEST_STANDARD_GET_DESCRIPTOR, 0, USB_DESCRIPTOR_TYPE_HID_REPORT, buffer_len, buffer, callbackFn, + callbackParam); +} + +usb_status_t USB_HostHidGetIdle(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t *idleRate, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_GET_IDLE, reportId, 0, 1, idleRate, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidSetIdle(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t idleRate, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_SET_IDLE, reportId, idleRate, 0, NULL, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidGetProtocol(usb_host_class_handle classHandle, + uint8_t *protocol, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_GET_PROTOCOL, 0, 0, 1, protocol, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidSetProtocol(usb_host_class_handle classHandle, + uint8_t protocol, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_SET_PROTOCOL, protocol, 0, 0, NULL, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidGetReport(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t reportType, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_GET_REPORT, reportId, reportType, bufferLength, buffer, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidSetReport(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t reportType, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_SET_REPORT, reportId, reportType, bufferLength, buffer, callbackFn, callbackParam); +} + +#endif /* USB_HOST_CONFIG_HID */ diff --git a/usb_1.1.0/host/class/usb_host_hid.h b/usb_1.1.0/host/class/usb_host_hid.h new file mode 100644 index 0000000..86e66d6 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hid.h @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_HOST_HID_H_ +#define _USB_HOST_HID_H_ + +/******************************************************************************* + * HID class public structure, enumerations, macros, functions + ******************************************************************************/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @addtogroup usb_host_hid_drv + * @{ + */ + +/*! @brief HID class-specific request (get report) */ +#define USB_HOST_HID_GET_REPORT (0x01U) +/*! @brief HID class-specific request (get idle) */ +#define USB_HOST_HID_GET_IDLE (0x02U) +/*! @brief HID class-specific request (get protocol) */ +#define USB_HOST_HID_GET_PROTOCOL (0x03U) +/*! @brief HID class-specific request (set report) */ +#define USB_HOST_HID_SET_REPORT (0x09U) +/*! @brief HID class-specific request (set idle) */ +#define USB_HOST_HID_SET_IDLE (0x0AU) +/*! @brief HID class-specific request (set protocol) */ +#define USB_HOST_HID_SET_PROTOCOL (0x0BU) + +/*! @brief HID class code */ +#define USB_HOST_HID_CLASS_CODE (3U) +/*! @brief HID sub-class code */ +#define USB_HOST_HID_SUBCLASS_CODE_NONE (0U) +/*! @brief HID sub-class code */ +#define USB_HOST_HID_SUBCLASS_CODE_BOOT (1U) +/*! @brief HID class protocol code */ +#define USB_HOST_HID_PROTOCOL_KEYBOARD (1U) +/*! @brief HID class protocol code */ +#define USB_HOST_HID_PROTOCOL_MOUSE (2U) +/*! @brief HID class protocol code */ +#define USB_HOST_HID_PROTOCOL_NONE (0U) + +/*! @brief HID get/set protocol request data code */ +#define USB_HOST_HID_REQUEST_PROTOCOL_BOOT (0U) +/*! @brief HID get/set protocol request data code */ +#define USB_HOST_HID_REQUEST_PROTOCOL_REPORT (1U) + +/*! @brief HID instance structure and HID usb_host_class_handle pointer to this structure */ +typedef struct _usb_host_hid_instance +{ + usb_host_handle hostHandle; /*!< This instance's related host handle*/ + usb_device_handle deviceHandle; /*!< This instance's related device handle*/ + usb_host_interface_handle interfaceHandle; /*!< This instance's related interface handle*/ + usb_host_pipe_handle controlPipe; /*!< This instance's related device control pipe*/ + usb_host_pipe_handle inPipe; /*!< HID interrupt in pipe*/ + usb_host_pipe_handle outPipe; /*!< HID interrupt out pipe*/ + transfer_callback_t inCallbackFn; /*!< HID interrupt in transfer callback function pointer*/ + void *inCallbackParam; /*!< HID interrupt in transfer callback parameter*/ + transfer_callback_t outCallbackFn; /*!< HID interrupt out transfer callback function pointer*/ + void *outCallbackParam; /*!< HID interrupt out transfer callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< HID control transfer callback function pointer*/ + void *controlCallbackParam; /*!< HID control transfer callback parameter*/ + usb_host_transfer_t *controlTransfer; /*!< Ongoing control transfer*/ +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + uint8_t *stallDataBuffer; /*!< keep the data buffer for stall transfer's data*/ + uint32_t stallDataLength; /*!< keep the data length for stall transfer's data*/ +#endif + + uint16_t inPacketSize; /*!< HID interrupt in maximum packet size*/ + uint16_t outPacketSize; /*!< HID interrupt out maximum packet size*/ +} usb_host_hid_instance_t; + +/*! @brief HID descriptor structure according to the 6.2.1 in HID specification */ +typedef struct _usb_host_hid_descriptor +{ + uint8_t bLength; /*!< Total size of the HID descriptor*/ + uint8_t bDescriptorType; /*!< Constant name specifying type of HID descriptor*/ + uint8_t bcdHID[2]; /*!< Numeric expression identifying the HID Class Specification release*/ + uint8_t bCountryCode; /*!< Numeric expression identifying country code of the localized hardware*/ + uint8_t bNumDescriptors; /*!< Numeric expression specifying the number of class descriptors*/ + uint8_t bHidDescriptorType; /*!< Constant name identifying type of class descriptor*/ + uint8_t wDescriptorLength[2]; /*!< Numeric expression that is the total size of the Report descriptor*/ +} usb_host_hid_descriptor_t; + +/*! @brief HID descriptor structure according to the 6.2.1 in HID specification */ +typedef struct _usb_host_hid_class_descriptor +{ + uint8_t bHidDescriptorType; /*!< Constant name specifying type of optional descriptor*/ + uint8_t wDescriptorLength[2]; /*!< Numeric expression that is the total size of the optional descriptor*/ +} usb_host_hid_class_descriptor_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @name USB host HID class APIs + * @{ + */ + +/*! + * @brief Initializes the HID instance. + * + * This function allocate the resource for the HID instance. + * + * @param[in] deviceHandle The device handle. + * @param[out] classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostHidInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets the interface. + * + * This function binds the interface with the HID instance. + * + * @param[in] classHandle The class handle. + * @param[in] interfaceHandle The interface handle. + * @param[in] alternateSetting The alternate setting value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + * @retval kStatus_USB_Busy Callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall Callback return status, the transfer is stalled by the device. + * @retval kStatus_USB_Error Callback return status, open pipe fail. See the USB_HostOpenPipe. + */ +extern usb_status_t USB_HostHidSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the the HID instance. + * + * This function frees the resources for the HID instance. + * + * @param[in] deviceHandle The device handle. + * @param[in] classHandle The class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +extern usb_status_t USB_HostHidDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Gets the pipe maximum packet size. + * + * @param[in] classHandle The class handle. + * @param[in] pipeType Its value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or + * USB_ENDPOINT_INTERRUPT. + * See the usb_spec.h + * @param[in] direction Pipe direction. + * + * @retval 0 The classHandle is NULL. + * @retval Maximum packet size. + */ +extern uint16_t USB_HostHidGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction); + +/*! + * @brief HID get report descriptor. + * + * This function implements the HID report descriptor request. + * + * @param[in] classHandle The class handle. + * @param[out] buffer The buffer pointer. + * @param[in] buffer_len The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidGetReportDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t buffer_len, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Receives data. + * + * This function implements the HID receiving data. + * + * @param[in] classHandle The class handle. + * @param[out] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostRecv. + */ +extern usb_status_t USB_HostHidRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Sends data. + * + * This function implements the HID sending data. + * + * @param[in] classHandle The class handle. + * @param[in] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSend. + */ +extern usb_status_t USB_HostHidSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID get idle. + * + * This function implements the HID class-specific request (get idle). + * + * @param[in] classHandle The class handle. + * @param[in] reportId Report ID. + * @param[out] idleRate Return idle rate value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidGetIdle(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t *idleRate, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID set idle. + * + * This function implements the HID class-specific request (set idle). + * + * @param[in] classHandle The class handle. + * @param[in] reportId Report ID. + * @param[in] idleRate Idle rate value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidSetIdle(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t idleRate, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID get protocol. + * + * This function implements the HID class-specific request (get protocol). + * + * @param[in] classHandle The class handle. + * @param[out] protocol Return protocol value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidGetProtocol(usb_host_class_handle classHandle, + uint8_t *protocol, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID set protocol. + * + * This function implements the HID class-specific request (set protocol). + * + * @param[in] classHandle The class handle. + * @param[in] protocol Protocol value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidSetProtocol(usb_host_class_handle classHandle, + uint8_t protocol, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID get report. + * + * This function implements the HID class-specific request (get report). + * + * @param[in] classHandle The class handle. + * @param[in] reportId Report ID. + * @param[in] reportType Report type. + * @param[out] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidGetReport(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t reportType, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID set report. + * + * This function implements the HID class-specific request (set report). + * + * @param[in] classHandle The class handle. + * @param[in] reportId Report ID. + * @param[in] reportType Report type. + * @param[in] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidSetReport(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t reportType, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_HID_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_hub.c b/usb_1.1.0/host/class/usb_host_hub.c new file mode 100644 index 0000000..1200770 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hub.c @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) +#include "usb_host.h" +#include "usb_host_hub.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief hub control transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostHubControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief hub interrupt in transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostHubInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief USB_HostHubSendPortReset's transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostHubResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief hub control transfer common code. + * + * @param classHandle the class handle. + * @param requestType request type. + * @param request setup packet request field. + * @param wvalue setup packet wValue field. + * @param windex setup packet wIndex field. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostHubClassRequestCommon(usb_host_class_handle classHandle, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostHubControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + hubInstance->controlTransfer = NULL; + if (hubInstance->controlCallbackFn) + { + hubInstance->controlCallbackFn(hubInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); /* callback to application */ + } + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); +} + +static void USB_HostHubInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + if (hubInstance->inCallbackFn) + { + hubInstance->inCallbackFn(hubInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); /* callback to application */ + } + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); +} + +static void USB_HostHubResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + /* note: there is not callback to application, the re-enumeration will start automatically after reset. */ + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostHubClassRequestCommon(usb_host_class_handle classHandle, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (hubInstance->controlTransfer != NULL) + { + return kStatus_USB_Busy; + } + + /* get transfer */ + if (USB_HostMallocTransfer(hubInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save hub application callback */ + hubInstance->controlCallbackFn = callbackFn; + hubInstance->controlCallbackParam = callbackParam; + + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHubControlCallback; + transfer->callbackParam = hubInstance; + transfer->setupPacket.bmRequestType = requestType; + transfer->setupPacket.bRequest = request; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(wvalue); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(windex); + transfer->setupPacket.wLength = USB_SHORT_TO_LITTLE_ENDIAN(bufferLength); + + /* send transfer */ + if (USB_HostSendSetup(hubInstance->hostHandle, hubInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("Error in hid get report descriptor\r\n"); +#endif + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + hubInstance->controlTransfer = transfer; /* record the on-going setup transfer */ + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + /* malloc the hub instance */ + usb_host_hub_instance_t *hubInstance = + (usb_host_hub_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_hub_instance_t)); + uint32_t infoValue; + + if (hubInstance == NULL) + { + return kStatus_USB_AllocFail; + } + + /* initialize hub instance structure */ + hubInstance->deviceHandle = deviceHandle; + hubInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + hubInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + hubInstance->controlPipe = (usb_host_pipe_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + hubInstance->hubLevel = infoValue; + + *classHandle = hubInstance; /* return the hub class handle */ + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status; + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_interface_t *interface = (usb_host_interface_t *)interfaceHandle; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_pipe_init_t pipeInit; + uint8_t epIndex; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + hubInstance->interfaceHandle = interfaceHandle; /* save the interface handle */ + + /* notify the host driver that the interface is used by class */ + status = USB_HostOpenDeviceInterface(hubInstance->deviceHandle, interfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + + /* close opened hub interrupt pipe */ + if (hubInstance->interruptPipe != NULL) + { + status = USB_HostCancelTransfer(hubInstance->hostHandle, hubInstance->interruptPipe, NULL); + status = USB_HostClosePipe(hubInstance->hostHandle, hubInstance->interruptPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hubInstance->interruptPipe = NULL; + } + + /* open hub interrupt pipe */ + for (epIndex = 0; epIndex < interface->epCount; ++epIndex) + { + epDesc = interface->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + /* get pipe information from endpoint descriptor */ + pipeInit.devInstance = hubInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + /* open hub interrupt in pipe */ + status = USB_HostOpenPipe(hubInstance->hostHandle, &hubInstance->interruptPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_hid_set_interface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + break; + } + } + + /* hub don't support alternatesetting that is not 0 */ + if (alternateSetting == 0) + { + if (callbackFn != NULL) + { + callbackFn(callbackParam, NULL, 0, kStatus_USB_Success); + } + } + else + { +#ifdef HOST_ECHO + usb_echo("host don't supprt alternate setting\r\n"); +#endif + return kStatus_USB_Error; + } + + return status; +} + +usb_status_t USB_HostHubDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + uint8_t status; + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (classHandle != NULL) + { + /* close opened hub interrupt pipe */ + if (hubInstance->interruptPipe != NULL) + { + status = USB_HostCancelTransfer(hubInstance->hostHandle, hubInstance->interruptPipe, NULL); + status = USB_HostClosePipe(hubInstance->hostHandle, hubInstance->interruptPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("hub close interrupt pipe error\r\n"); +#endif + } + hubInstance->interruptPipe = NULL; + } + + /* cancel control transfer if exist */ + if ((hubInstance->controlPipe != NULL) && (hubInstance->controlTransfer != NULL)) + { + status = + USB_HostCancelTransfer(hubInstance->hostHandle, hubInstance->controlPipe, hubInstance->controlTransfer); + } + + /* notify host driver that the interface will not be used */ + USB_HostCloseDeviceInterface(deviceHandle, hubInstance->interfaceHandle); + USB_OsaMemoryFree(hubInstance); + } + else + { + /* notify host driver that the interface will not be used */ + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubInterruptRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* get transfer */ + if (USB_HostMallocTransfer(hubInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save hub application callback */ + hubInstance->inCallbackFn = callbackFn; + hubInstance->inCallbackParam = callbackParam; + + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHubInPipeCallback; + transfer->callbackParam = hubInstance; + + /* call host driver API to receive data */ + if (USB_HostRecv(hubInstance->hostHandle, hubInstance->interruptPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubSendPortReset(usb_host_class_handle classHandle, uint8_t portNumber) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* get transfer */ + if (USB_HostMallocTransfer(hubInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + + /* initialize transfer */ + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + transfer->callbackFn = USB_HostHubResetCallback; + transfer->callbackParam = hubInstance; + transfer->setupPacket.bmRequestType = + USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_FEATURE; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(PORT_RESET); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(portNumber); + transfer->setupPacket.wLength = 0; + + /* send the transfer */ + if (USB_HostSendSetup(hubInstance->hostHandle, hubInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("Error in hid get report descriptor\r\n"); +#endif + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} + +/*! + * @brief hub get descriptor. + * + * This function implements get hub descriptor specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubGetDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_DEVICE, + USB_REQUEST_STANDARD_GET_DESCRIPTOR, 0x00, 0, buffer, bufferLength, callbackFn, callbackParam); +} + +/*! + * @brief hub clear feature. + * + * This function implements clear hub feature specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubClearFeature(usb_host_class_handle classHandle, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon(classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS, + USB_REQUEST_STANDARD_CLEAR_FEATURE, feature, 0, NULL, 0, callbackFn, + callbackParam); +} + +/*! + * @brief hub get status. + * + * This function implements get hub status specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubGetStatus(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon(classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS, + USB_REQUEST_STANDARD_GET_STATUS, 0, 0, buffer, bufferLength, callbackFn, + callbackParam); +} + +/*! + * @brief hub set feature. + * + * This function implements set hub feature specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubSetPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_SET_FEATURE, feature, portNumber, NULL, 0, callbackFn, callbackParam); +} + +/*! + * @brief hub clear port feature. + * + * This function implements clear hub port feature specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubClearPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_CLEAR_FEATURE, feature, portNumber, NULL, 0, callbackFn, callbackParam); +} + +/*! + * @brief hub port get status. + * + * This function implements get hub port status specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubGetPortStatus(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_GET_STATUS, 0, portNumber, buffer, bufferLength, callbackFn, callbackParam); +} + +#endif /* USB_HOST_CONFIG_HUB */ diff --git a/usb_1.1.0/host/class/usb_host_hub.h b/usb_1.1.0/host/class/usb_host_hub.h new file mode 100644 index 0000000..4ea3700 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hub.h @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_HOST_HUB_H_ +#define _USB_HSOT_HUB_H_ + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief USB host HUB maximum port count */ +#define USB_HOST_HUB_MAX_PORT (7U) + +/*! @brief HUB class code */ +#define USB_HOST_HUB_CLASS_CODE (9U) +/*! @brief HUB sub-class code */ +#define USB_HOST_HUB_SUBCLASS_CODE_NONE (0U) + +/* HUB and PORT status according to Table 11-17 in chapter 11.*/ +/*! @brief Local Power Status Change: This field indicates that a change has occurred in the HUB's Local Power Source */ +#define C_HUB_LOCAL_POWER (0U) +/*! @brief Over-Current Change: This field indicates if a change has occurred in the Over-Current field*/ +#define C_HUB_OVER_CURRENT (1U) +/*! @brief Current Connect Status: This field reflects whether or not a device is currently connected to this port*/ +#define PORT_CONNECTION (0U) +/*! @brief Port Enabled/Disabled: Ports can be enabled by the USB System Software only. Ports +can be disabled by either a fault condition (disconnect event or other fault condition) or by the USB System +Software*/ +#define PORT_ENABLE (1U) +/*! @brief Suspend: This field indicates whether or not the device on this port is suspended */ +#define PORT_SUSPEND (2U) +/*! @brief this field indicate that the current drain on the port exceeds the specified maximum. */ +#define PORT_OVER_CURRENT (3U) +/*! @brief This field is set when the host wishes to reset the attached device */ +#define PORT_RESET (4U) +/*! @brief This field reflects a port's logical, power control state */ +#define PORT_POWER (8U) +/*! @brief Low- Speed Device Attached: This is relevant only if a device is attached */ +#define PORT_LOW_SPEED (9U) +/*! @brief High-speed Device Attached: This is relevant only if a device is attached */ +#define PORT_HIGH_SPEED (10U) +/*! @brief Connect Status Change: Indicates a change has occurred in the port's Current Connect Status */ +#define C_PORT_CONNECTION (16U) +/*! @brief Port Enable/Disable Change: This field is set to one when a port is disabled because of a Port_Error + * condition */ +#define C_PORT_ENABLE (17U) +/*! @brief Suspend Change: This field indicates a change in the host-visible suspend state of the attached device */ +#define C_PORT_SUSPEND (18U) +/*! @brief Over-Current Indicator Change: This field applies only to HUBs that report over-current conditions on a + * per-port basis */ +#define C_PORT_OVER_CURRENT (19U) +/*! @brief Reset Change: This field is set when reset processing on this port is complete */ +#define C_PORT_RESET (20U) + +/*! @brief Get HUB think time value */ +#define USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_MASK (0x60U) +/*! @brief Get HUB think time value */ +#define USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_SHIFT (5U) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! @brief HUB descriptor structure */ +typedef struct _usb_host_hub_descriptor +{ + uint8_t blength; /*!< Number of bytes in this descriptor*/ + uint8_t bdescriptortype; /*!< Descriptor Type*/ + uint8_t bnrports; /*!< Number of downstream facing ports that this HUB supports*/ + uint8_t whubcharacteristics[2]; /*!< HUB characteristics please reference to Table 11-13 in usb2.0 specification*/ + uint8_t bpwron2pwrgood; /*!< Time (in 2 ms intervals) from the time the power-on sequence begins on a port until + power is good on that port.*/ + uint8_t bhubcontrcurrent; /*!< Maximum current requirements of the HUB Controller electronics in mA*/ + uint8_t deviceremovable; /*!< Indicates if a port has a removable device attached*/ +} usb_host_hub_descriptor_t; + +/*! @brief HUB port instance structure */ +typedef struct _usb_host_hub_port_instance +{ + usb_device_handle deviceHandle; /*!< Device handle*/ + uint8_t portStatus; /*!< Port running status*/ + uint8_t resetCount; /*!< Port reset time*/ + uint8_t speed; /*!< Port's device speed*/ +} usb_host_hub_port_instance_t; + +/*! @brief HUB instance structure */ +typedef struct _usb_host_hub_instance +{ + struct _usb_host_hub_instance *next; /*!< Next HUB instance*/ + usb_host_handle hostHandle; /*!< Host handle*/ + usb_device_handle deviceHandle; /*!< Device handle*/ + usb_host_interface_handle interfaceHandle; /*!< Interface handle*/ + usb_host_pipe_handle controlPipe; /*!< Control pipe handle*/ + usb_host_pipe_handle interruptPipe; /*!< HUB interrupt in pipe handle*/ + usb_host_hub_port_instance_t *portList; /*!< HUB's port instance list*/ + usb_host_transfer_t *controlTransfer; /*!< Control transfer in progress*/ + transfer_callback_t inCallbackFn; /*!< Interrupt in callback*/ + void *inCallbackParam; /*!< Interrupt in callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< Control callback*/ + void *controlCallbackParam; /*!< Control callback parameter*/ + /* HUB property */ + uint16_t totalThinktime; /*!< HUB total think time*/ + uint8_t hubLevel; /*!< HUB level, the root HUB's level is 1*/ + + /* HUB application parameter */ + uint8_t hubDescriptor[7 + (USB_HOST_HUB_MAX_PORT >> 3) + 1]; /*!< HUB descriptor buffer*/ + uint8_t hubBitmapBuffer[(USB_HOST_HUB_MAX_PORT >> 3) + 1]; /*!< HUB receiving bitmap data buffer*/ + uint8_t hubStatusBuffer[4]; /*!< HUB status buffer*/ + uint8_t portStatusBuffer[4]; /*!< Port status buffer*/ + uint8_t hubStatus; /*!< HUB instance running status*/ + uint8_t portCount; /*!< HUB port count*/ + uint8_t portIndex; /*!< Record the index when processing ports in turn*/ + uint8_t portProcess; /*!< The port that is processing*/ + uint8_t primeStatus; /*!< Data prime transfer status*/ + uint8_t invalid; /*!< 0/1, when invalid, cannot send transfer to the class*/ +} usb_host_hub_instance_t; + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Initializes the HUB instance. + * + * This function allocates the resource for HUB instance. + * + * @param deviceHandle The device handle. + * @param classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostHubInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets interface. + * + * This function binds the interfaces with the HUB instance. + * + * @param classHandle The class handle. + * @param interfaceHandle The interface handle. + * @param alternateSetting The alternate setting value. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Open pipe fail. See the USB_HostOpenPipe. + * Or send transfer fail. See the USB_HostSendSetup, + */ +extern usb_status_t USB_HostHubSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the HUB instance. + * + * This function releases the resource for HUB instance. + * + * @param deviceHandle The device handle. + * @param classHandle The class handle. + * + * @retval kStatus_USB_Success The device is deinitialized successfully. + */ +extern usb_status_t USB_HostHubDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Receives data. + * + * This function implements the HUB receiving data. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostRecv. + */ +extern usb_status_t USB_HostHubInterruptRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Port reset setup. + * + * This function sends the HUB port reset transfer. + * + * @param classHandle The class handle. + * @param portNumber Port number. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubSendPortReset(usb_host_class_handle classHandle, uint8_t portNumber); + +/*! + * @brief HUB get descriptor. + * + * This function implements get HUB descriptor-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubGetDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB clear feature. + * + * This function implements clear HUB feature specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubClearFeature(usb_host_class_handle classHandle, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB get status. + * + * This function implements the get HUB status-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubGetStatus(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB set feature. + * + * This function implements the set HUB feature-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubSetPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB clear port feature. + * + * This function implements the clear HUB port feature-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubClearPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB port get status. + * + * This function implements the get HUB port status-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubGetPortStatus(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +#ifdef __cplusplus +} +#endif + +#endif /* USB_HOST_CONFIG_HUB */ + +#endif /* _USB_HSOT_HUB_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_hub_app.c b/usb_1.1.0/host/class/usb_host_hub_app.c new file mode 100644 index 0000000..1755b69 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hub_app.c @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +#include "usb_host.h" +#include "usb_host_hub.h" +#include "usb_host_hub_app.h" +#include "usb_host_devices.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief prime interrupt in data. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubGetInterruptStatus(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub process state machine. hub is enable after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcess(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port attach process state machine. one device is attached to the port after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPortAttach(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port detach process state machine. one device is detached from the port after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPortDetach(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port process. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPort(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub interrupt in data process. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessData(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostHubControlCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status); + +/*! + * @brief hub interrupt pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostHubInterruptInCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +static usb_device_handle s_HubDeviceHandle; +static usb_host_interface_handle s_HubInterfaceHandle; +static usb_host_hub_global_t s_HubGlobal; + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostHubGetInterruptStatus(usb_host_hub_instance_t *hubInstance) +{ + if (hubInstance == NULL) + { + return; + } + + /* there is no prime for control or interrupt */ + if (hubInstance->primeStatus != kPrimeNone) + { + return; + } + + /* receive interrupt data */ + if (USB_HostHubInterruptRecv(hubInstance, hubInstance->hubBitmapBuffer, (hubInstance->portCount >> 3) + 1, + USB_HostHubInterruptInCallback, hubInstance) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error in hub interrupt recv\r\n"); +#endif + } + else + { + hubInstance->primeStatus = kPrimeInterrupt; + } +} + +static void USB_HostHubProcess(usb_host_hub_instance_t *hubInstance) +{ + uint8_t needPrimeInterrupt = 0; /* need to prime interrupt in transfer (0 - don't need; 1 - need) */ + uint8_t processSuccess = 0; /* the code excute successfully (0 - fail; 1 - success) */ + uint32_t tmp = 0; + usb_host_hub_descriptor_t *hubDescriptor; + + switch (hubInstance->hubStatus) + { + case kHubRunIdle: + case kHubRunInvalid: + break; + + case kHubRunWaitSetInterface: + hubInstance->hubStatus = kHubRunGetDescriptor7; /* update as next state */ + /* get hub descriptor */ + if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, 7, USB_HostHubControlCallback, + hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* control transfer is on-going */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("hub get descriptor 7\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("hub get descriptor 7 error\r\n"); +#endif + break; + } + break; + + case kHubRunGetDescriptor7: + hubDescriptor = (usb_host_hub_descriptor_t *)&hubInstance->hubDescriptor[0]; + + /* get the hub think time */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetHubThinkTime, &tmp); + hubInstance->totalThinktime = tmp + (((uint32_t)hubDescriptor->whubcharacteristics[0] & + USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_MASK) >> + USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_SHIFT); + + /* get hub port number */ + hubInstance->portCount = hubDescriptor->bnrports; + if (hubInstance->portCount > USB_HOST_HUB_MAX_PORT) + { +#ifdef HOST_ECHO + usb_echo("port number is bigger than USB_HOST_HUB_MAX_PORT\r\n"); +#endif + return; + } + + hubInstance->hubStatus = kHubRunGetDescriptor; /* update as next state */ + /* get hub descriptor */ + if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, 7 + (hubInstance->portCount >> 3) + 1, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* control transfer is on-going */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("hub get descriptor\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("hub get descriptor error\r\n"); +#endif + break; + } + break; + + case kHubRunGetDescriptor: + /* malloc port instance for the hub's ports */ + hubInstance->portList = (usb_host_hub_port_instance_t *)USB_OsaMemoryAllocate( + hubInstance->portCount * sizeof(usb_host_hub_port_instance_t)); + if (hubInstance->portList == NULL) + { +#ifdef HOST_ECHO + usb_echo("port list allocate fail\r\n"); +#endif + hubInstance->hubStatus = kHubRunInvalid; + break; + } + /* TODO: port instance status -> can be removed. app_status */ + + hubInstance->hubStatus = kHubRunSetPortPower; /* update as next state */ + hubInstance->portIndex = 0; + + /* there is no significance, just for fixing misra error */ + if (hubInstance->hubStatus != kHubRunSetPortPower) + { + break; + } + + case kHubRunSetPortPower: + /* set PORT_POWER for all ports */ + if (hubInstance->portIndex < hubInstance->portCount) + { + hubInstance->portIndex++; + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portIndex, PORT_POWER, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* update as next state */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("set port feature PORT_POWER\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("set port feature PORT_POWER fail\r\n"); +#endif + needPrimeInterrupt = 1; + break; + } + break; + } + hubInstance->portProcess = 0; + /* reset port information as default */ + for (tmp = 0; tmp < hubInstance->portCount; ++tmp) + { + hubInstance->portList[tmp].deviceHandle = NULL; + hubInstance->portList[tmp].resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + hubInstance->portList[tmp].portStatus = kPortRunWaitPortChange; + } + hubInstance->hubStatus = kHubRunIdle; + needPrimeInterrupt = 1; + break; + + case kHubRunGetStatusDone: /* process hub status change */ + tmp = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS((&hubInstance->hubStatusBuffer[2])); + hubInstance->hubStatus = kHubRunIdle; + if ((1 << C_HUB_LOCAL_POWER) & tmp) /* C_HUB_LOCAL_POWER */ + { + if (USB_HostHubClearFeature(hubInstance, C_HUB_LOCAL_POWER, USB_HostHubControlCallback, hubInstance) == + kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + processSuccess = 1; + } + else + { + needPrimeInterrupt = 1; + } + } + else if ((1 << C_HUB_OVER_CURRENT) & tmp) /* C_HUB_OVER_CURRENT */ + { + if (USB_HostHubClearFeature(hubInstance, C_HUB_OVER_CURRENT, USB_HostHubControlCallback, hubInstance) == + kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + processSuccess = 1; + } + else + { + needPrimeInterrupt = 1; + } + } + else + { + needPrimeInterrupt = 1; + } + break; + + default: + break; + } + + if (needPrimeInterrupt == 1) /* prime interrupt in transfer */ + { + hubInstance->hubStatus = kHubRunIdle; + USB_HostHubGetInterruptStatus(hubInstance); + } + else + { + if (processSuccess == 0) + { + hubInstance->hubStatus = kHubRunInvalid; + } + } +} + +static void USB_HostHubProcessPort(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + + /* for device attach */ + if (portInstance->deviceHandle == NULL) + { + USB_HostHubProcessPortAttach(hubInstance); + } + else /* for device detach */ + { + USB_HostHubProcessPortDetach(hubInstance); + } +} + +static void USB_HostHubProcessPortAttach(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + uint8_t processSuccess = 0; + uint32_t specStatus; + uint8_t feature; + uint32_t infoValue; + + switch (portInstance->portStatus) + { + case kPortRunIdle: + case kPortRunInvalid: + break; + case kPortRunWaitPortChange: /* (1) port is changed, and get port status */ + portInstance->portStatus = kPortRunCheckCPortConnection; /* update as next state */ + /* send class-specific request to get port status */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckCPortConnection: /* (2) check port status, and clear the status bits */ + feature = 0; + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS((hubInstance->portStatusBuffer)); + if ((1 << C_PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunGetPortConnection; /* update as next state */ + /* clear C_PORT_CONNECTION */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_CONNECTION, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else if ((1 << PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunWaitPortResetDone; /* update as next state */ + /* set PORT_RESET */ + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + if (portInstance->resetCount > 0) + { + portInstance->resetCount--; + } + } + break; + } + else if ((1 << C_PORT_RESET) & specStatus) + { + feature = C_PORT_RESET; /* clear C_PORT_RESET */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_RESET when detached\r\n"); +#endif + } + else if ((1 << C_PORT_ENABLE) & specStatus) + { + feature = C_PORT_ENABLE; /* clear C_PORT_ENABLE */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_ENABLE when detached\r\n"); +#endif + } + else if ((1 << C_PORT_OVER_CURRENT) & specStatus) + { + feature = C_PORT_OVER_CURRENT; /* clear C_PORT_OVER_CURRENT */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_OVER_CURRENT when detached\r\n"); +#endif + } + else + { + } + + if (feature != 0) + { + portInstance->portStatus = kPortRunWaitPortChange; /* update as next state */ + /* clear feature */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, feature, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + } + break; + + case kPortRunGetPortConnection: /* (3) get port status */ + portInstance->portStatus = kPortRunCheckPortConnection; /* update as next state */ + /* get port status bits */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; /* control transfer is on-going */ + processSuccess = 1; + } + break; + + case kPortRunCheckPortConnection: /* (4) check PORT_CONNECTION bit */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunWaitPortResetDone; /* update as next state */ + /* set PORT_RESET */ + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + if (portInstance->resetCount > 0) + { + portInstance->resetCount--; + } + } + } + break; + + case kPortRunWaitPortResetDone: /* (5) wait port change */ + portInstance->portStatus = kPortRunWaitCPortReset; /* update as next state */ + processSuccess = 1; + /* must wait the enumeration done, then operate the next port */ + USB_HostHubGetInterruptStatus(hubInstance); + break; + + case kPortRunWaitCPortReset: /* (6) get port satus for checking C_PORT_RESET */ + portInstance->portStatus = KPortRunCheckCPortReset; /* update as next state */ + /* get port status bits */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case KPortRunCheckCPortReset: /* (7) check C_PORT_RESET and clear C_PORT_RESET */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << C_PORT_RESET) & specStatus) + { + if (portInstance->resetCount == 0) + { + portInstance->portStatus = kPortRunPortAttached; /* update as next state */ + /* get port's device speed */ + if (specStatus & (1 << PORT_HIGH_SPEED)) + { + portInstance->speed = USB_SPEED_HIGH; + } + else if (specStatus & (1 << PORT_LOW_SPEED)) + { + portInstance->speed = USB_SPEED_LOW; + } + else + { + portInstance->speed = USB_SPEED_FULL; + } + } + else + { + portInstance->portStatus = kPortRunResetAgain; /* update as next state */ + } + + /* clear C_PORT_RESET */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + } + break; + + case kPortRunResetAgain: /* (8) reset again */ + portInstance->portStatus = kPortRunCheckPortConnection; /* check connection then reset again */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunPortAttached: /* (9) the port have one device attached */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + USB_HostAttachDevice(hubInstance->hostHandle, portInstance->speed, infoValue, hubInstance->portProcess, + hubInstance->hubLevel + 1, &portInstance->deviceHandle); + processSuccess = 1; + hubInstance->portProcess = 0; + s_HubGlobal.hubProcess = NULL; + portInstance->resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + USB_HostHubGetInterruptStatus(hubInstance); + break; + + default: + break; + } + + if (processSuccess == 0) + { + portInstance->portStatus = kPortRunWaitPortChange; + hubInstance->portProcess = 0; + s_HubGlobal.hubProcess = NULL; + portInstance->resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +static void USB_HostHubProcessPortDetach(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + uint8_t processSuccess = 0; + uint32_t specStatus; + + switch (portInstance->portStatus) + { + case kPortRunIdle: + case kPortRunInvalid: + break; + + case kPortRunPortAttached: /* (1) port is changed, then get port status */ + portInstance->portStatus = kPortRunCheckPortDetach; + /* get port status */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckPortDetach: /* (2) check port status bits */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + portInstance->portStatus = kPortRunGetConnectionBit; + if ((1 << C_PORT_CONNECTION) & specStatus) /* C_PORT_CONNECTION */ + { + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_CONNECTION, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else if ((1 << C_PORT_ENABLE) & specStatus) /* C_PORT_ENABLE */ + { + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_ENABLE, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else + { + /* don't break to check CONNECTION bit */ + } + + case kPortRunGetConnectionBit: /* (3) get port status */ + portInstance->portStatus = kPortRunCheckConnectionBit; + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckConnectionBit: /* (4) check port connection bit */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << PORT_CONNECTION) & specStatus) /* PORT_CONNECTION */ + { + portInstance->portStatus = kPortRunPortAttached; +#ifdef HOST_ECHO + usb_echo("PORT_CONNECTION in attach for detach\r\n"); +#endif + } + else + { + processSuccess = 1; + /* port's device is detached */ + portInstance->portStatus = kPortRunWaitPortChange; + USB_HostDetachDeviceInternal(hubInstance->hostHandle, portInstance->deviceHandle); + portInstance->deviceHandle = NULL; + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } + break; + default: + break; + } + + if (processSuccess == 0) + { + portInstance->portStatus = kPortRunPortAttached; + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +static void USB_HostHubProcessData(usb_host_hub_instance_t *hubInstance) +{ + uint8_t needPrimeInterrupt = 1; + uint8_t portIndex; + + /* process the port which status change */ + for (portIndex = 0; portIndex <= hubInstance->portCount; ++portIndex) + { + if ((0x01u << (portIndex & 0x07u)) & (hubInstance->hubBitmapBuffer[portIndex >> 3])) + { + if (portIndex == 0) /* hub status change */ + { + if ((s_HubGlobal.hubProcess == NULL) || + ((s_HubGlobal.hubProcess == hubInstance) && (hubInstance->portProcess == 0))) + { + hubInstance->hubStatus = kHubRunGetStatusDone; + if (USB_HostHubGetStatus(hubInstance, hubInstance->hubStatusBuffer, 4, USB_HostHubControlCallback, + hubInstance) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error in usb_class_hub_get_status\r\n"); +#endif + hubInstance->hubStatus = kHubRunIdle; + } + else + { + hubInstance->primeStatus = kPrimeHubControl; + needPrimeInterrupt = 0; + } + } + } + else /* port's status change */ + { + /* process the on-going port or process one new port */ + if ((s_HubGlobal.hubProcess == NULL) || + ((s_HubGlobal.hubProcess == hubInstance) && (hubInstance->portProcess == 0)) || + ((s_HubGlobal.hubProcess == hubInstance) && (hubInstance->portProcess == portIndex))) + { + if (hubInstance->controlTransfer == NULL) + { + s_HubGlobal.hubProcess = hubInstance; + hubInstance->portProcess = portIndex; + needPrimeInterrupt = 0; + USB_HostHubProcessPort(hubInstance); + } + break; /* process the port change in turn */ + } + } + } + } + + if (needPrimeInterrupt == 1) + { + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +void USB_HostHubControlCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + if (hubInstance->invalid == 1) + { + return; + } + if (status != kStatus_USB_Success) + { + /* if transfer fail, prime a new interrupt in transfer */ + hubInstance->primeStatus = kPrimeNone; + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + return; + } + + if (hubInstance->primeStatus == kPrimeHubControl) /* hub related control transfer */ + { + hubInstance->primeStatus = kPrimeNone; + USB_HostHubProcess(hubInstance); + } + else if (hubInstance->primeStatus == kPrimePortControl) /* hub's port related control transfer */ + { + hubInstance->primeStatus = kPrimeNone; + USB_HostHubProcessPort(hubInstance); + } + else + { + } +} + +void USB_HostHubInterruptInCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + if (hubInstance->invalid == 1) + { + return; + } + /* interrupt data received */ + hubInstance->primeStatus = kPrimeNone; + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("hub interrupt in data callback error\r\n"); +#endif + /* prime nexe interrupt transfer */ + if (hubInstance->controlTransfer == NULL) + { + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } + } + else + { + USB_HostHubProcessData(hubInstance); /* process the interrupt data */ + } +} + +/*! + * @brief host hub callback function. + * + * This function should be called in the host callback function. + * + * @param deviceHandle device handle. + * @param configurationHandle attached device's configuration descriptor information. + * @param event_code callback event code, please reference to enumeration host_event_t. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_NotSupported The configuration don't contain hub interface. + */ +usb_status_t USB_HostHubDeviceEvent(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode) +{ + usb_host_configuration_t *configuration; + usb_host_interface_t *interface; + uint8_t interfaceIndex; + uint8_t id; + usb_status_t status = kStatus_USB_Success; + usb_host_class_handle hubClassHandle; + usb_host_hub_instance_t *hubInstance; + usb_host_hub_instance_t *prevInstance; + uint32_t infoValue; + usb_osa_status_t osaStatus; + + switch (eventCode) + { + case kUSB_HostEventAttach: + /* judge whether is configurationHandle supported */ + configuration = (usb_host_configuration_t *)configurationHandle; + for (interfaceIndex = 0; interfaceIndex < configuration->interfaceCount; ++interfaceIndex) + { + interface = &configuration->interfaceList[interfaceIndex]; + id = interface->interfaceDesc->bInterfaceClass; + if (id != USB_HOST_HUB_CLASS_CODE) + { + continue; + } + id = interface->interfaceDesc->bInterfaceSubClass; + if (id != USB_HOST_HUB_SUBCLASS_CODE_NONE) + { + continue; + } + else + { + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + if (infoValue > 5) + { +#ifdef HOST_ECHO + usb_echo("Host can support max 5 level hubs\r\n"); +#endif + continue; + } + /* the interface is hub */ + s_HubDeviceHandle = deviceHandle; + s_HubInterfaceHandle = interface; + return kStatus_USB_Success; + } + } + status = kStatus_USB_NotSupported; + break; + + case kUSB_HostEventEnumerationDone: + /* the device enumeration is done */ + if ((s_HubDeviceHandle != NULL) && (s_HubInterfaceHandle != NULL)) + { + /* print hub information */ + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + usb_echo("hub attached:level=%d ", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + usb_echo("address=%d\r\n", infoValue); + + /* initialize hub mutex */ + if (s_HubGlobal.hubMutex == (usb_osa_mutex_handle)NULL) + { + osaStatus = USB_OsaMutexCreate(&s_HubGlobal.hubMutex); + if (osaStatus != kStatus_USB_OSA_Success) + { + s_HubGlobal.hubMutex = NULL; +#ifdef HOST_ECHO + usb_echo("hub mutex error\r\n"); +#endif + } + } + + /* initialize hub class instance */ + status = USB_HostHubInit(s_HubDeviceHandle, &hubClassHandle); + hubInstance = (usb_host_hub_instance_t *)hubClassHandle; + + /* link hub instance to list */ + USB_HostHubLock(); + hubInstance->next = s_HubGlobal.hubList; + s_HubGlobal.hubList = hubInstance; + USB_HostHubUnlock(); + + /* set hub instance's interface */ + if (status == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + hubInstance->hubStatus = kHubRunWaitSetInterface; + if (USB_HostHubSetInterface(hubClassHandle, s_HubInterfaceHandle, 0, USB_HostHubControlCallback, + hubInstance) != kStatus_USB_Success) + { + hubInstance->hubStatus = kHubRunInvalid; + } + } + } + break; + + case kUSB_HostEventDetach: + /* the device is detached */ + hubInstance = NULL; + + /* get device's hub instance handle */ + USB_HostHubLock(); + prevInstance = s_HubGlobal.hubList; + if (prevInstance->deviceHandle == deviceHandle) + { + hubInstance = prevInstance; + s_HubGlobal.hubList = prevInstance->next; + } + else + { + hubInstance = prevInstance->next; + while (hubInstance != NULL) + { + if (hubInstance->deviceHandle == deviceHandle) + { + prevInstance->next = hubInstance->next; + break; + } + prevInstance = hubInstance; + hubInstance = hubInstance->next; + } + } + USB_HostHubUnlock(); + + if (hubInstance != NULL) + { + if (hubInstance == s_HubGlobal.hubProcess) + { + s_HubGlobal.hubProcess = NULL; + } + /* print hub information */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + usb_echo("hub detached:level=%d ", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + usb_echo("address=%d\r\n", infoValue); + hubInstance->invalid = 1; + /* detach hub ports' devices */ + for (uint8_t portIndex = 0; portIndex < hubInstance->portCount; ++portIndex) + { + if ((hubInstance->portList != NULL) && (hubInstance->portList[portIndex].deviceHandle != NULL)) + { + USB_HostDetachDeviceInternal(hubInstance->hostHandle, + hubInstance->portList[portIndex].deviceHandle); + hubInstance->portList[portIndex].deviceHandle = NULL; + } + } + if (hubInstance->portList != NULL) + { + USB_OsaMemoryFree(hubInstance->portList); + } + USB_HostHubDeinit(deviceHandle, hubInstance); /* de-initialize hub instance */ + } + + /* destory hub mutex if there is no hub instance */ + if (s_HubGlobal.hubList == NULL) + { + if (s_HubGlobal.hubMutex != NULL) + { + USB_OsaMutexDestroy(s_HubGlobal.hubMutex); + s_HubGlobal.hubMutex = NULL; + } + } + break; + + default: + break; + } + + return status; +} + +/*! + * @brief remove attached device. called by USB_HostRemoveDevice. + * + * @param hubNumber the device attached hub. + * @param portNumber the device attached port. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostHubRemovePort(uint8_t hubNumber, uint8_t portNumber) +{ + usb_host_hub_instance_t *hubInstance; + uint32_t infoValue; + + /* get hub number's hub instance handle */ + hubInstance = (usb_host_hub_instance_t *)s_HubGlobal.hubList; + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + if (infoValue == hubNumber) + { + break; + } + hubInstance = hubInstance->next; + } + + /* set port's status as default, and reset port */ + if (hubInstance != NULL) + { + hubInstance->portList[portNumber - 1].deviceHandle = NULL; + hubInstance->portList[portNumber - 1].portStatus = kPortRunInvalid; + if (hubInstance->portProcess == portNumber) + { + hubInstance->portProcess = 0; + } + USB_HostHubSendPortReset(hubInstance, portNumber); + } + return kStatus_USB_Error; +} + +/*! + * @brief get device's high-speed hub's address. + * + * @param parent_hub_no device's parent hub's address. + * + * @return hub number. + */ +uint32_t USB_HostHubGetHsHubNumber(uint8_t parentHubNo) +{ + usb_host_hub_instance_t *hubInstance = s_HubGlobal.hubList; + uint32_t deviceInfo; + uint32_t hubNumber; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceInfo); + if (parentHubNo == deviceInfo) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceSpeed, &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */ + { + hubNumber = parentHubNo; + } + else /* parent hub is not HS */ + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceHSHubNumber, + &hubNumber); + } + return hubNumber; + } + return 0; +} + +/*! + * @brief get device's high-speed hub's port number. + * + * @param parent_hub_no device's parent hub's address. + * @param parent_port_no device's parent port no. + * + * @return port number. + */ +uint32_t USB_HostHubGetHsHubPort(uint8_t parentHubNo, uint8_t parentPortNo) +{ + usb_host_hub_instance_t *hubInstance = s_HubGlobal.hubList; + uint32_t deviceInfo; + uint32_t hubPort; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceInfo); + if (parentHubNo == deviceInfo) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceSpeed, &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */ + { + hubPort = parentPortNo; + } + else /* parent hub is not HS */ + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceHSHubNumber, &hubPort); + } + return hubPort; + } + return 0; +} + +/*! + * @brief get device's hub total think time. + * + * @param parent_hub_no device's parent hub's address. + * + * @return think time value. + */ +uint32_t USB_HostHubGetTotalThinkTime(uint8_t parentHubNo) +{ + usb_host_hub_instance_t *hubInstance = s_HubGlobal.hubList; + uint32_t deviceAddress; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceAddress); + if (parentHubNo == deviceAddress) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + return hubInstance->totalThinktime; + } + return 0; +} + +#endif /* USB_HOST_CONFIG_HUB */ diff --git a/usb_1.1.0/host/class/usb_host_hub_app.h b/usb_1.1.0/host/class/usb_host_hub_app.h new file mode 100644 index 0000000..fd7df5b --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hub_app.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_HOST_HUB_APP_H_ +#define _USB_HOST_HUB_APP_H_ + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief HUB reset times*/ +#define USB_HOST_HUB_PORT_RESET_TIMES (1) + +/*! @brief HUB lock */ +#define USB_HostHubLock() USB_OsaMutexLock(s_HubGlobal.hubMutex) +/*! @brief HUB unlock */ +#define USB_HostHubUnlock() USB_OsaMutexUnlock(s_HubGlobal.hubMutex) + +/*! @brief HUB application global structure */ +typedef struct _usb_host_hub_global +{ + usb_host_handle hostHandle; /*!< This HUB list belong to this host*/ + usb_host_hub_instance_t *hubProcess; /*!< HUB in processing*/ + usb_host_hub_instance_t *hubList; /*!< host's HUB list*/ + usb_osa_mutex_handle hubMutex; /*!< HUB mutex*/ +} usb_host_hub_global_t; + +/*! @brief HUB application status */ +typedef enum _usb_host_hub_app_status +{ + kHubRunIdle = 0, /*!< Idle */ + kHubRunInvalid, /*!< Invalid state */ + kHubRunWaitSetInterface, /*!< Wait callback of set interface */ + kHubRunGetDescriptor7, /*!< Get 7 bytes HUB descriptor */ + kHubRunGetDescriptor, /*!< Get all HUB descriptor */ + kHubRunSetPortPower, /*!< Set HUB's port power */ + kHubRunGetStatusDone, /*!< HUB status changed */ +} usb_host_hub_app_status_t; + +/*! @brief HUB port application status */ +typedef enum _usb_host_port_app_status +{ + kPortRunIdle = 0, /*!< Idle */ + kPortRunInvalid, /*!< Invalid state */ + kPortRunWaitPortChange, /*!< Wait port status change */ + kPortRunCheckCPortConnection, /*!< Check C_PORT_CONNECTION */ + kPortRunGetPortConnection, /*!< Get port status data */ + kPortRunCheckPortConnection, /*!< Check PORT_CONNECTION */ + kPortRunWaitPortResetDone, /*!< Wait port reset transfer done */ + kPortRunWaitCPortReset, /*!< Wait C_PORT_RESET */ + KPortRunCheckCPortReset, /*!< Check C_PORT_RESET */ + kPortRunResetAgain, /*!< Reset port again */ + kPortRunPortAttached, /*!< Device is attached on the port */ + kPortRunCheckPortDetach, /*!< Check port is detached */ + kPortRunGetConnectionBit, /*!< Get the port status data */ + kPortRunCheckConnectionBit, /*!< Check PORT_CONNECTION */ +} usb_host_port_app_status_t; + +/*! @brief HUB data prime status */ +typedef enum _usb_host_hub_prime_status +{ + kPrimeNone = 0, /*!< Don't prime data*/ + kPrimeHubControl, /*!< Prime HUB control transfer*/ + kPrimePortControl, /*!< Prime port control transfer*/ + kPrimeInterrupt, /*!< Prime interrupt transfer*/ +} usb_host_hub_prime_status_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#endif /* USB_HOST_CONFIG_HUB */ + +#endif /* _USB_HOST_HUB_APP_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_msd.c b/usb_1.1.0/host/class/usb_host_msd.c new file mode 100644 index 0000000..ecb9706 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_msd.c @@ -0,0 +1,1155 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_MSD) && (USB_HOST_CONFIG_MSD)) +#include "usb_host.h" +#include "usb_host_msd.h" +#include "usb_host_hci.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief clear stall transfer callback. + * + * @param param callback parameter. + * @param transfer transfer. + * @param status transfer result status. + */ +static void USB_HostMsdClearHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief send clear stall transfer. + * + * @param msdInstance msd instance pointer. + * @param callbackFn callback function. + * @param endpoint endpoint address. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostMsdClearHalt(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint); + +/*! + * @brief mass storage reset three step processes are done. + * + * @param msdInstance msd instance pointer. + * @param status result status. + */ +static void USB_HostMsdResetDone(usb_host_msd_instance_t *msdInstance, usb_status_t status); + +/*! + * @brief mass storage reset process step 3 callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdMassResetClearOutCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief mass storage reset process step 2 callback. + * + * @param msdInstance msd instance pointer. + * @transfer transfer + * @param status result status. + */ +static void USB_HostMsdMassResetClearInCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief mass storage reset process step 1 callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdMassResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief mass storage control transfer callback function. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief this function is called when ufi command is done. + * + * @param msdInstance msd instance pointer. + */ +static void USB_HostMsdCommandDone(usb_host_msd_instance_t *msdInstance, usb_status_t status); + +/*! + * @brief csw transfer callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdCswCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief cbw transfer callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdCbwCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief data transfer callback. + * + * @param msdInstance sd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdDataCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief msd open interface. + * + * @param msdInstance msd instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostMsdOpenInterface(usb_host_msd_instance_t *msdInstance); + +/*! + * @brief msd set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostMsdSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief msd control transfer common code. + * + * This function allocate the resource for msd instance. + * + * @param msdInstance the msd class instance. + * @param pipeCallbackFn inner callback function. + * @param callbackFn callback function. + * @param callbackParam callback parameter. + * @param buffer buffer pointer. + * @param bufferLength buffer length. + * @param requestType request type. + * @param requestValue request value. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostMsdControl(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t pipeCallbackFn, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t *buffer, + uint16_t bufferLength, + uint8_t requestType, + uint8_t requestValue); + +/*! + * @brief command process function, this function is called many time for one command's different state. + * + * @param msdInstance the msd class instance. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostMsdProcessCommand(usb_host_msd_instance_t *msdInstance); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostMsdClearHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + if (status != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_TransferCancel); + } + + if (msdInstance->commandStatus == kMSD_CommandErrorDone) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); /* command fail */ + } + else + { + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } +} + +static usb_status_t USB_HostMsdClearHalt(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint) +{ + usb_status_t status; + usb_host_transfer_t *transfer; + + /* malloc one transfer */ + status = USB_HostMallocTransfer(msdInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + /* save the application callback function */ + msdInstance->controlCallbackFn = NULL; + msdInstance->controlCallbackParam = NULL; + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = msdInstance; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_CLEAR_FEATURE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(endpoint); + transfer->setupPacket.wLength = 0; + status = USB_HostSendSetup(msdInstance->hostHandle, msdInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + } + msdInstance->controlTransfer = transfer; + + return status; +} + +static void USB_HostMsdResetDone(usb_host_msd_instance_t *msdInstance, usb_status_t status) +{ + if (msdInstance->internalResetRecovery == 1) /* internal mass reset recovery */ + { + msdInstance->internalResetRecovery = 0; + + if ((status != kStatus_USB_Success) || (msdInstance->commandStatus == kMSD_CommandErrorDone)) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); /* command fail */ + } + else + { + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } + } + else /* user call mass storage reset recovery */ + { + if (msdInstance->controlCallbackFn != NULL) + { + msdInstance->controlCallbackFn(msdInstance->controlCallbackParam, NULL, 0, + status); /* callback to application */ + } + } +} + +static void USB_HostMsdMassResetClearOutCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + USB_HostMsdResetDone(msdInstance, status); /* mass storage reset done */ +} + +static void USB_HostMsdMassResetClearInCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + + if (status == kStatus_USB_Success) + { + if (msdInstance->outPipe != NULL) + { + /* continue to process mass storage reset */ + USB_HostMsdClearHalt( + msdInstance, USB_HostMsdMassResetClearOutCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)msdInstance->outPipe)->endpointAddress)); + } + } + else + { + USB_HostMsdResetDone(msdInstance, status); /* mass storage reset done */ + } +} + +static void USB_HostMsdMassResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + if (status == kStatus_USB_Success) + { + if (msdInstance->inPipe != NULL) + { + /* continue to process mass storage reset */ + USB_HostMsdClearHalt(msdInstance, USB_HostMsdMassResetClearInCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)); + } + } + else + { + USB_HostMsdResetDone(msdInstance, status); /* mass storage reset done */ + } +} + +static void USB_HostMsdControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + if (msdInstance->controlCallbackFn != NULL) + { + msdInstance->controlCallbackFn(msdInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); /* callback to application */ + } + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); +} + +static void USB_HostMsdCommandDone(usb_host_msd_instance_t *msdInstance, usb_status_t status) +{ + if (msdInstance->commandCallbackFn != NULL) + { + /* callback to application */ + msdInstance->commandCallbackFn(msdInstance->commandCallbackParam, msdInstance->msdCommand.dataBuffer, + msdInstance->msdCommand.dataSofar, status); + } + msdInstance->commandStatus = kMSD_CommandIdle; +} + +static void USB_HostMsdCswCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + if (status == kStatus_USB_Success) + { + /* kStatus_USB_Success */ + if ((transfer->transferSofar == 13) && + (msdInstance->msdCommand.cswBlock.CSWSignature == USB_HOST_MSD_CSW_SIGNATURE)) + { + switch (msdInstance->msdCommand.cswBlock.CSWStatus) + { + case 0: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Success); + break; + + case 1: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_MSDStatusFail); + break; + + case 2: + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + break; + + default: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_MSDStatusFail); + break; + } + } + else + { + /* mass reset recovery to end ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + else + { + if (status == kStatus_USB_TransferStall) /* case 1: stall */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (msdInstance->msdCommand.retryTime > 0) + { + /* clear stall to continue the ufi command */ + if (USB_HostMsdClearHalt( + msdInstance, USB_HostMsdClearHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)) != + kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + else if (status == kStatus_USB_TransferCancel) /* case 2: cancel */ + { + USB_HostMsdCommandDone(msdInstance, status); /* command cancel */ + } + else /* case 3: error */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (msdInstance->msdCommand.retryTime > 0) + { + USB_HostMsdProcessCommand(msdInstance); /* retry the last step transaction */ + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + } +} + +static void USB_HostMsdCbwCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + if (status == kStatus_USB_Success) + { + /* kStatus_USB_Success */ + if (transfer->transferSofar == USB_HOST_UFI_CBW_LENGTH) + { + msdInstance->commandStatus = kMSD_CommandTransferData; + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } + else + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; + } + if (msdInstance->msdCommand.retryTime > 0) + { + USB_HostMsdProcessCommand(msdInstance); /* retry the last step transaction */ + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + } + else + { + if (status == kStatus_USB_TransferStall) /* case 1: stall */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (msdInstance->msdCommand.retryTime > 0) + { + /* clear stall to continue the ufi command */ + if (USB_HostMsdClearHalt( + msdInstance, USB_HostMsdClearHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)) != + kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + else if (status == kStatus_USB_TransferCancel) /* case 2: cancel */ + { + USB_HostMsdCommandDone(msdInstance, status); /* command cancel */ + } + else /* case 3: error */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; + } + if (msdInstance->msdCommand.retryTime > 0) + { + USB_HostMsdProcessCommand(msdInstance); /* retry the last step transaction */ + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + return; + } +} + +static void USB_HostMsdDataCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + uint8_t direction; + + if (status == kStatus_USB_Success) + { + /* kStatus_USB_Success */ + msdInstance->msdCommand.dataSofar += transfer->transferSofar; + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } + else + { + if (status == kStatus_USB_TransferStall) /* case 1: stall */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (transfer->direction == USB_IN) + { + direction = USB_REQUEST_TYPE_DIR_IN; + } + else + { + direction = USB_REQUEST_TYPE_DIR_OUT; + } + + if (msdInstance->msdCommand.retryTime == 0) + { + msdInstance->commandStatus = kMSD_CommandTransferCSW; /* next step */ + } + /* clear stall to continue the ufi command */ + if (USB_HostMsdClearHalt(msdInstance, USB_HostMsdClearHaltCallback, + (direction | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)) != + kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + else if (status == kStatus_USB_TransferCancel) /* case 2: cancel */ + { + USB_HostMsdCommandDone(msdInstance, status); /* command cancel */ + } + else /* case 3: error */ + { + /* mass reset recovery to finish ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } +} + +static usb_status_t USB_HostMsdProcessCommand(usb_host_msd_instance_t *msdInstance) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_transfer_t *transfer; + + if (msdInstance->msdCommand.transfer == NULL) + { + /* malloc one transfer */ + status = USB_HostMallocTransfer(msdInstance->hostHandle, &(msdInstance->msdCommand.transfer)); + if (status != kStatus_USB_Success) + { + msdInstance->msdCommand.transfer = NULL; +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return kStatus_USB_Busy; + } + } + transfer = msdInstance->msdCommand.transfer; + switch (msdInstance->commandStatus) + { + case kMSD_CommandTransferCBW: /* ufi CBW phase */ + transfer->direction = USB_OUT; + transfer->transferBuffer = (uint8_t *)(&(msdInstance->msdCommand.cbwBlock)); + transfer->transferLength = USB_HOST_UFI_CBW_LENGTH; + transfer->callbackFn = USB_HostMsdCbwCallback; + transfer->callbackParam = msdInstance; + status = USB_HostSend(msdInstance->hostHandle, msdInstance->outPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host send error\r\n"); +#endif + } + break; + + case kMSD_CommandTransferData: /* ufi DATA phase */ + if (msdInstance->msdCommand.dataBuffer != NULL) + { + transfer->direction = msdInstance->msdCommand.dataDirection; + transfer->transferBuffer = (msdInstance->msdCommand.dataBuffer + msdInstance->msdCommand.dataSofar); + transfer->transferLength = (msdInstance->msdCommand.dataLength - msdInstance->msdCommand.dataSofar); + transfer->callbackParam = msdInstance; + if (msdInstance->msdCommand.dataSofar != msdInstance->msdCommand.dataLength) + { + if (transfer->direction == USB_OUT) + { + transfer->callbackFn = USB_HostMsdDataCallback; + status = USB_HostSend(msdInstance->hostHandle, msdInstance->outPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host send error\r\n"); +#endif + } + } + else + { + transfer->callbackFn = USB_HostMsdDataCallback; + status = USB_HostRecv(msdInstance->hostHandle, msdInstance->inPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host recv error\r\n"); +#endif + } + } + break; + } + else + { + /* don't break */ + } + } + else + { + /* don't break */ + } + case kMSD_CommandTransferCSW: /* ufi CSW phase */ + transfer->direction = USB_IN; + transfer->transferBuffer = (uint8_t *)&msdInstance->msdCommand.cswBlock; + transfer->transferLength = sizeof(usb_host_csw_t); + transfer->callbackFn = USB_HostMsdCswCallback; + transfer->callbackParam = msdInstance; + status = USB_HostRecv(msdInstance->hostHandle, msdInstance->inPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host recv error\r\n"); +#endif + } + break; + + case kMSD_CommandDone: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Success); + break; + + default: + break; + } + return status; +} + +/*! + * @brief all ufi function calls this api. + * + * This function implements the common ufi commands. + * + * @param classHandle the class msd handle. + * @param buffer buffer pointer. + * @param bufferLength buffer length. + * @param callbackFn callback function. + * @param callbackParam callback parameter. + * @param direction command direction. + * @param byteValues ufi command fields value. + * + * @return An error code or kStatus_USB_Success. + */ +usb_status_t USB_HostMsdCommand(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t direction, + uint8_t byteValues[10]) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + usb_host_cbw_t *cbwPointer = &(msdInstance->msdCommand.cbwBlock); + uint8_t index = 0; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (msdInstance->commandStatus != kMSD_CommandIdle) + { + return kStatus_USB_Busy; + } + + /* save the application callback function */ + msdInstance->commandCallbackFn = callbackFn; + msdInstance->commandCallbackParam = callbackParam; + + /* initialize CBWCB fields */ + for (index = 0; index < USB_HOST_UFI_BLOCK_DATA_VALID_LENGTH; ++index) + { + cbwPointer->CBWCB[index] = byteValues[index]; + } + + /* initialize CBW fields */ + cbwPointer->CBWDataTransferLength = USB_LONG_TO_LITTLE_ENDIAN(bufferLength); + cbwPointer->CBWFlags = direction; + cbwPointer->CBWLun = (byteValues[1] >> USB_HOST_UFI_LOGICAL_UNIT_POSITION); + cbwPointer->CBWCBLength = USB_HOST_UFI_BLOCK_DATA_VALID_LENGTH; + + msdInstance->commandStatus = kMSD_CommandTransferCBW; + if (direction == USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN) + { + msdInstance->msdCommand.dataDirection = USB_IN; + } + else + { + msdInstance->msdCommand.dataDirection = USB_OUT; + } + msdInstance->msdCommand.dataBuffer = buffer; + + msdInstance->msdCommand.dataLength = bufferLength; + msdInstance->msdCommand.dataSofar = 0; + msdInstance->msdCommand.retryTime = USB_HOST_MSD_RETRY_MAX_TIME; + + return USB_HostMsdProcessCommand(msdInstance); /* start to process ufi command */ +} + +static usb_status_t USB_HostMsdOpenInterface(usb_host_msd_instance_t *msdInstance) +{ + usb_status_t status; + uint8_t epIndex = 0; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_interface_t *interfacePointer; + + if (msdInstance->inPipe != NULL) /* close bulk in pipe if the pipe is open */ + { + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->inPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + msdInstance->inPipe = NULL; + } + if (msdInstance->outPipe != NULL) /* close bulk out pipe if the pipe is open */ + { + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->outPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + msdInstance->outPipe = NULL; + } + + /* open interface pipes */ + interfacePointer = (usb_host_interface_t *)msdInstance->interfaceHandle; + for (epIndex = 0; epIndex < interfacePointer->epCount; ++epIndex) + { + epDesc = interfacePointer->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = msdInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + status = USB_HostOpenPipe(msdInstance->hostHandle, &msdInstance->inPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_hid_set_interface fail to open pipe\r\n"); +#endif + return status; + } + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = msdInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + status = USB_HostOpenPipe(msdInstance->hostHandle, &msdInstance->outPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_hid_set_interface fail to open pipe\r\n"); +#endif + return status; + } + } + else + { + } + } + + return kStatus_USB_Success; +} + +static void USB_HostMsdSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = USB_HostMsdOpenInterface(msdInstance); /* msd open interface */ + } + + if (msdInstance->controlCallbackFn != NULL) + { + msdInstance->controlCallbackFn(msdInstance->controlCallbackParam, NULL, 0, + status); /* callback to application */ + } + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); +} + +usb_status_t USB_HostMsdInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + uint32_t infoValue; + usb_status_t status; + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)USB_OsaMemoryAllocate( + sizeof(usb_host_msd_instance_t)); /* malloc msd class instance */ + + if (msdInstance == NULL) + { + return kStatus_USB_AllocFail; + } + + /* initialize msd instance */ + msdInstance->deviceHandle = deviceHandle; + msdInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + msdInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + msdInstance->controlPipe = (usb_host_pipe_handle)infoValue; + + msdInstance->msdCommand.cbwBlock.CBWSignature = USB_LONG_TO_LITTLE_ENDIAN(USB_HOST_MSD_CBW_SIGNATURE); + status = USB_HostMallocTransfer(msdInstance->hostHandle, &(msdInstance->msdCommand.transfer)); + if (status != kStatus_USB_Success) + { + msdInstance->msdCommand.transfer = NULL; +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + } + + *classHandle = msdInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostMsdSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status = kStatus_USB_Error; + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + status = USB_HostOpenDeviceInterface(msdInstance->deviceHandle, + interfaceHandle); /* notify host driver the interface is open */ + if (status != kStatus_USB_Success) + { + return status; + } + msdInstance->interfaceHandle = interfaceHandle; + + /* cancel transfers */ + if (msdInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->inPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + if (msdInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->outPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (alternateSetting == 0) /* open interface directly */ + { + if (callbackFn != NULL) + { + status = USB_HostMsdOpenInterface(msdInstance); + callbackFn(callbackParam, NULL, 0, status); + } + } + else /* send setup transfer */ + { + /* malloc one transfer */ + if (USB_HostMallocTransfer(msdInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + msdInstance->controlCallbackFn = callbackFn; + msdInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = USB_HostMsdSetInterfaceCallback; + transfer->callbackParam = msdInstance; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_INTERFACE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)msdInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(msdInstance->hostHandle, msdInstance->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + msdInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + } + } + + return status; +} + +usb_status_t USB_HostMsdDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + usb_status_t status; + + if (classHandle != NULL) + { + if (msdInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->inPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->inPipe); /* close pipe */ + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + } + if (msdInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->outPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->outPipe); /* close pipe */ + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + } + if ((msdInstance->controlPipe != NULL) && + (msdInstance->controlTransfer != NULL)) /* cancel control transfer if there is on-going control transfer */ + { + status = + USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->controlPipe, msdInstance->controlTransfer); + } + if (msdInstance->msdCommand.transfer) + { + USB_HostFreeTransfer(msdInstance->hostHandle, msdInstance->msdCommand.transfer); + } + USB_HostCloseDeviceInterface(deviceHandle, + msdInstance->interfaceHandle); /* notify host driver the interface is closed */ + USB_OsaMemoryFree(msdInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostMsdControl(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t pipeCallbackFn, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t *buffer, + uint16_t bufferLength, + uint8_t requestType, + uint8_t requestValue) +{ + usb_host_transfer_t *transfer; + + if (msdInstance == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(msdInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + msdInstance->controlCallbackFn = callbackFn; + msdInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = pipeCallbackFn; + transfer->callbackParam = msdInstance; + + transfer->setupPacket.bmRequestType = requestType; + transfer->setupPacket.bRequest = requestValue; + transfer->setupPacket.wValue = 0x0000; + transfer->setupPacket.wIndex = + ((usb_host_interface_t *)msdInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber; + transfer->setupPacket.wLength = bufferLength; + + if (USB_HostSendSetup(msdInstance->hostHandle, msdInstance->controlPipe, transfer) != + kStatus_USB_Success) /* call host driver api */ + { + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + msdInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +usb_status_t USB_HostMsdMassStorageReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + + return USB_HostMsdControl(msdInstance, USB_HostMsdMassResetCallback, callbackFn, callbackParam, NULL, 0, + (USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE), + USB_HOST_HID_MASS_STORAGE_RESET); +} + +usb_status_t USB_HostMsdGetMaxLun(usb_host_class_handle classHandle, + uint8_t *logicalUnitNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + + return USB_HostMsdControl( + msdInstance, USB_HostMsdControlCallback, callbackFn, callbackParam, logicalUnitNumber, 1, + (USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE), + USB_HOST_HID_GET_MAX_LUN); +} + +#endif /* USB_HOST_CONFIG_MSD */ diff --git a/usb_1.1.0/host/class/usb_host_msd.h b/usb_1.1.0/host/class/usb_host_msd.h new file mode 100644 index 0000000..b062d9a --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_msd.h @@ -0,0 +1,872 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_HOST_MSD_H_ +#define _USB_HOST_MSD_H_ + +/******************************************************************************* + * MSD class private structure, enumeration, macro + ******************************************************************************/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* CBW and CSW Macros */ +#define USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT (0x00U) +#define USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN (0x80U) +#define USB_HOST_MSD_CBW_SIGNATURE (0x43425355U) +#define USB_HOST_MSD_CSW_SIGNATURE (0x53425355U) + +/* UFI data bit macro */ +#define USB_HOST_UFI_BLOCK_DATA_VALID_LENGTH (10U) +#define USB_HOST_UFI_LOGICAL_UNIT_POSITION (5U) +#define USB_HOST_UFI_CBW_LENGTH (31U) +#define USB_HOST_UFI_MODE_SENSE_PAGE_CONTROL_SHIFT (6U) +#define USB_HOST_UFI_MODE_SENSE_PAGE_CODE_SHIFT (0U) +#define USB_HOST_UFI_START_STOP_UNIT_LOEJ_SHIFT (1U) +#define USB_HOST_UFI_START_STOP_UNIT_START_SHIFT (0U) +#define USB_HOST_UFI_SEND_DIAGNOSTIC_SELF_TEST_SHIFT (2U) + +/******************************************************************************* + * MSD class public structure, enumeration, macro, function + ******************************************************************************/ +/*! + * @addtogroup usb_host_msc_drv + * @{ + */ + +/*! @brief retry time when transfer fail, when all the retries fail the transfer callback with error status */ +#define USB_HOST_MSD_RETRY_MAX_TIME (1U) +/*! @brief mass storage block size */ +#define USB_HOST_MSD_BLOCK_SIZE (512U) + +/*! @brief MSD class code */ +#define USB_HOST_MSD_CLASS_CODE (8U) +/*! @brief MSD sub-class code */ +#define USB_HOST_MSD_SUBCLASS_CODE_UFI (4U) +/*! @brief MSD sub-class code */ +#define USB_HOST_MSD_SUBCLASS_CODE_SCSI (6U) +/*! @brief MSD protocol code */ +#define USB_HOST_MSD_PROTOCOL_BULK (0x50U) + +/*! @brief MSD class-specific request (mass storage reset) */ +#define USB_HOST_HID_MASS_STORAGE_RESET (0xFFU) +/*! @brief MSD class-specific request (get maximum logical unit number) */ +#define USB_HOST_HID_GET_MAX_LUN (0xFEU) + +/*! @brief UFI command process status */ +typedef enum _usb_host_msd_command_status +{ + kMSD_CommandIdle = 0, + kMSD_CommandTransferCBW, + kMSD_CommandTransferData, + kMSD_CommandTransferCSW, + kMSD_CommandDone, + kMSD_CommandCancel, + kMSD_CommandErrorDone, +} usb_host_msd_command_status_t; + +/*! @brief MSC Bulk-Only command block wrapper (CBW) */ +typedef struct _usb_host_cbw +{ + uint32_t CBWSignature; /*!< Signature that helps identify this data packet as a CBW. The signature field shall + contain the value 43425355h (little endian), indicating a CBW */ + uint32_t + CBWTag; /*!< A Command Block Tag sent by the host. The device shall echo the contents of this field back to the + host in the dCSWTag field of the associated CSW */ + uint32_t CBWDataTransferLength; /*!< The number of bytes of data that the host expects to transfer on the Bulk-In or + Bulk-Out endpoint during the execution of this command */ + uint8_t CBWFlags; /*!< + Bit 7 Direction - the device shall ignore this bit if the dCBWDataTransferLength field is + zero, otherwise: + 0 = Data-Out from host to the device, + 1 = Data-In from the device to the host. + Bit 6 Obsolete. The host shall set this bit to zero. + Bits 5..0 Reserved - the host shall set these bits to zero. + */ + uint8_t CBWLun; /*!< The device Logical Unit Number (LUN) to which the command block is being sent */ + uint8_t CBWCBLength; /*!< The valid length of the CBWCB in bytes. This defines the valid length of the command + block. The only legal values are 1 through 16 (01h through 10h).*/ + uint8_t CBWCB[16]; /*!< The command block to be executed by the device*/ +} usb_host_cbw_t; + +/*! @brief MSC Bulk-Only command status wrapper (CSW) */ +typedef struct _usb_host_csw +{ + uint32_t CSWSignature; /*!< Signature that helps identify this data packet as a CSW. The signature field shall + contain the value 53425355h (little endian), indicating CSW.*/ + uint32_t CSWTag; /*!< The device shall set this field to the value received in the dCBWTag of the associated CBW*/ + uint32_t CSWDataResidue; /*!< the difference between the amount of data expected as stated in the + dCBWDataTransferLength and the actual amount of relevant data processed by the device.*/ + uint8_t CSWStatus; /*!< + bCSWStatus indicates the success or failure of the command. + 00h - Command passed. + 01h - Command Failed. + 02h - Phase error. + others - Reserved. + */ +} usb_host_csw_t; + +/*! @brief MSC UFI command information structure */ +typedef struct _usb_host_msd_command +{ + usb_host_cbw_t cbwBlock; /*!< CBW data block*/ + usb_host_csw_t cswBlock; /*!< CSW data block*/ + uint8_t *dataBuffer; /*!< Data buffer pointer*/ + uint32_t dataLength; /*!< Data buffer length*/ + uint32_t dataSofar; /*!< Successful transfer data length*/ + usb_host_transfer_t *transfer; /*!< The transfer is used for processing the UFI command*/ + uint8_t retryTime; /*!< The UFI command residual retry time, when it reduce to zero the UFI command fail */ + uint8_t dataDirection; /*!< The data direction, its value is USB_OUT or USB_IN*/ +} usb_host_msd_command_t; + +/*! @brief MSD instance structure, MSD usb_host_class_handle pointer to this structure */ +typedef struct _usb_host_msd_instance +{ + usb_host_handle hostHandle; /*!< This instance's related host handle*/ + usb_device_handle deviceHandle; /*!< This instance's related device handle*/ + usb_host_interface_handle interfaceHandle; /*!< This instance's related interface handle*/ + usb_host_pipe_handle controlPipe; /*!< This instance's related device control pipe*/ + usb_host_pipe_handle outPipe; /*!< MSD bulk out pipe*/ + usb_host_pipe_handle inPipe; /*!< MSD bulk in pipe*/ + transfer_callback_t commandCallbackFn; /*!< MSD UFI command callback function pointer*/ + void *commandCallbackParam; /*!< MSD UFI command callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< MSD control transfer callback function pointer*/ + void *controlCallbackParam; /*!< MSD control transfer callback parameter*/ + usb_host_transfer_t *controlTransfer; /*!< Ongoing control transfer*/ + usb_host_msd_command_t msdCommand; /*!< Ongoing MSD UFI command information*/ + uint8_t commandStatus; /*!< UFI command process status, see command_status_t*/ + uint8_t internalResetRecovery; /*!< 1 - class driver internal mass storage reset recovery is on-going; 0 - + application call USB_HostMsdMassStorageReset to reset or there is no reset*/ +} usb_host_msd_instance_t; + +/*! @brief UFI standard sense data structure */ +typedef struct _usb_host_ufi_sense_data +{ + uint8_t errorCode; /*!< This field shall contain a value of 70h to indicate current errors*/ + uint8_t reserved1; /*!< Reserved field*/ + uint8_t senseKey; /*!< Provide a hierarchy of error or command result information*/ + uint8_t information[4]; /*!< This field is command-specific; it is typically used by some commands to return a + logical block address denoting where an error occurred*/ + uint8_t additionalSenseLength; /*!< The UFI device sets the value of this field to ten, to indicate that ten more + bytes of sense data follow this field*/ + uint8_t reserved2[4]; /*!< Reserved field*/ + uint8_t additionalSenseCode; /*!< Provide a hierarchy of error or command result information*/ + uint8_t additionalSenseCodeQualifier; /*!< Provide a hierarchy of error or command result information*/ + uint8_t reserved3[4]; /*!< Reserved field*/ +} usb_host_ufi_sense_data_t; + +/*! @brief UFI standard inquiry data structure */ +typedef struct _usb_host_ufi_inquiry_data +{ + uint8_t peripheralDeviceType; /*!< Identifies the device currently connected to the requested logical unit*/ + uint8_t removableMediaBit; /*!< This shall be set to one to indicate removable media*/ + uint8_t version; /*!< Version*/ + uint8_t responseDataFormat; /*!< A value of 01h shall be used for UFI device*/ + uint8_t additionalLength; /*!< Specify the length in bytes of the parameters*/ + uint8_t reserved1[3]; /*!< Reserved field*/ + uint8_t vendorInformation[8]; /*!< Contains 8 bytes of ASCII data identifying the vendor of the product*/ + uint8_t productIdentification[16]; /*!< Contains 16 bytes of ASCII data as defined by the vendor*/ + uint8_t productRevisionLevel[4]; /*!< Contains 4 bytes of ASCII data as defined by the vendor*/ +} usb_host_ufi_inquiry_data_t; + +/*! @brief UFI read capacity data structure */ +typedef struct _usb_host_ufi_read_capacity +{ + uint8_t lastLogicalBlockAddress[4]; /*!< The logical block number*/ + uint8_t blockLengthInBytes[4]; /*!< Block size*/ +} usb_host_ufi_read_capacity_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @name USB host MSD class APIs + * @{ + */ + +/*! + * @brief Initializes the MSD instance. + * + * This function allocates the resources for the MSD instance. + * + * @param[in] deviceHandle The device handle. + * @param[out] classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostMsdInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets the interface. + * + * This function binds the interface with the MSD instance. + * + * @param[in] classHandle The class handle. + * @param[in] interfaceHandle The interface handle. + * @param[in] alternateSetting The alternate setting value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + * @retval kStatus_USB_Success Callback return status, the command succeeded. + * @retval kStatus_USB_Busy Callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall Callback return status, the transfer is stalled by the device. + * @retval kStatus_USB_Error Callback return status, open pipe fail. See the USB_HostOpenPipe. + */ +extern usb_status_t USB_HostMsdSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the MSD instance. + * + * This function frees the resource for the MSD instance. + * + * @param[in] deviceHandle The device handle. + * @param[in] classHandle The class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +extern usb_status_t USB_HostMsdDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Mass storage reset. + * + * This function implements the mass storage reset request. + * + * @param[in] classHandle The class handle. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostMsdMassStorageReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Gets the maximum logical unit number. + * + * This function implements the get maximum LUN request. + * + * @param[in] classHandle The class handle. + * @param[out] logicalUnitNumber Return logical unit number value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdGetMaxLun(usb_host_class_handle classHandle, + uint8_t *logicalUnitNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read (10). + * + * This function implements the UFI READ(10) command. This command requests that the UFI + * device transfer data to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Read block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRead10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read (12). + * + * This function implements the UFI READ(12) command and requests that the UFI + * device transfer data to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Read block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRead12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage write (10). + * + * This function implements the UFI WRITE(10) command and requests that the UFI device + * write the data transferred by the host to the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Write block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdWrite10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage write (12). + * + * This function implements the UFI WRITE(12) command and requests that the UFI device + * write the data transferred by the host to the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Write block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdWrite12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read capacity. + * + * This function implements the UFI READ CAPACITY command and allows the host to request + * capacities of the currently installed medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdReadCapacity(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage test unit ready. + * + * This function implements the UFI TEST UNIT READY command and + * checks if the UFI device is ready. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdTestUnitReady(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief mass storage request sense. + * + * This function implements the UFI REQUEST SENSE command, this command instructs + * the UFI device to transfer sense data to the host for the specified logical unit. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRequestSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage mode select. + * + * This function implements the UFI MODE SELECT command and allows the host + * to specify medium or device parameters to the UFI device. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdModeSelect(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage mode sense. + * + * This function implements the UFI MODE SENSE command and allows the UFI + * device to report medium or device parameters to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] pageControl The page control field specifies the type of mode parameters to return. + * @param[in] pageCode Buffer pointer. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdModeSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t pageControl, + uint8_t pageCode, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage inquiry. + * + * This function implements the UFI INQUIRY command and requests that information regarding + * parameters of the UFI device itself be sent to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdInquiry(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read format capacities. + * + * This function implements the UFI READ FORMAT CAPACITIES command and allows the host to request + * a list of the possible capacities that can be formatted on the currently installed medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdReadFormatCapacities(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage format unit. + * + * This function implements the UFI FORMAT UNIT command and the host sends this command to physically format one + * track of a diskette according to the selected options. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] trackNumber This specifies which track is to be formatted. + * @param[in] interLeave This specifies the interleave that shall be used for formatting. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdFormatUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t trackNumber, + uint16_t interLeave, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage prevents/allows a medium removal. + * + * This function implements the UFI PREVENT-ALLOW MEDIUM REMOVAL command and notifies the FUI device + * to enable or disable the removal of the medium in the logical unit. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] prevent Prevent or allow + * - 0: enable (allow) the removal of the medium + * - 1: disable (prevent) removal of the medium + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdPreventAllowRemoval(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t prevent, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage write and verify. + * + * This function implements the UFI WRITE AND VERIFY command and requests that the UFI device + * writes the data transferred by the host to the medium, then verifies the data on the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Write and verify block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdWriteAndVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage start stop unit. + * + * This function implements the UFI START-STOP UNIT command and instructs the UFI device + * to enable or disable media access operations . + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] loadEject A Load Eject (LoEj) bit of zero requests that no eject action be performed. A LoEj bit of + * one, with the + * Start bit cleared to zero, which instructs the UFI device to eject the media. + * @param[in] start A Start bit of one instructs the UFI device to enable media access operations. A Start bit + * of zero instructs the UFI device to disable media access operations. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdStartStopUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t loadEject, + uint8_t start, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage verify. + * + * This function implements the UFI VERIFY command and requests that the UFI device + * verify the data on the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] verificationLength The data length that need to be verified. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint16_t verificationLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage rezero. + * + * This function implements the UFI REZERO UNIT command. This command positions the head of + * the drive to the cylinder 0. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRezeroUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage seek(10). + * + * This function implements the UFI SEEK(10) command and requests that the UFI device + * seek to the specified Logical Block Address. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdSeek10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage send diagnostic. + * + * This function implements the UFI SEND DIAGNOSTIC command. This command requests the UFI device + * to do a reset or perform a self-test. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] selfTest 0 = perform special diagnostic test; 1 = perform default self-test. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdSendDiagnostic(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t selfTest, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_MSD_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_msd_ufi.c b/usb_1.1.0/host/class/usb_host_msd_ufi.c new file mode 100644 index 0000000..0e47e79 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_msd_ufi.c @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_MSD) && (USB_HOST_CONFIG_MSD)) +#include "usb_host.h" +#include "usb_host_msd.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* UFI command code */ +#define UFI_FORMAT_UNIT (0x04U) +#define UFI_INQUIRY (0x12U) +#define UFI_START_STOP (0x1BU) +#define UFI_MODE_SELECT (0x55U) +#define UFI_MODE_SENSE (0x5AU) +#define UFI_MEDIUM_REMOVAL (0x1EU) +#define UFI_READ10 (0x28U) +#define UFI_READ12 (0xA8U) +#define UFI_READ_CAPACITY (0x25U) +#define UFI_READ_FORMAT_CAPACITY (0x23U) +#define UFI_REQUEST_SENSE (0x03U) +#define UFI_REZERO_UINT (0x01U) +#define UFI_SEEK (0x2BU) +#define UFI_SEND_DIAGNOSTIC (0x1DU) +#define UFI_TEST_UNIT_READY (0x00U) +#define UFI_VERIFY (0x2FU) +#define UFI_WRITE10 (0x2AU) +#define UFI_WRITE12 (0xAAU) +#define UFI_WRITE_VERIFY (0x2EU) + +#define GET_BYTE_FROM_LE_LONG(b, n) \ + ((uint8_t)((USB_LONG_TO_LITTLE_ENDIAN(b)) >> (n * 8))) /* get the byte from the long value */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +extern usb_status_t USB_HostMsdCommand(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t direction, + uint8_t byteValues[10]); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +usb_status_t USB_HostMsdRead10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ10, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdRead12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ12, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + GET_BYTE_FROM_LE_LONG(blockNumber, 3), + GET_BYTE_FROM_LE_LONG(blockNumber, 2), + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0)}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdWrite10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_WRITE10, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdWrite12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_WRITE12, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + GET_BYTE_FROM_LE_LONG(blockNumber, 3), + GET_BYTE_FROM_LE_LONG(blockNumber, 2), + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0)}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdReadCapacity(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ_CAPACITY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdTestUnitReady(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_TEST_UNIT_READY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdRequestSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_REQUEST_SENSE, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + (uint8_t)bufferLength, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdModeSelect(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_MODE_SELECT, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdModeSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t pageControl, + uint8_t pageCode, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_MODE_SENSE, (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + (uint8_t)(((uint32_t)pageCode << USB_HOST_UFI_MODE_SENSE_PAGE_CONTROL_SHIFT) | + ((uint32_t)pageCode << USB_HOST_UFI_MODE_SENSE_PAGE_CODE_SHIFT)), + 0x00, 0x00, 0x00, 0x00, GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdInquiry(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_INQUIRY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + (uint8_t)bufferLength, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdReadFormatCapacities(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ_FORMAT_CAPACITY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdFormatUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t trackNumber, + uint16_t interLeave, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_FORMAT_UNIT, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + trackNumber, + GET_BYTE_FROM_LE_LONG(interLeave, 1), + GET_BYTE_FROM_LE_LONG(interLeave, 0), + 0x00, + 0x00, + GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdPreventAllowRemoval(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t prevent, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_MEDIUM_REMOVAL, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + prevent, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdWriteAndVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_WRITE_VERIFY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdStartStopUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t loadEject, + uint8_t start, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_START_STOP, (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), 0x00, 0x00, + (uint8_t)(((uint32_t)loadEject << USB_HOST_UFI_START_STOP_UNIT_LOEJ_SHIFT) | + ((uint32_t)start << USB_HOST_UFI_START_STOP_UNIT_START_SHIFT)), + 0x00, 0x00, 0x00, 0x00, 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint16_t verificationLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_VERIFY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(verificationLength, 1), + GET_BYTE_FROM_LE_LONG(verificationLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdRezeroUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_REZERO_UINT, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdSeek10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_SEEK, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdSendDiagnostic(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t selfTest, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_REZERO_UINT, + (uint8_t)(((uint32_t)logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION) | + ((uint32_t)selfTest << USB_HOST_UFI_SEND_DIAGNOSTIC_SELF_TEST_SHIFT)), + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +#endif /* USB_HOST_CONFIG_MSD */ diff --git a/usb_1.1.0/host/class/usb_host_phdc.c b/usb_1.1.0/host/class/usb_host_phdc.c new file mode 100644 index 0000000..e740487 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_phdc.c @@ -0,0 +1,1272 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_PHDC) && (USB_HOST_CONFIG_PHDC)) +#include "usb_host.h" +#include "usb_host_phdc.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief phdc control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief phdc set and clear feature endpoint halt callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcSetClearFeatureEndpointHaltCallback(void *param, + usb_host_transfer_t *transfer, + usb_status_t status); + +/*! + * @brief phdc interrupt pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcInterruptPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief phdc bulk in pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcBulkInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief phdc bulk out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcBulkOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief phdc set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/*! @brief meta-data message preamble signature string */ +static char const metaDataMsgPreambleSignature[] = "PhdcQoSSignature"; + +/******************************************************************************* + * Code + ******************************************************************************/ + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + +static void USB_HostPhdcClearInHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + + phdcInstance->controlTransfer = NULL; + /* Reduces the number of bulk transfer to 0 to expect new message preamble transfer */ + phdcInstance->numberTransferBulkIn = 0U; + if (phdcInstance->inCallbackFn != NULL) + { + /* callback to application */ + phdcInstance->inCallbackFn(phdcInstance->inCallbackParam, phdcInstance->stallDataBuffer, + phdcInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +static void USB_HostPhdcClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + + phdcInstance->controlTransfer = NULL; + if (phdcInstance->outCallbackFn != NULL) + { + /* callback to application */ + phdcInstance->outCallbackFn(phdcInstance->outCallbackParam, phdcInstance->stallDataBuffer, + phdcInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostPhdcClearHalt(usb_host_phdc_instance_t *phdcInstance, + usb_host_transfer_t *stallTransfer, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint) +{ + usb_status_t status; + usb_host_transfer_t *transfer; + + /* malloc one transfer */ + status = USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + phdcInstance->stallDataBuffer = stallTransfer->transferBuffer; + phdcInstance->stallDataLength = stallTransfer->transferSofar; + /* save the application callback function */ + phdcInstance->controlCallbackFn = NULL; + phdcInstance->controlCallbackParam = NULL; + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = phdcInstance; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_CLEAR_FEATURE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(endpoint); + transfer->setupPacket.wLength = 0; + status = USB_HostSendSetup(phdcInstance->hostHandle, phdcInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + } + phdcInstance->controlTransfer = transfer; + + return status; +} + +#endif + +/*! + * @brief phdc control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + phdcInstance->controlTransfer = NULL; + if (kStatus_USB_Success == status) + { + if (USB_HOST_PHDC_SET_FEATURE_REQUEST == transfer->setupPacket.bRequest) + { + /* Meta-data message preamble feature is enabled */ + phdcInstance->isMessagePreambleEnabled = 1U; + } + else if (USB_HOST_PHDC_CLEAR_FEATURE_REQUEST == transfer->setupPacket.bRequest) + { + /* Meta-data message preamble feature is disable */ + phdcInstance->isMessagePreambleEnabled = 0U; + } + else + { + } + } + if (NULL != phdcInstance->controlCallbackFn) + { + phdcInstance->controlCallbackFn(phdcInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc set and clear feature endpoint halt callback for meta-data message preamble error. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcSetClearFeatureEndpointHaltCallback(void *param, + usb_host_transfer_t *transfer, + usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + phdcInstance->controlTransfer = NULL; + if (kStatus_USB_Success == status) + { + if ((transfer->setupPacket.bRequest == USB_REQUEST_STANDARD_SET_FEATURE) && + (transfer->setupPacket.bmRequestType == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) && + (transfer->setupPacket.wValue == + USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT)) && + (transfer->setupPacket.wIndex == + USB_SHORT_TO_LITTLE_ENDIAN(phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress))) + { + /* The host shall issue CLEAR_FEATURE ENDPOINT_HALT request to the device */ + usb_host_process_feature_param_t featureParam; + featureParam.requestType = kRequestEndpoint; + featureParam.featureSelector = USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT; + featureParam.interfaceOrEndpoint = phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress; + if (kStatus_USB_Success != USB_HostPhdcSetClearFeatureEndpointHalt(phdcInstance->hostHandle, + USB_REQUEST_STANDARD_CLEAR_FEATURE, + &featureParam, NULL, NULL)) + { +#ifdef HOST_ECHO + usb_echo("Error for USB_HostPhdcSetClearFeatureEndpointHalt\r\n"); +#endif + } + } + if ((transfer->setupPacket.bRequest == USB_REQUEST_STANDARD_CLEAR_FEATURE) && + (transfer->setupPacket.bmRequestType == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) && + (transfer->setupPacket.wValue == + USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT)) && + (transfer->setupPacket.wIndex == + USB_SHORT_TO_LITTLE_ENDIAN(phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress))) + { + /* Reduces the number of bulk transfer to 0 to expect new message preamble transfer */ + phdcInstance->numberTransferBulkIn = 0U; + } + } + if (NULL != phdcInstance->controlCallbackFn) + { + /* Notify to application the status of request */ + phdcInstance->controlCallbackFn(phdcInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc interrupt pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcInterruptPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostPhdcClearHalt( + phdcInstance, transfer, USB_HostPhdcClearInHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)phdcInstance->interruptPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return; + } + } +#endif + if (NULL != phdcInstance->inCallbackFn) + { + phdcInstance->inCallbackFn(phdcInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc bulk in pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcBulkInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostPhdcClearHalt( + phdcInstance, transfer, USB_HostPhdcClearInHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)phdcInstance->bulkInPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return; + } + } +#endif + if (status == kStatus_USB_Success) + { + /* The meta-data message preamble is implemented and enabled */ + if (phdcInstance->isMessagePreambleEnabled == 1U) + { + /* The meta-data message preamble feature is enabled, then all data transfers or sets + of data transfers shall be preceded by a meta-data message preamble transfer. The + numberTransferBulkIn is initialized as zero for receiving this message preamble data, + then it is updated to the value of bNumTransfers field of message preamble data */ + if (phdcInstance->numberTransferBulkIn) + { + /* When numberTransferBulkIn reduces to 0, a new meta-data message preamble shall + be transferred */ + phdcInstance->numberTransferBulkIn--; + } + else + { + uint8_t preambleSignatureChecking = 1U; + /* The received packet is meta-data message preamble */ + usb_host_phdc_metadata_preamble_t *metaDataMsgPreamble = + (usb_host_phdc_metadata_preamble_t *)transfer->transferBuffer; + /* Meta-data message preamble signature checking */ + for (uint8_t i = 0U; i < USB_HOST_PHDC_MESSAGE_PREAMBLE_SIGNATURE_SIZE; i++) + { + if (*(transfer->transferBuffer + i) != metaDataMsgPreambleSignature[i]) + { + preambleSignatureChecking = 0U; + break; + } + } + if (preambleSignatureChecking) + { + /* Checks if the meta-data message preamble contains an invalid bmLatencyReliability value + or bNumTransfers value */ + if ((!(metaDataMsgPreamble->bNumberTransfers)) || /* bNumTransfers shall never equal zero */ + (metaDataMsgPreamble->bQosEncodingVersion != 0x01U) || /* Encoding version should be 0x01 */ + ((metaDataMsgPreamble->bmLatencyReliability != + 0x02U) && /* Medium.Good latency, reliability bin */ + (metaDataMsgPreamble->bmLatencyReliability != + 0x04U) && /* Medium.Better latency, reliability bin */ + (metaDataMsgPreamble->bmLatencyReliability != + 0x08U) && /* Medium.Best latency, reliability bin */ + (metaDataMsgPreamble->bmLatencyReliability != + 0x10U) && /* High.Best latency, reliability bin */ + (metaDataMsgPreamble->bmLatencyReliability != + 0x20U) /* VeryHigh.Best latency, reliability bin */)) + { + /* The host shall issue SET_FEATURE ENDPOINT_HALT request to the device */ + usb_host_process_feature_param_t featureParam; + featureParam.requestType = kRequestEndpoint; + featureParam.featureSelector = USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT; + featureParam.interfaceOrEndpoint = + phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress; + if (kStatus_USB_Success != + USB_HostPhdcSetClearFeatureEndpointHalt( + phdcInstance->hostHandle, USB_REQUEST_STANDARD_SET_FEATURE, &featureParam, NULL, NULL)) + { +#ifdef HOST_ECHO + usb_echo( + "USB_HostPhdcBulkInPipeCallback: Error for " + "USB_HostPhdcSetClearFeatureEndpointHalt\r\n"); +#endif + } + } + else + { + /* The meta-data message preamble data is correct, update the phdc status and + * numberTransferBulkIn value */ + phdcInstance->numberTransferBulkIn = metaDataMsgPreamble->bNumberTransfers; + } + } + } + } + } + if (NULL != phdcInstance->inCallbackFn) + { + phdcInstance->inCallbackFn(phdcInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc bulk out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcBulkOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostPhdcClearHalt( + phdcInstance, transfer, USB_HostPhdcClearOutHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)phdcInstance->bulkOutPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return; + } + } +#endif + if (NULL != phdcInstance->outCallbackFn) + { + phdcInstance->outCallbackFn(phdcInstance->outCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc open interface. + * + * @param phdcInstance phdc instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostPhdcOpenInterface(usb_host_phdc_instance_t *phdcInstance) +{ + usb_status_t status; + uint8_t epIndex = 0U; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_interface_t *interface; + if (NULL != phdcInstance->interruptPipe) + { + /* Close the PHDC interrupt pipe if it is opening */ + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->interruptPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when close pipe\r\n"); +#endif + } + phdcInstance->interruptPipe = NULL; + } + + if (NULL != phdcInstance->bulkInPipe) + { + /* Close the PHDC bulk in pipe if it is opening */ + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkInPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when close pipe\r\n"); +#endif + } + phdcInstance->bulkInPipe = NULL; + } + + if (NULL != phdcInstance->bulkOutPipe) + { + /* Close the PHDC bulk out pipe if it is opening */ + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkOutPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when close pipe\r\n"); +#endif + } + phdcInstance->bulkOutPipe = NULL; + } + + /* open interface pipes */ + interface = (usb_host_interface_t *)phdcInstance->interfaceHandle; + for (epIndex = 0U; epIndex < interface->epCount; ++epIndex) + { + epDesc = interface->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + /* Initialize the interrupt pipe */ + pipeInit.devInstance = phdcInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + status = USB_HostOpenPipe(phdcInstance->hostHandle, &phdcInstance->interruptPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + /* save interrupt in endpoint information */ + phdcInstance->interruptInEndpointInformation = interface->epList[epIndex]; + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + /* Initialize bulk in pipe */ + pipeInit.devInstance = phdcInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + status = USB_HostOpenPipe(phdcInstance->hostHandle, &phdcInstance->bulkInPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + /* save bulk in endpoint information */ + phdcInstance->bulkInEndpointInformation = interface->epList[epIndex]; + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + /* Initialize bulk out pipe */ + pipeInit.devInstance = phdcInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + status = USB_HostOpenPipe(phdcInstance->hostHandle, &phdcInstance->bulkOutPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + /* save bulk out endpoint information */ + phdcInstance->bulkOutEndpointInformation = interface->epList[epIndex]; + } + else + { + } + } + return kStatus_USB_Success; +} + +/*! + * @brief phdc set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + + phdcInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + /* set interface is done, open the interface */ + status = USB_HostPhdcOpenInterface(phdcInstance); + } + + if (NULL != phdcInstance->controlCallbackFn) + { + /* Notify to application the status of set interface request */ + phdcInstance->controlCallbackFn(phdcInstance->controlCallbackParam, NULL, 0U, status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief set interface. + * + * This function binds the interface with the phdc instance. + * + * @param classHandle the class handle. + * @param interfaceHandle the interface handle. + * @param alternateSetting the alternate setting value. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error send transfer fail, please reference to USB_HostSendSetup. + * @retval kStatus_USB_Busy callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall callback return status, the transfer is stall by device. + * @retval kStatus_USB_Error callback return status, open pipe fail, please reference to USB_HostOpenPipe. + */ +usb_status_t USB_HostPhdcSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status; + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (NULL == classHandle) + { + return kStatus_USB_InvalidParameter; + } + + phdcInstance->interfaceHandle = interfaceHandle; + + status = USB_HostOpenDeviceInterface(phdcInstance->deviceHandle, interfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + + /* Cancel interrupt transfers */ + if (NULL != phdcInstance->interruptPipe) + { + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->interruptPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSetInterface: Error when cancel pipe\r\n"); +#endif + } + } + /* Cancel bulk in transfers */ + if (NULL != phdcInstance->bulkInPipe) + { + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkInPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSetInterface: Error when cancel pipe\r\n"); +#endif + } + } + /* Cancel bulk out transfers */ + if (NULL != phdcInstance->bulkOutPipe) + { + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkOutPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSetInterface: Error when cancel pipe\r\n"); +#endif + } + phdcInstance->bulkOutPipe = NULL; + } + if (0U == alternateSetting) + { + if (NULL != callbackFn) + { + status = USB_HostPhdcOpenInterface(phdcInstance); + callbackFn(callbackParam, NULL, 0U, status); + } + } + else + { + /* Create transfer buffer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSetInterface: Error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save application callback function and parameter */ + phdcInstance->controlCallbackFn = callbackFn; + phdcInstance->controlCallbackParam = callbackParam; + /* Initialize transfer */ + transfer->callbackFn = USB_HostPhdcSetInterfaceCallback; + transfer->callbackParam = phdcInstance; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_INTERFACE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)phdcInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + /* Send set interface request to device */ + status = USB_HostSendSetup(phdcInstance->hostHandle, phdcInstance->controlPipe, transfer); + if (status == kStatus_USB_Success) + { + phdcInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + } + } + return status; +} + +/*! + * @brief initialize the phdc instance. + * + * This function allocates the resource for phdc instance. + * + * @param deviceHandle the device handle. + * @param classHandle return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +usb_status_t USB_HostPhdcInit(usb_host_handle deviceHandle, usb_host_class_handle *classHandle) +{ + usb_host_phdc_instance_t *phdcInstance = + (usb_host_phdc_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_phdc_instance_t)); + uint32_t infoValue; + + if (NULL == phdcInstance) + { + return kStatus_USB_AllocFail; + } + /* Initialize PHDC instance */ + phdcInstance->deviceHandle = deviceHandle; + phdcInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + phdcInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + phdcInstance->controlPipe = (usb_host_pipe_handle)infoValue; + + *classHandle = phdcInstance; + return kStatus_USB_Success; +} + +/*! + * @brief de-initialize the phdc instance. + * + * This function release the resource for phdc instance. + * + * @param deviceHandle the device handle. + * @param classHandle the class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +usb_status_t USB_HostPhdcDeinit(usb_host_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_status_t status; + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL != classHandle) + { + if (NULL != phdcInstance->interruptPipe) + { + /* Cancel/close interrupt transfers/pipe */ + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->interruptPipe, NULL); + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->interruptPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcDeinit: Error when close pipe\r\n"); +#endif + } + phdcInstance->interruptPipe = NULL; + } + if (NULL != phdcInstance->bulkInPipe) + { + /* Cancel/close bulk in transfers/pipe */ + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkInPipe, NULL); + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkInPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcDeinit: Error when close pipe\r\n"); +#endif + } + phdcInstance->bulkInPipe = NULL; + } + if (NULL != phdcInstance->bulkOutPipe) + { + /* Cancel/close bulk out transfers/pipe */ + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkOutPipe, NULL); + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkOutPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcDeinit: Error when close pipe\r\n"); +#endif + } + phdcInstance->bulkOutPipe = NULL; + } + if ((NULL != phdcInstance->controlPipe) && (NULL != phdcInstance->controlTransfer)) + { + /* Cancel control transfers */ + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->controlPipe, + phdcInstance->controlTransfer); + } + /* Close device interface */ + USB_HostCloseDeviceInterface(deviceHandle, phdcInstance->interfaceHandle); + /* Release PHDC instance */ + USB_OsaMemoryFree(phdcInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + return kStatus_USB_Success; +} + +/*! + * @brief receive data. + * + * This function implements phdc receiving data. + * + * @param classHandle the class handle. + * @param qos QoS of the data being received. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostRecv. + */ +usb_status_t USB_HostPhdcRecv(usb_host_class_handle classHandle, + uint8_t qos, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_transfer_t *transfer; + usb_host_pipe_handle pipe; + usb_host_phdc_qos_descriptor_t *qosDesc = NULL; + + if (NULL == classHandle) + { + return kStatus_USB_InvalidHandle; + } + + if ((NULL == phdcInstance->interruptPipe) && (NULL == phdcInstance->bulkInPipe)) + { + return kStatus_USB_Error; + } + /* Allocate the transfer buffer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save application callback function and parameter */ + phdcInstance->inCallbackFn = callbackFn; + phdcInstance->inCallbackParam = callbackParam; + /* Initialize the transfer pointer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackParam = phdcInstance; + /* The on can receive the data on interrupt pipe or bulk in pipe depends on the QoS value */ + pipe = (qos & 0x01U) ? (phdcInstance->interruptPipe) : (phdcInstance->bulkInPipe); + if (pipe == phdcInstance->bulkInPipe) + { + /* get bulk in QoS descriptor */ + qosDesc = (usb_host_phdc_qos_descriptor_t *)phdcInstance->bulkInEndpointInformation.epExtension; + transfer->callbackFn = USB_HostPhdcBulkInPipeCallback; + } + else + { + /* get interrupt in QoS descriptor */ + qosDesc = (usb_host_phdc_qos_descriptor_t *)phdcInstance->interruptInEndpointInformation.epExtension; + transfer->callbackFn = USB_HostPhdcInterruptPipeCallback; + } + /* Latency and reliability checking */ + if (!(qos & qosDesc->bmLatencyReliability)) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcRecv, ERROR: invalid QoS bin"); +#endif + return kStatus_USB_Error; + } + /* The previous control transfer is pending */ + if (NULL != phdcInstance->controlTransfer) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcRecv, ERROR: Control transfer is in progress"); +#endif + return kStatus_USB_Busy; + } + if (USB_HostRecv(phdcInstance->hostHandle, pipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +/*! + * @brief send data. + * + * This function implements phdc sending data. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSend. + */ +usb_status_t USB_HostPhdcSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_transfer_t *transfer; + usb_status_t status; + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL == phdcInstance->bulkOutPipe) + { + return kStatus_USB_Error; + } + if (NULL != phdcInstance->controlTransfer) + { + status = kStatus_USB_Busy; +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSend, Error: control transfer is in progress"); +#endif + return status; + } + /* The meta-data message preamble is implemented and enabled */ + if (phdcInstance->isMessagePreambleEnabled == 1U) + { + /* The meta-data message preamble feature is enabled, then all data transfers or sets + of data transfers shall be preceded by a meta-data message preamble transfer. The + numberTransferBulkOut is initialized as zero for sending this message preamble data, + then it is updated to the value of bNumTransfers field of message preamble data */ + if (phdcInstance->numberTransferBulkOut) + { + /* When numberTransferBulkOut reduces to 0, a new meta-data message preamble shall + be transferred */ + phdcInstance->numberTransferBulkOut--; + } + else + { + usb_host_phdc_qos_descriptor_t *qosDesc = + (usb_host_phdc_qos_descriptor_t *)phdcInstance->bulkOutEndpointInformation.epExtension; + ; + uint8_t latencyReliability = ((usb_host_phdc_metadata_preamble_t *)buffer)->bmLatencyReliability; + /* Latency reliability validity checking */ + if ((latencyReliability != 0x02U) && /* Medium.Good latency, reliability bin */ + (latencyReliability != 0x04U) && /* Medium.Better latency, reliability bin */ + (latencyReliability != 0x08U) && /* Medium.Best latency, reliability bin */ + (latencyReliability != 0x10U) && /* High.Best latency, reliability bin */ + (latencyReliability != 0x20U) /* VeryHigh.Best latency, reliability bin */) + { + status = kStatus_USB_InvalidRequest; +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSend, Error: invalid LatencyReliability"); +#endif + return status; + } + /* LatencyReliablity checking */ + if (0U == (qosDesc->bmLatencyReliability & latencyReliability)) + { + status = kStatus_USB_Error; +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSend, Error: the latency reliability is not supported by Bulk OUT endpoint"); +#endif + return status; + } + if (0U == ((usb_host_phdc_metadata_preamble_t *)buffer)->bNumberTransfers) + { + status = kStatus_USB_Error; +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSend, Error: the numTransfer should never zero"); +#endif + return status; + } + /* Update the number of bulk out transfer */ + phdcInstance->numberTransferBulkOut = ((usb_host_phdc_metadata_preamble_t *)buffer)->bNumberTransfers; + } + } + /* Allocate the transfer pointer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save the application callback function and parameter */ + phdcInstance->outCallbackFn = callbackFn; + phdcInstance->outCallbackParam = callbackParam; + /* Initialize the transfer pointer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostPhdcBulkOutPipeCallback; + transfer->callbackParam = phdcInstance; + if (USB_HostSend(phdcInstance->hostHandle, phdcInstance->bulkOutPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail to USB_HostSend\r\n"); +#endif + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} + +/*! + * @brief phdc sends control request. + * + * @param classHandle the class handle. + * @param request_type setup packet request. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSend. + */ +usb_status_t USB_HostPhdcSendControlRequest(usb_host_class_handle classHandle, + uint8_t request, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_status_t status = kStatus_USB_Success; + usb_host_transfer_t *transfer; + + if (NULL == classHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL == phdcInstance->controlPipe) + { + return kStatus_USB_Error; + } + + if (NULL != phdcInstance->controlTransfer) + { + return kStatus_USB_Busy; + } + /* Allocate the transfer pointer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save the callback function and parameter */ + phdcInstance->controlCallbackFn = callbackFn; + phdcInstance->controlCallbackParam = callbackParam; + /* Initialize the transfer pointer */ + transfer->callbackFn = USB_HostPhdcControlPipeCallback; + transfer->callbackParam = phdcInstance; + transfer->setupPacket.bRequest = request; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)phdcInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + switch (request) + { + case USB_HOST_PHDC_GET_STATUS_REQUEST: + /* Initialize the PHDC get status request */ + transfer->setupPacket.wValue = 0U; + transfer->setupPacket.bmRequestType = + USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wLength = 2U; + break; + case USB_HOST_PHDC_SET_FEATURE_REQUEST: + case USB_HOST_PHDC_CLEAR_FEATURE_REQUEST: + /* Initialize the PHDC set/clear feature request */ + transfer->setupPacket.bmRequestType = + USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wValue = + (USB_HOST_PHDC_FEATURE_METADATA | (uint16_t)((uint16_t)USB_HOST_PHDC_QOS_ENCODING_VERSION << 8U)); + transfer->setupPacket.wLength = 0U; + break; + default: + status = kStatus_USB_InvalidRequest; + break; + } + if (USB_HostSendSetup(phdcInstance->hostHandle, phdcInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + phdcInstance->controlTransfer = transfer; + + return status; +} + +/*! + * @brief phdc set and clear feature endpoint halt request for meta-data message preamble error. + * + * @param classHandle the class handle. + * @param request setup packet request. + * @param param request parameter + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSend. + */ +usb_status_t USB_HostPhdcSetClearFeatureEndpointHalt(usb_host_class_handle classHandle, + uint8_t request, + void *param, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_transfer_t *transfer; + if (NULL == classHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL == phdcInstance->controlPipe) + { + return kStatus_USB_Error; + } + + if (NULL != phdcInstance->controlTransfer) + { + return kStatus_USB_Busy; + } + /* Allocate the transfer pointer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save application callback function and parameter */ + phdcInstance->controlCallbackFn = callbackFn; + phdcInstance->controlCallbackParam = callbackParam; + /* Initialize the transfer request */ + transfer->callbackFn = USB_HostPhdcSetClearFeatureEndpointHaltCallback; + transfer->callbackParam = phdcInstance; + if (USB_HostRequestControl(phdcInstance->hostHandle, request, transfer, param)) + { +#ifdef HOST_ECHO + usb_echo("fail for USB_HostRequestControl\r\n"); +#endif + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + phdcInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +/*! + * @brief USB_HostPhdcGetEndpointInformation. + * This function returns the PHDC endpoint information structure contains endpoint + * descriptor and endpoint extended descriptor. + * + * @param classHandle the class handle. + * @param pipeType pipe type. + * @param direction pipe direction. + * + * @retval endpointReturn All input parameters are valid. + * @retval NULL One or more input parameters are invalid. + */ +usb_host_ep_t *USB_HostPhdcGetEndpointInformation(usb_host_class_handle classHandle, + uint8_t pipeType, + uint8_t direction) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_ep_t *endpointReturn = NULL; + if (NULL != classHandle) + { + if (pipeType == USB_ENDPOINT_BULK) + { + if (direction == USB_IN) + { + /* bulk in endpoint information */ + endpointReturn = (usb_host_ep_t *)&phdcInstance->bulkInEndpointInformation; + } + else + { + /* bulk out endpoint information */ + endpointReturn = (usb_host_ep_t *)&phdcInstance->bulkOutEndpointInformation; + } + } + else if (pipeType == USB_ENDPOINT_INTERRUPT) + { + /* interrupt in endpoint information */ + endpointReturn = (usb_host_ep_t *)&phdcInstance->interruptInEndpointInformation; + } + else + { + } + } + return endpointReturn; +} +#endif diff --git a/usb_1.1.0/host/class/usb_host_phdc.h b/usb_1.1.0/host/class/usb_host_phdc.h new file mode 100644 index 0000000..4b62b6b --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_phdc.h @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_HOST_PHDC_H__ +#define __USB_HOST_PHDC_H__ + +/******************************************************************************* + * PHDC class public structure, enumeration, macro, function + ******************************************************************************/ +/*! + * @addtogroup usb_host_phdc_drv + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHDC class code */ +#define USB_HOST_PHDC_CLASS_CODE (0x0FU) +/*! @brief PHDC sub class code */ +#define USB_HOST_PHDC_SUBCLASS_CODE (0x00U) +/*! @brief PHDC protocol */ +#define USB_HOST_PHDC_PROTOCOL (0x00U) +/*! @brief PHDC get status request */ +#define USB_HOST_PHDC_GET_STATUS_REQUEST (0x00U) +/*! @brief PHDC set feature request */ +#define USB_HOST_PHDC_SET_FEATURE_REQUEST (0x03U) +/*! @brief PHDC clear feature request */ +#define USB_HOST_PHDC_CLEAR_FEATURE_REQUEST (0x01U) +/*! @brief PHDC meta-data feature */ +#define USB_HOST_PHDC_FEATURE_METADATA (0x01U) +/*! @brief PHDC QoS information encoding feature */ +#define USB_HOST_PHDC_QOS_ENCODING_VERSION (0x01U) + +/*! @brief meta-data message preamble signature size */ +#define USB_HOST_PHDC_MESSAGE_PREAMBLE_SIGNATURE_SIZE (0x10U) + +/*! @brief PHDC class function descriptor type */ +#define USB_HOST_PHDC_CLASSFUNCTION_DESCRIPTOR (0x20U) +/*! @brief PHDC QoS descriptor type */ +#define USB_HOST_PHDC_QOS_DESCRIPTOR (0x21U) +/*! @brief PHDC function extension descriptor type */ +#define USB_HOST_PHDC_11073PHD_FUNCTION_DESCRIPTOR (0x30U) +/*! @brief PHDC meta-data descriptor type */ +#define USB_HOST_PHDC_METADATA_DESCRIPTOR (0x22U) + +/*! @brief PHDC class function descriptor structure as defined by the PHDC class specification */ +typedef struct _usb_host_phdc_class_function_desciptor +{ + uint8_t bLength; /*!< Class function descriptor length */ + uint8_t bDescriptortype; /*!< PHDC_CLASSFUNCTION_DESCRIPTOR type */ + uint8_t bPhdcDataCode; /*!< Data/Messaging format code */ + uint8_t bmCapability; /*!< If bit 0 is 1 the meta-data message preamble is implemented and 0 if it is not */ +} usb_host_phdc_class_function_desciptor_t; + +/*! @brief Function extension descriptor (device specialization) structure as defined by the PHDC class specification. + */ +typedef struct _usb_host_phdc_function_extension_descriptor +{ + uint8_t bLength; /*!< Function extension descriptor length */ + uint8_t bDescriptortype; /*!< PHDC_CLASSFUNCTION_DESCRIPTOR type */ + uint8_t bReserved; /*!< Reserved for future use */ + uint8_t bNumDevSpecs; /*!< Number of wDevSpecializations */ + uint16_t *wDevSpecializations; /*!< Variable length list that defines the device specialization */ +} usb_host_phdc_function_extension_descriptor_t; + +/*! @brief QoS descriptor structure as defined by the PHDC class specification. */ +typedef struct _usb_host_phdc_qos_descriptor +{ + uint8_t bLength; /*!< QoS descriptor length */ + uint8_t bDescriptortype; /*!< PHDC_QOS_DESCRIPTOR type */ + uint8_t bQosEncodingVersion; /*!< Version of QoS information encoding */ + uint8_t bmLatencyReliability; /*!< Latency/reliability bin for the QoS data */ +} usb_host_phdc_qos_descriptor_t; + +/*! @brief Metadata descriptor structure as defined by the PHDC class specification. */ +typedef struct _usb_host_phdc_metadata_descriptor +{ + uint8_t bLength; /*!< Metadata descriptor length */ + uint8_t bDescriptortype; /*!< Descriptor type */ + uint8_t *bOpaqueData; /*!< Opaque metadata */ +} usb_host_phdc_metadata_descriptor_t; + +/*! @brief Metadata message preamble structure as defined by the PHDC class specification. */ +typedef struct _usb_host_phdc_metadata_preamble +{ + uint8_t + aSignature[USB_HOST_PHDC_MESSAGE_PREAMBLE_SIGNATURE_SIZE]; /*!< Constant used to give preamble verifiability */ + uint8_t bNumberTransfers; /*!< Count of following transfer to which the QoS setting applies */ + uint8_t bQosEncodingVersion; /*!< Version of QoS information encoding */ + uint8_t bmLatencyReliability; /*!< See latency/reliability bin for the QoS data */ + uint8_t bOpaqueDataSize; /*!< Opaque QoS data or meta-data size */ + uint8_t *bOpaqueData; /*!< Opaque metadata */ +} usb_host_phdc_metadata_preamble_t; + +/*! @brief PHDC instance structure */ +typedef struct _usb_host_phdc_instance +{ + usb_host_handle hostHandle; /*!< The host handle */ + usb_device_handle deviceHandle; /*!< The device handle */ + usb_host_interface_handle interfaceHandle; /*!< The interface handle */ + usb_host_pipe_handle controlPipe; /*!< The control pipe */ + usb_host_pipe_handle interruptPipe; /*!< The interrupt pipe */ + usb_host_pipe_handle bulkInPipe; /*!< The bulk in pipe */ + usb_host_pipe_handle bulkOutPipe; /*!< The bulk out pipe */ + transfer_callback_t inCallbackFn; /*!< The callback function is called when the PHDC receives complete */ + void *inCallbackParam; /*!< The first parameter of the in callback function */ + transfer_callback_t outCallbackFn; /*!< The callback function is called when the PHDC sends complete */ + void *outCallbackParam; /*!< The first parameter of the out callback function */ + transfer_callback_t controlCallbackFn; /*!< The control callback function */ + void *controlCallbackParam; /*!< The first parameter of the control callback function */ + usb_host_transfer_t *controlTransfer; /*!< The control transfer pointer */ + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + uint8_t *stallDataBuffer; /*!< keep the data buffer for stall transfer's data*/ + uint32_t stallDataLength; /*!< keep the data length for stall transfer's data*/ +#endif + + usb_host_ep_t interruptInEndpointInformation; /*!< The interrupt in information */ + usb_host_ep_t bulkInEndpointInformation; /*!< The bulk in information */ + usb_host_ep_t bulkOutEndpointInformation; /*!< The bulk out information */ + uint8_t isMessagePreambleEnabled; /*!< The flag is used to check the message preamble feature is enabled or not */ + uint8_t numberTransferBulkOut; /*!< The number of transfer that follow Meta-data Message Preamble */ + uint8_t numberTransferBulkIn; /*!< The number of transfer that follow Meta-data Message Preamble */ +} usb_host_phdc_instance_t; + +/******************************************************************************* + * API + ******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @name USB host PHDC class APIs + * @{ + */ + +/*! + * @brief Initializes the PHDC instance. + * + * This function allocates the resource for PHDC instance. + * + * @param deviceHandle The device handle. + * @param classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostPhdcInit(usb_host_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets an interface. + * + * This function binds the interface with the PHDC instance. + * + * @param classHandle The class handle. + * @param interfaceHandle The interface handle. + * @param alternateSetting The alternate setting value. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + * @retval kStatus_USB_Busy Callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall Callback return status, the transfer is stalled by the device. + * @retval kStatus_USB_Error Callback return status, open pipe fail. See the USB_HostOpenPipe. + */ +extern usb_status_t USB_HostPhdcSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the PHDC instance. + * + * This function frees the resource for the PHDC instance. + * + * @param deviceHandle The device handle. + * @param classHandle The class handle. + * + * @retval kStatus_USB_Success The device is deinitialized successfully. + */ +extern usb_status_t USB_HostPhdcDeinit(usb_host_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Receives data. + * + * This function implements the PHDC receiving data. + * + * @param classHandle The class handle. + * @param qos QoS of the data being received. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostRecv. + */ +extern usb_status_t USB_HostPhdcRecv(usb_host_class_handle classHandle, + uint8_t qos, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Sends data. + * + * This function implements the PHDC sending data. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSend. + */ +extern usb_status_t USB_HostPhdcSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief PHDC sends the control request. + * + * @param classHandle The class handle. + * @param request Setup packet request. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSend. + */ +extern usb_status_t USB_HostPhdcSendControlRequest(usb_host_class_handle classHandle, + uint8_t request, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief PHDC set and clear feature endpoint halt request. + * + * @param classHandle The class handle. + * @param request Setup packet request. + * @param param Request parameter + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSend. + */ +extern usb_status_t USB_HostPhdcSetClearFeatureEndpointHalt(usb_host_class_handle classHandle, + uint8_t request, + void *param, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief USB_HostPhdcGetEndpointInformation. + * This function returns the PHDC endpoint information structure, which contains an endpoint + * descriptor and an endpoint extended descriptor. + * + * @param classHandle The class handle. + * @param pipeType Pipe type. + * @param direction Pipe direction. + * + * @retval endpointReturn All input parameters are valid. + * @retval NULL One or more input parameters are invalid. + */ +usb_host_ep_t *USB_HostPhdcGetEndpointInformation(usb_host_class_handle classHandle, + uint8_t pipeType, + uint8_t direction); + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_PHDC_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_printer.c b/usb_1.1.0/host/class/usb_host_printer.c new file mode 100644 index 0000000..5a10038 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_printer.c @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_PRINTER) && (USB_HOST_CONFIG_PRINTER)) +#include "usb_host.h" +#include "usb_host_printer.h" + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief printer in pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPrinterInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief printer out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPrinterOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief printer control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPrinterControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief printer open interface. It is called when set interface request success or open alternate setting 0 interface. + * + * @param printerInstance printer instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostPrinterOpenInterface(usb_host_printer_instance_t *printerInstance); + +/*! + * @brief printer set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPrinterSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief printer send control transfer common code. + * + * @param classHandle the class handle. + * @param requestType setup packet request type. + * @param request setup packet request value. + * @param wvalue setup packet wValue. + * @param windex setup packet wIndex. + * @param wlength setup packet wlength value. + * @param data data buffer pointer + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostPrinterControl(usb_host_printer_instance_t *printerInstance, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint16_t wlength, + uint8_t *data, + transfer_callback_t callbackFn, + void *callbackParam); + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/******************************************************************************* + * Variables + ******************************************************************************/ +/******************************************************************************* + * Code + ******************************************************************************/ + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) +static void USB_HostPrinterClearInHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + + if (printerInstance->inCallbackFn != NULL) + { + /* callback to application */ + printerInstance->inCallbackFn(printerInstance->outCallbackParam, printerInstance->stallDataBuffer, + printerInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static void USB_HostPrinterClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + + if (printerInstance->outCallbackFn != NULL) + { + /* callback to application */ + printerInstance->outCallbackFn(printerInstance->outCallbackParam, printerInstance->stallDataBuffer, + printerInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static void USB_HostPrinterClearHalt(usb_host_printer_instance_t *printerInstance, + usb_host_transfer_t *stallTransfer, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint) +{ + usb_status_t status; + usb_host_transfer_t *transfer; + + /* malloc one transfer */ + status = USB_HostMallocTransfer(printerInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + printerInstance->stallDataBuffer = stallTransfer->transferBuffer; + printerInstance->stallDataLength = stallTransfer->transferSofar; + /* save the application callback function */ + printerInstance->controlCallbackFn = NULL; + printerInstance->controlCallbackParam = NULL; + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = printerInstance; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_CLEAR_FEATURE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(endpoint); + transfer->setupPacket.wLength = 0; + status = USB_HostSendSetup(printerInstance->hostHandle, printerInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + } + printerInstance->controlTransfer = transfer; + + return status; +} +#endif + +static void USB_HostPrinterInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostPrinterClearHalt( + printerInstance, transfer, USB_HostPrinterClearInHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)printerInstance->inPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return; + } + } +#endif + + if (printerInstance->inCallbackFn != NULL) + { + /* callback to application */ + printerInstance->inCallbackFn(printerInstance->inCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static void USB_HostPrinterOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + if (status == kStatus_USB_TransferStall) + { + if (USB_HostPrinterClearHalt( + printerInstance, transfer, USB_HostPrinterClearOutHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)printerInstance->outPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return; + } + } +#endif + if (printerInstance->outCallbackFn != NULL) + { + /* callback to application */ + printerInstance->outCallbackFn(printerInstance->outCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static void USB_HostPrinterControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + + printerInstance->controlTransfer = NULL; + if (printerInstance->controlCallbackFn != NULL) + { + /* callback to application */ + printerInstance->controlCallbackFn(printerInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostPrinterOpenInterface(usb_host_printer_instance_t *printerInstance) +{ + usb_status_t status; + uint8_t epIndex = 0; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_interface_t *interfacePointer; + + if (printerInstance->inPipe != NULL) + { + status = USB_HostClosePipe(printerInstance->hostHandle, printerInstance->inPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + printerInstance->inPipe = NULL; + } + if (printerInstance->outPipe != NULL) /* close interrupt out pipe if it is open */ + { + status = USB_HostClosePipe(printerInstance->hostHandle, printerInstance->outPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + printerInstance->outPipe = NULL; + } + + /* open interface pipes */ + interfacePointer = (usb_host_interface_t *)printerInstance->interfaceHandle; + for (epIndex = 0; epIndex < interfacePointer->epCount; ++epIndex) + { + epDesc = interfacePointer->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = printerInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + printerInstance->inPacketSize = pipeInit.maxPacketSize; + + status = USB_HostOpenPipe(printerInstance->hostHandle, &printerInstance->inPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPrinterSetInterface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = printerInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + printerInstance->outPacketSize = pipeInit.maxPacketSize; + + status = USB_HostOpenPipe(printerInstance->hostHandle, &printerInstance->outPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPrinterSetInterface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else + { + } + } + + return kStatus_USB_Success; +} + +static void USB_HostPrinterSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + + printerInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = USB_HostPrinterOpenInterface(printerInstance); /* printer open interface */ + } + + if (printerInstance->controlCallbackFn != NULL) + { + /* callback to application */ + printerInstance->controlCallbackFn(printerInstance->controlCallbackParam, NULL, 0, status); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +usb_status_t USB_HostPrinterInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + uint32_t infoValue; + /* malloc printer class instance */ + usb_host_printer_instance_t *printerInstance = + (usb_host_printer_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_printer_instance_t)); + + if (printerInstance == NULL) + { + return kStatus_USB_AllocFail; + } + + /* initialize printer instance */ + printerInstance->deviceHandle = deviceHandle; + printerInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + printerInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + printerInstance->controlPipe = (usb_host_pipe_handle)infoValue; + + *classHandle = printerInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostPrinterSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status; + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + /* notify host driver the interface is open */ + status = USB_HostOpenDeviceInterface(printerInstance->deviceHandle, interfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + printerInstance->interfaceHandle = interfaceHandle; + + /* cancel transfers */ + if (printerInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->inPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + if (printerInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->outPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (alternateSetting == 0) /* open interface directly */ + { + if (callbackFn != NULL) + { + status = USB_HostPrinterOpenInterface(printerInstance); + callbackFn(callbackParam, NULL, 0, status); + } + } + else /* send setup transfer */ + { + /* malloc one transfer */ + if (USB_HostMallocTransfer(printerInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save the application callback function */ + printerInstance->controlCallbackFn = callbackFn; + printerInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = USB_HostPrinterSetInterfaceCallback; + transfer->callbackParam = printerInstance; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_INTERFACE; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)printerInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(printerInstance->hostHandle, printerInstance->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + printerInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + } + } + + return status; +} + +usb_status_t USB_HostPrinterDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_status_t status; + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (classHandle != NULL) /* class instance has initialized */ + { + if (printerInstance->inPipe != NULL) + { + status = + USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->inPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(printerInstance->hostHandle, printerInstance->inPipe); /* close pipe */ + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + printerInstance->inPipe = NULL; + } + if (printerInstance->outPipe != NULL) + { + status = + USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->outPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(printerInstance->hostHandle, printerInstance->outPipe); /* close pipe */ + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + printerInstance->outPipe = NULL; + } + if ((printerInstance->controlPipe != NULL) && + (printerInstance->controlTransfer != + NULL)) /* cancel control transfer if there is on-going control transfer */ + { + status = USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->controlPipe, + printerInstance->controlTransfer); + } + USB_HostCloseDeviceInterface(deviceHandle, + printerInstance->interfaceHandle); /* notify host driver the interface is closed */ + USB_OsaMemoryFree(printerInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostPrinterRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (printerInstance->inPipe == NULL) + { + return kStatus_USB_Error; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(printerInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + printerInstance->inCallbackFn = callbackFn; + printerInstance->inCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostPrinterInPipeCallback; + transfer->callbackParam = printerInstance; + + /* call host driver api */ + if (USB_HostRecv(printerInstance->hostHandle, printerInstance->inPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +uint16_t USB_HostPrinterGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction) +{ + usb_host_printer_instance_t *phdcInstance = (usb_host_printer_instance_t *)classHandle; + if (classHandle == NULL) + { + return 0; + } + + if (pipeType == USB_ENDPOINT_INTERRUPT) + { + if (direction == USB_IN) + { + return phdcInstance->inPacketSize; + } + else + { + return phdcInstance->outPacketSize; + } + } + + return 0; +} + +usb_status_t USB_HostPrinterSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (printerInstance->outPipe == NULL) + { + return kStatus_USB_Error; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(printerInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* save the application callback function */ + printerInstance->outCallbackFn = callbackFn; + printerInstance->outCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostPrinterOutPipeCallback; + transfer->callbackParam = printerInstance; + + /* call host driver api */ + if (USB_HostSend(printerInstance->hostHandle, printerInstance->outPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail to USB_HostSend\r\n"); +#endif + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostPrinterControl(usb_host_printer_instance_t *printerInstance, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint16_t wlength, + uint8_t *data, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_transfer_t *transfer; + + if (printerInstance == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (USB_HostMallocTransfer(printerInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + printerInstance->controlCallbackFn = callbackFn; + printerInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = data; + transfer->transferLength = wlength; + transfer->callbackFn = USB_HostPrinterControlPipeCallback; + transfer->callbackParam = printerInstance; + transfer->setupPacket.bmRequestType = requestType; + transfer->setupPacket.bRequest = request; + transfer->setupPacket.wValue = wvalue; + transfer->setupPacket.wIndex = windex; + transfer->setupPacket.wLength = USB_SHORT_TO_LITTLE_ENDIAN(wlength); + + /* call host driver api */ + if (USB_HostSendSetup(printerInstance->hostHandle, printerInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + printerInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +usb_status_t USB_HostPrinterGetDeviceId(usb_host_class_handle classHandle, + uint8_t interfaceIndex, + uint8_t alternateSetting, + uint8_t *buffer, + uint32_t length, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + uint32_t infoValue; + + USB_HostHelperGetPeripheralInformation(printerInstance->deviceHandle, kUSB_HostGetDeviceConfigIndex, &infoValue); + + return USB_HostPrinterControl( + printerInstance, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_PRINTER_GET_DEVICE_ID, (uint16_t)infoValue, + (uint16_t)((uint16_t)((uint16_t)interfaceIndex << 8U) | alternateSetting), length, buffer, callbackFn, + callbackParam); +} + +usb_status_t USB_HostPrinterGetPortStatus(usb_host_class_handle classHandle, + uint8_t *portStatus, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + + return USB_HostPrinterControl( + printerInstance, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_PRINTER_GET_PORT_STATUS, 0, + (uint16_t)(((usb_host_interface_t *)printerInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber), 1, + portStatus, callbackFn, callbackParam); +} + +usb_status_t USB_HostPrinterSoftReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + + return USB_HostPrinterControl( + printerInstance, USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_PRINTER_SOFT_RESET, 0, + (uint16_t)(((usb_host_interface_t *)printerInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber), 0, + NULL, callbackFn, callbackParam); +} + +#endif /* USB_HOST_CONFIG_PRINTER */ diff --git a/usb_1.1.0/host/class/usb_host_printer.h b/usb_1.1.0/host/class/usb_host_printer.h new file mode 100644 index 0000000..371ea80 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_printer.h @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_HOST_PRINTER_H__ +#define __USB_HOST_PRINTER_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @addtogroup usb_host_printer_drv + * @{ + */ + +/*! @brief Printer class code */ +#define USB_HOST_PRINTER_CLASS_CODE (7U) +/*! @brief Printer sub-class code */ +#define USB_HOST_PRINTER_SUBCLASS_CODE (1U) +/*! @brief Printer class protocol code (Unidirectional interface) */ +#define USB_HOST_PRINTER_PROTOCOL_UNIDIRECTION (1U) +/*! @brief Printer class protocol code (Bi-directional interface) */ +#define USB_HOST_PRINTER_PROTOCOL_BIDIRECTION (2U) +/*! @brief Printer class protocol code (IEEE® 1284.4 compatible bi-directional interface) */ +#define USB_HOST_PRINTER_PROTOCOL_IEEE1284 (3U) + +/*! @brief Printer class-specific request (GET_DEVICE_ID) */ +#define USB_HOST_PRINTER_GET_DEVICE_ID (0) +/*! @brief Printer class-specific request (GET_PORT_STATUS) */ +#define USB_HOST_PRINTER_GET_PORT_STATUS (1) +/*! @brief Printer class-specific request (SOFT_RESET) */ +#define USB_HOST_PRINTER_SOFT_RESET (2) + +/*! @brief Paper empty bit mask for GET_PORT_STATUS */ +#define USB_HOST_PRINTER_PORT_STATUS_PAPER_EMPTRY_MASK (0x20U) +/*! @brief Select bit mask for GET_PORT_STATUS */ +#define USB_HOST_PRINTER_PORT_STATUS_SELECT_MASK (0x10U) +/*! @brief Error bit mask for GET_PORT_STATUS */ +#define USB_HOST_PRINTER_PORT_STATUS_NOT_ERROR_MASK (0x08U) + +/*! @brief Printer instance structure and printer usb_host_class_handle pointer to this structure */ +typedef struct _usb_host_printer_instance +{ + usb_host_handle hostHandle; /*!< This instance's related host handle*/ + usb_device_handle deviceHandle; /*!< This instance's related device handle*/ + usb_host_interface_handle interfaceHandle; /*!< This instance's related interface handle*/ + usb_host_pipe_handle controlPipe; /*!< This instance's related device control pipe*/ + usb_host_pipe_handle inPipe; /*!< Printer bulk in pipe*/ + usb_host_pipe_handle outPipe; /*!< Printer bulk out pipe*/ + transfer_callback_t inCallbackFn; /*!< Printer bulk in transfer callback function pointer*/ + void *inCallbackParam; /*!< Printer bulk in transfer callback parameter*/ + transfer_callback_t outCallbackFn; /*!< Printer bulk out transfer callback function pointer*/ + void *outCallbackParam; /*!< Printer bulk out transfer callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< Printer control transfer callback function pointer*/ + void *controlCallbackParam; /*!< Printer control transfer callback parameter*/ + usb_host_transfer_t *controlTransfer; /*!< Ongoing control transfer*/ +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + uint8_t *stallDataBuffer; + uint32_t stallDataLength; +#endif + + uint16_t inPacketSize; /*!< Printer bulk in maximum packet size*/ + uint16_t outPacketSize; /*!< Printer bulk out maximum packet size*/ +} usb_host_printer_instance_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @name USB host printer class APIs + * @{ + */ + +/*! + * @brief Initializes the printer instance. + * + * This function allocate the resource for the printer instance. + * + * @param[in] deviceHandle The device handle. + * @param[out] classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostPrinterInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets the interface. + * + * This function binds the interface with the printer instance. + * + * @param[in] classHandle The class handle. + * @param[in] interfaceHandle The interface handle. + * @param[in] alternateSetting The alternate setting value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + * @retval kStatus_USB_Busy Callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall Callback return status, the transfer is stalled by the device. + * @retval kStatus_USB_Error Callback return status, open pipe fail. See the USB_HostOpenPipe. + */ +extern usb_status_t USB_HostPrinterSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief De-initializes the the printer instance. + * + * This function frees the resources for the printer instance. + * + * @param[in] deviceHandle The device handle. + * @param[in] classHandle The class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +extern usb_status_t USB_HostPrinterDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Gets the pipe maximum packet size. + * + * @param[in] classHandle The class handle. + * @param[in] pipeType Its value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or + * USB_ENDPOINT_INTERRUPT. + * See the usb_spec.h + * @param[in] direction Pipe direction. + * + * @retval 0 The classHandle is NULL. + * @retval Maximum Packet size. + */ +extern uint16_t USB_HostPrinterGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction); + +/*! + * @brief Receives data. + * + * This function implements the printer receiving data. + * + * @param[in] classHandle The class handle. + * @param[out] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostRecv. + */ +extern usb_status_t USB_HostPrinterRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Sends data. + * + * This function implements the printer sending data. + * + * @param[in] classHandle The class handle. + * @param[in] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSend. + */ +extern usb_status_t USB_HostPrinterSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Gets the pipe maximum packet size. + * + * @param[in] classHandle The class handle. + * @param[in] pipeType Its value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or + * USB_ENDPOINT_INTERRUPT. See the usb_spec.h + * @param[in] direction Pipe direction. + * + * @retval 0 The classHandle is NULL. + * @retval Maximum Packet size. + */ +extern uint16_t USB_HostPrinterGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction); + +/*! + * @brief Printer get device ID. + * + * This function implements the printer class-specific request (GET_DEVICE_ID). + * + * @param[in] classHandle The class handle. + * @param[in] interfaceIndex Interface index. + * @param[in] alternateSetting Get the alternateSetting's device ID. + * @param[out] buffer The buffer pointer. + * @param[in] length The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostPrinterGetDeviceId(usb_host_class_handle classHandle, + uint8_t interfaceIndex, + uint8_t alternateSetting, + uint8_t *buffer, + uint32_t length, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Printer get port status. + * + * This function implements the printer class-specific request (GET_PORT_STATUS). + * + * @param[in] classHandle The class handle. + * @param[in] portStatus Port status buffer. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostPrinterGetPortStatus(usb_host_class_handle classHandle, + uint8_t *portStatus, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Printer soft reset. + * + * This function implements the printer class-specific request (SOFT_RESET). + * + * @param[in] classHandle The class handle. + * @param[in] portStatus Port status buffer. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostPrinterSoftReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam); +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* __USB_HOST_PRINTER_H__ */ diff --git a/usb_1.1.0/host/usb_host.h b/usb_1.1.0/host/usb_host.h new file mode 100644 index 0000000..6237b21 --- /dev/null +++ b/usb_1.1.0/host/usb_host.h @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_HOST_H_ +#define _USB_HOST_H_ + +#include "usb.h" +#include "usb_misc.h" +#include "usb_spec.h" +#include "usb_host_framework.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +struct _usb_host_transfer; /* for cross reference */ + +/*! + * @addtogroup usb_host_drv + * @{ + */ + +/*! @brief USB host class handle type define */ +typedef void *usb_host_class_handle; + +/*! @brief USB host controller handle type define */ +typedef void *usb_host_controller_handle; + +/*! @brief USB host configuration handle type define */ +typedef void *usb_host_configuration_handle; + +/*! @brief USB host interface handle type define */ +typedef void *usb_host_interface_handle; + +/*! @brief USB host pipe handle type define */ +typedef void *usb_host_pipe_handle; + +/*! @brief Event codes for device attach/detach */ +typedef enum _usb_host_event +{ + kUSB_HostEventAttach = 1U, /*!< Device is attached */ + kUSB_HostEventDetach, /*!< Device is detached */ + kUSB_HostEventEnumerationDone, /*!< Device's enumeration is done and the device is supported */ + kUSB_HostEventNotSupported /*!< Device's enumeration is done and the device is not supported */ +} usb_host_event_t; + +/*! @brief USB host device information code */ +typedef enum _usb_host_dev_info +{ + kUSB_HostGetDeviceAddress = 1U, /*!< Device's address */ + kUSB_HostGetDeviceHubNumber, /*!< Device's first hub address */ + kUSB_HostGetDevicePortNumber, /*!< Device's first hub port number */ + kUSB_HostGetDeviceSpeed, /*!< Device's speed */ + kUSB_HostGetDeviceHSHubNumber, /*!< Device's first high-speed hub address */ + kUSB_HostGetDeviceHSHubPort, /*!< Device's first high-speed hub number */ + kUSB_HostGetDeviceLevel, /*!< Device's hub level */ + kUSB_HostGetHostHandle, /*!< Device's host handle */ + kUSB_HostGetDeviceControlPipe, /*!< Device's control pipe handle */ + kUSB_HostGetDevicePID, /*!< Device's PID */ + kUSB_HostGetDeviceVID, /*!< Device's VID */ + kUSB_HostGetHubThinkTime, /*!< Device's hub total think time */ + kUSB_HostGetDeviceConfigIndex, /*!< Device's running zero-based config index */ +} usb_host_dev_info_t; + +/*! + * @brief Host callback function typedef. + * + * This callback function is used to notify application device attach/detach event. + * This callback pointer is passed when initializing the host. + * + * @param deviceHandle The device handle, which indicates the attached device. + * @param configurationHandle The configuration handle contains the attached device's configuration information. + * @param event_code The callback event code; See the enumeration host_event_t. + * + * @return A USB error code or kStatus_USB_Success. + * @retval kStatus_USB_Success Application handles the attached device successfully. + * @retval kStatus_USB_NotSupported Application don't support the attached device. + * @retval kStatus_USB_Error Application handles the attached device falsely. + */ +typedef usb_status_t (*host_callback_t)(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode); + +/*! + * @brief Transfer callback function typedef. + * + * This callback function is used to notify the upper layer the result of the transfer. + * This callback pointer is passed when calling the send/receive APIs. + * + * @param param The parameter pointer, which is passed when calling the send/receive APIs. + * @param data The data buffer pointer. + * @param data_len The result data length. + * @param status A USB error code or kStatus_USB_Success. + */ +typedef void (*transfer_callback_t)(void *param, uint8_t *data, uint32_t dataLen, usb_status_t status); + +/*! + * @brief Host stack inner transfer callback function typedef. + * + * This callback function is used to notify the upper layer the result of a transfer. + * This callback pointer is passed when initializing the structure usb_host_transfer_t. + * + * @param param The parameter pointer, which is passed when calling the send/receive APIs. + * @param transfer The transfer information; See the structure usb_host_transfer_t. + * @param status A USB error code or kStatus_USB_Success. + */ +typedef void (*host_inner_transfer_callback_t)(void *param, struct _usb_host_transfer *transfer, usb_status_t status); + +/*! @brief USB host endpoint information structure */ +typedef struct _usb_host_ep +{ + usb_descriptor_endpoint_t *epDesc; /*!< Endpoint descriptor pointer*/ + uint8_t *epExtension; /*!< Endpoint extended descriptor pointer*/ + uint16_t epExtensionLength; /*!< Extended descriptor length*/ +} usb_host_ep_t; + +/*! @brief USB host interface information structure */ +typedef struct _usb_host_interface +{ + usb_host_ep_t epList[USB_HOST_CONFIG_INTERFACE_MAX_EP]; /*!< Endpoint array*/ + usb_descriptor_interface_t *interfaceDesc; /*!< Interface descriptor pointer*/ + uint8_t *interfaceExtension; /*!< Interface extended descriptor pointer*/ + uint16_t interfaceExtensionLength; /*!< Extended descriptor length*/ + uint8_t interfaceIndex; /*!< The interface index*/ + uint8_t alternateSettingNumber; /*!< The interface alternate setting value*/ + uint8_t epCount; /*!< Interface's endpoint number*/ +} usb_host_interface_t; + +/*! @brief USB host configuration information structure */ +typedef struct _usb_host_configuration +{ + usb_host_interface_t interfaceList[USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE]; /*!< Interface array*/ + usb_descriptor_configuration_t *configurationDesc; /*!< Configuration descriptor pointer*/ + uint8_t *configurationExtension; /*!< Configuration extended descriptor pointer*/ + uint16_t configurationExtensionLength; /*!< Extended descriptor length*/ + uint8_t interfaceCount; /*!< The configuration's interface number*/ +} usb_host_configuration_t; + +/*! @brief USB host pipe common structure */ +typedef struct _usb_host_pipe +{ + struct _usb_host_pipe *next; /*!< Link the idle pipes*/ + usb_device_handle deviceHandle; /*!< This pipe's device's handle*/ + uint16_t currentCount; /*!< For KHCI transfer*/ + uint16_t nakCount; /*!< Maximum NAK count*/ + uint16_t maxPacketSize; /*!< Maximum packet size*/ + uint16_t interval; /*!< FS/LS: frame unit; HS: micro-frame unit*/ + uint8_t open; /*!< 0 - closed, 1 - open*/ + uint8_t nextdata01; /*!< Data toggle*/ + uint8_t endpointAddress; /*!< Endpoint address*/ + uint8_t direction; /*!< Pipe direction*/ + uint8_t pipeType; /*!< Pipe type, for example USB_ENDPOINT_BULK*/ + uint8_t numberPerUframe; /*!< Transaction number per micro-frame*/ +} usb_host_pipe_t; + +/*! @brief USB host transfer structure */ +typedef struct _usb_host_transfer +{ + struct _usb_host_transfer *next; /*!< The next transfer structure*/ +#if USB_HOST_CONFIG_EHCI + uint32_t ehciUnitHead; /*!< QTD/ITD/SITD head for this transfer*/ + uint32_t ehciUnitTail; /*!< QTD/ITD/SITD tail for this transfer*/ +#endif + uint8_t *transferBuffer; /*!< Transfer data buffer*/ + uint32_t transferLength; /*!< Transfer data length*/ + uint32_t transferSofar; /*!< Have transferred length*/ + host_inner_transfer_callback_t callbackFn; /*!< Transfer callback function*/ + void *callbackParam; /*!< Transfer callback parameter*/ + usb_host_pipe_t *transferPipe; /*!< Transfer pipe pointer*/ + usb_setup_struct_t setupPacket; /*!< Set up packet buffer*/ + uint8_t direction; /*!< Transfer direction; its values are USB_OUT or USB_IN*/ + uint8_t setupStatus; /*!< Set up the transfer status*/ +#if USB_HOST_CONFIG_KHCI + int32_t transferResult; /*!< KHCI transfer result */ + uint32_t frame; /*!< KHCI transfer frame number */ + uint16_t nakTimeout; /*!< KHCI transfer NAK timeout */ + uint16_t retry; /*!< KHCI transfer retry */ +#endif +} usb_host_transfer_t; + +/*! @brief USB host pipe information structure for opening pipe */ +typedef struct _usb_host_pipe_init +{ + void *devInstance; /*!< Device instance handle*/ + uint16_t nakCount; /*!< Maximum NAK retry count. MUST be zero for interrupt*/ + uint16_t maxPacketSize; /*!< Pipe's maximum packet size*/ + uint8_t interval; /*!< Pipe's interval*/ + uint8_t endpointAddress; /*!< Endpoint address*/ + uint8_t direction; /*!< Endpoint direction*/ + uint8_t pipeType; /*!< Endpoint type, the value is USB_ENDPOINT_INTERRUPT, USB_ENDPOINT_CONTROL, + USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK*/ + uint8_t numberPerUframe; /*!< Transaction number for each micro-frame*/ +} usb_host_pipe_init_t; + +/*! @brief Cancel transfer parameter structure */ +typedef struct _usb_host_cancel_param +{ + usb_host_pipe_handle pipeHandle; /*!< Cancelling pipe handle*/ + usb_host_transfer_t *transfer; /*!< Cancelling transfer*/ +} usb_host_cancel_param_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @name USB host APIs Part 1 + * The following APIs are recommended for application use. + * @{ + */ + +/*! + * @brief Initializes the USB host stack. + * + * This function initializes the USB host module specified by the controllerId. + * + * @param[in] controllerId The controller ID of the USB IP. See the enumeration usb_controller_index_t. + * @param[out] hostHandle Returns the host handle. + * @param[in] callbackFn Host callback function notifies device attach/detach. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_InvalidHandle The host_handle_ptr is a NULL pointer. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller according to the controller ID. + * @retval kStatus_USB_AllocFail Allocation memory fail. + * @retval kStatus_USB_Error Host mutex create fail; KHCI/EHCI mutex or KHCI/EHCI event create fail, + * or, KHCI/EHCI IP initialize fail. + */ +extern usb_status_t USB_HostInit(uint8_t controllerId, usb_host_handle *hostHandle, host_callback_t callbackFn); + +/*! + * @brief Deinitializes the USB host stack. + * + * This function deinitializes the USB host module specified by the hostHandle. + * + * @param[in] hostHandle The host handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle is a NULL pointer. + * @retval kStatus_USB_Error Controller deinitialization fail. + */ +extern usb_status_t USB_HostDeinit(usb_host_handle hostHandle); + +/*! + * @brief Gets the device information. + * + * This function gets the device information. + * + * @param[in] deviceHandle Removing device handle. + * @param[in] infoCode See the enumeration host_dev_info_t. + * @param[out] infoValue Return the information value. + * + * @retval kStatus_USB_Success Close successfully. + * @retval kStatus_USB_InvalidParameter The deviceHandle or info_value is a NULL pointer. + * @retval kStatus_USB_Error The info_code is not the host_dev_info_t value. + */ +extern usb_status_t USB_HostHelperGetPeripheralInformation(usb_device_handle deviceHandle, + uint32_t infoCode, + uint32_t *infoValue); + +/*! + * @brief Parses the alternate interface descriptor. + * + * This function parses the alternate interface descriptor and returns an interface information through the structure + * usb_host_interface_t. + * + * @param[in] interfaceHandle The whole interface handle. + * @param[in] alternateSetting Alternate setting value. + * @param[out] interface Return interface information. + * + * @retval kStatus_USB_Success Close successfully. + * @retval kStatus_USB_InvalidHandle The interfaceHandle is a NULL pointer. + * @retval kStatus_USB_InvalidParameter The alternateSetting is 0. + * @retval kStatus_USB_Error The interface descriptor is wrong. + */ +extern usb_status_t USB_HostHelperParseAlternateSetting(usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + usb_host_interface_t *interface); + +/*! + * @brief Removes the attached device. + * + * This function removes the attached device. + * + * @param[in] hostHandle The host handle. + * @param[in] deviceHandle Removing device handle. + * + * @retval kStatus_USB_Success Remove successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle or deviceHandle is a NULL pointer. + * @retval kStatus_USB_InvalidParameter The deviceHandle instance don't belong to hostHandle instance. + */ +extern usb_status_t USB_HostRemoveDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle); + +/*! + * @brief KHCI task function. + * + * The function is used to handle the KHCI controller message. + * In the bare metal environment, this function should be called periodically in the main function. + * In the RTOS environment, this function should be used as a function entry to create a task. + * + * @param[in] hostHandle The host handle. + */ +extern void USB_HostKhciTaskFunction(void *hostHandle); + +/*! + * @brief EHCI task function. + * + * The function is used to handle the EHCI controller message. + * In the bare metal environment, this function should be called periodically in the main function. + * In the RTOS environment, this function should be used as a function entry to create a task. + * + * @param[in] hostHandle The host handle. + */ +extern void USB_HostEhciTaskFunction(void *hostHandle); + +/*! + * @brief Device KHCI ISR function. + * + * The function is the KHCI interrupt service routine. + * + * @param[in] hostHandle The host handle. + */ +extern void USB_HostKhciIsrFunction(void *hostHandle); + +/*! + * @brief Device EHCI ISR function. + * + * The function is the EHCI interrupt service routine. + * + * @param[in] hostHandle The host handle. + */ +extern void USB_HostEhciIsrFunction(void *hostHandle); +/*! @}*/ + +/*! + * @name USB host APIs Part 2. + * The following APIs are not recommended for application use. They are mainly used in the class driver. + * @{ + */ + +/*! + * @brief Opens the USB host pipe. + * + * This function opens a pipe according to the pipe_init_ptr parameter. + * + * @param[in] hostHandle The host handle. + * @param[out] pipeHandle The pipe handle pointer used to return the pipe handle. + * @param[in] pipeInit Used to initialize the pipe. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle or pipe_handle_ptr is a NULL pointer. + * @retval kStatus_USB_Error There is no idle pipe. + * Or, there is no idle QH for EHCI. + * Or, bandwidth allocate fail for EHCI. + */ +extern usb_status_t USB_HostOpenPipe(usb_host_handle hostHandle, + usb_host_pipe_handle *pipeHandle, + usb_host_pipe_init_t *pipeInit); + +/*! + * @brief Closes the USB host pipe. + * + * This function closes a pipe and frees the related resources. + * + * @param[in] hostHandle The host handle. + * @param[in] pipeHandle The closing pipe handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle or pipeHandle is a NULL pointer. + */ +extern usb_status_t USB_HostClosePipe(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle); + +/*! + * @brief Sends data to a pipe. + * + * This function requests to send the transfer to the specified pipe. + * + * @param[in] hostHandle The host handle. + * @param[in] pipeHandle The sending pipe handle. + * @param[in] transfer The transfer information. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle, pipeHandle or transfer is a NULL pointer. + * @retval kStatus_USB_LackSwapBuffer There is no swap buffer for KHCI. + * @retval kStatus_USB_Error There is no idle QTD/ITD/SITD for EHCI. + */ +extern usb_status_t USB_HostSend(usb_host_handle hostHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); + +/*! + * @brief Sends a setup transfer to the pipe. + * + * This function request to send the setup transfer to the specified pipe. + * + * @param[in] hostHandle The host handle. + * @param[in] pipeHandle The sending pipe handle. + * @param[in] transfer The transfer information. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle, pipeHandle or transfer is a NULL pointer. + * @retval kStatus_USB_LackSwapBuffer There is no swap buffer for KHCI. + * @retval kStatus_USB_Error There is no idle QTD/ITD/SITD for EHCI. + */ +extern usb_status_t USB_HostSendSetup(usb_host_handle hostHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); + +/*! + * @brief Receives the data from the pipe. + * + * This function requests to receive the transfer from the specified pipe. + * + * @param[in] hostHandle The host handle. + * @param[in] pipeHandle The receiving pipe handle. + * @param[in] transfer The transfer information. + * + * @retval kStatus_USB_Success Receive successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle, pipeHandle or transfer is a NULL pointer. + * @retval kStatus_USB_LackSwapBuffer There is no swap buffer for KHCI. + * @retval kStatus_USB_Error There is no idle QTD/ITD/SITD for EHCI. + */ +extern usb_status_t USB_HostRecv(usb_host_handle hostHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); + +/*! + * @brief Cancel the pipe's transfers. + * + * This function cancels all pipe's transfers when the parameter transfer is NULL or cancels the transfers altogether. + * + * @param[in] hostHandle The host handle. + * @param[in] pipeHandle The receiving pipe handle. + * @param[in] transfer The transfer information. + * + * @retval kStatus_USB_Success Cancel successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle or pipeHandle is a NULL pointer. + */ +extern usb_status_t USB_HostCancelTransfer(usb_host_handle hostHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); + +/*! + * @brief Allocates a transfer resource. + * + * This function allocates a transfer. This transfer is used to pass data information to a low level stack. + * + * @param[in] hostHandle The host handle. + * @param[out] transfer Return the transfer. + * + * @retval kStatus_USB_Success Allocate successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle or transfer is a NULL pointer. + * @retval kStatus_USB_Error There is no idle transfer. + */ +extern usb_status_t USB_HostMallocTransfer(usb_host_handle hostHandle, usb_host_transfer_t **transfer); + +/*! + * @brief Frees a transfer resource. + * + * This function frees a transfer. This transfer is used to pass data information to a low level stack. + * + * @param[in] hostHandle The host handle. + * @param[in] transfer Release the transfer. + * + * @retval kStatus_USB_Success Free successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle or transfer is a NULL pointer. + */ +extern usb_status_t USB_HostFreeTransfer(usb_host_handle hostHandle, usb_host_transfer_t *transfer); + +/*! + * @brief Requests the USB standard request. + * + * This function sends the USB standard request packet. + * + * @param[in] deviceHandle The device handle for control transfer. + * @param[in] usbRequest A USB standard request code. Se the usb_spec.h. + * @param[in] transfer The used transfer. + * @param[in] param The parameter structure is different for different request, see + * usb_host_framework.h. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The deviceHandle is a NULL pointer. + * @retval kStatus_USB_LackSwapBuffer There is no swap buffer for KHCI. + * @retval kStatus_USB_Error There is no idle QTD/ITD/SITD for EHCI, + * Or, the request is not standard request. + */ +extern usb_status_t USB_HostRequestControl(usb_device_handle deviceHandle, + uint8_t usbRequest, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief Opens the interface. + * + * This function opens the interface. It is used to notify the host driver the interface is used by APP or class driver. + * + * @param[in] deviceHandle Removing device handle. + * @param[in] interfaceHandle Opening interface handle. + * + * @retval kStatus_USB_Success Open successfully. + * @retval kStatus_USB_InvalidHandle The deviceHandle or interfaceHandle is a NULL pointer. + */ +extern usb_status_t USB_HostOpenDeviceInterface(usb_device_handle deviceHandle, + usb_host_interface_handle interfaceHandle); + +/*! + * @brief Closes an interface. + * + * This function opens an interface. It is used to notify the host driver the interface is not used by APP or class + * driver. + * + * @param[in] deviceHandle Removing device handle. + * @param[in] interfaceHandle Opening interface handle. + * + * @retval kStatus_USB_Success Close successfully. + * @retval kStatus_USB_InvalidHandle The deviceHandle is a NULL pointer. + */ +extern usb_status_t USB_HostCloseDeviceInterface(usb_device_handle deviceHandle, + usb_host_interface_handle interfaceHandle); + +/*! + * @brief Gets a host stack version function. + * + * The function is used to get the host stack version. + * + * @param[out] version The version structure pointer to keep the host stack version. + * + */ +extern void USB_HostGetVersion(uint32_t *version); + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_H_ */ diff --git a/usb_1.1.0/host/usb_host_devices.c b/usb_1.1.0/host/usb_host_devices.c new file mode 100644 index 0000000..f4ec31b --- /dev/null +++ b/usb_1.1.0/host/usb_host_devices.c @@ -0,0 +1,1345 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#include "usb_host.h" +#include "usb_host_hci.h" +#include "usb_host_devices.h" + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) +#include "usb_host_hub.h" +#endif /* USB_HOST_CONFIG_HUB */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief enumeration transfer callback function. + * + * @param param callback parameter. + * @param transfer the transfer. + * @param status transfer result status. + */ +static void USB_HostEnumerationTransferCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief process the new step state. + * + * @param deviceInstance device instance pointer. + * + * @return kStatus_USB_Success or error codes + */ +static usb_status_t USB_HostProcessState(usb_host_device_instance_t *deviceInstance); + +/*! + * @brief process the previous step transfer result. + * + * @param deviceInstance device instance pointer. + * + * @return kStatus_USB_Success or error codes + */ +static usb_status_t USB_HostProcessCallback(usb_host_device_instance_t *deviceInstance); + +/*! + * @brief notify the application event, the callback is registered when initializing host. + * + * @param deviceInstance device instance pointer. + * @param eventCode event code. + * + * @return kStatus_USB_Success or error codes + */ +static usb_status_t USB_HostNotifyDevice(usb_host_device_instance_t *deviceInstance, uint32_t eventCode); + +/*! + * @brief allocate one address. + * + * @param hostInstance host instance pointer. + * + * @return address, 0 is invalid. + */ +static uint8_t USB_HostAllocateDeviceAddress(usb_host_instance_t *hostInstance); + +/*! + * @brief release one address. + * + * @param hostInstance host instance pointer. + * @param address releasing address. + */ +static void USB_HostReleaseDeviceAddress(usb_host_instance_t *hostInstance, uint8_t address); + +/*! + * @brief release device resource. + * + * @param hostInstance host instance pointer. + * @param deviceInstance device instance pointer. + */ +static void USB_HostReleaseDeviceResource(usb_host_instance_t *hostInstance, + usb_host_device_instance_t *deviceInstance); + +/*! + * @brief parse device configuration descriptor. + * + * @param deviceHandle device handle. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostParseDeviceConfigurationDescriptor(usb_device_handle deviceHandle); + +/*! + * @brief remove device instance from host device list. + * + * @param hostHandle host instance handle. + * @param deviceHandle device handle. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostRemoveDeviceInstance(usb_host_handle hostHandle, usb_device_handle deviceHandle); + +/*! + * @brief control the bus. + * + * This function control the host bus. + * + * @param[in] hostHandle the host handle. + * @param[in] controlType the control code, please reference to bus_event_t. + * + * @retval kStatus_USB_Success control successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle is a NULL pointer. + */ +static usb_status_t USB_HostControlBus(usb_host_handle hostHandle, uint8_t controlType); + +extern usb_status_t USB_HostStandardSetGetDescriptor(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); +extern usb_status_t USB_HostStandardSetAddress(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); +extern usb_status_t USB_HostCh9RequestCommon(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + uint8_t *buffer, + uint32_t bufferLen); + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +extern usb_status_t USB_HostHubDeviceEvent(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode); + +extern uint32_t USB_HostHubGetHsHubNumber(uint8_t parentHubNo); + +extern uint32_t USB_HostHubGetHsHubPort(uint8_t parentHubNo, uint8_t parentPortNo); + +extern usb_status_t USB_HostHubRemovePort(uint8_t hubNumber, uint8_t portNumber); + +#endif + +/******************************************************************************* + * Variables + ******************************************************************************/ + +extern usb_host_instance_t g_UsbHostInstance[USB_HOST_CONFIG_MAX_HOST]; + +/*! @brief enumeration step process array */ +static const usb_host_enum_process_entry_t s_EnumEntries[] = \ +{ + /* kStatus_dev_initial */ + { + 0, 0, NULL, + }, + /* kStatus_DEV_GetDes8 */ + { + kStatus_DEV_SetAddress, kStatus_DEV_GetDes8, USB_HostProcessCallback, + }, + /* kStatus_DEV_SetAddress */ + { + kStatus_DEV_GetDes, kStatus_DEV_SetAddress, USB_HostProcessCallback, + }, + /* kStatus_DEV_GetDes */ + { + kStatus_DEV_GetCfg9, kStatus_DEV_GetDes, NULL, + }, + /* kStatus_DEV_GetCfg9 */ + { + kStatus_DEV_GetCfg, kStatus_DEV_GetCfg9, USB_HostProcessCallback, + }, + /* kStatus_DEV_GetCfg */ + { + kStatus_DEV_SetCfg, kStatus_DEV_GetCfg9, USB_HostProcessCallback, + }, + /* kStatus_DEV_SetCfg */ + { + kStatus_DEV_EnumDone, kStatus_DEV_SetCfg, NULL, + }, +}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostEnumerationTransferCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + uint8_t nextStep = 0; + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)param; + + USB_HostFreeTransfer(deviceInstance->hostHandle, transfer); /* free transfer */ + + if (status == kStatus_USB_Success) + { + nextStep = 1; + } + else if (status == kStatus_USB_TransferStall) + { +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + usb_echo("no response from device\r\n"); +#endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */ + if (deviceInstance->stallRetries > 0) /* retry same transfer when stall */ + { + deviceInstance->stallRetries--; + } + else /* process next state when all retries stall */ + { + nextStep = 1; + } + } + else if (status == kStatus_USB_TransferCancel) + { + return; + } + else + { + if (deviceInstance->enumRetries > 0) /* next whole retry */ + { + deviceInstance->enumRetries--; + deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + deviceInstance->configurationValue = 0; + deviceInstance->state = kStatus_DEV_GetDes8; + } + else + { +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + usb_echo("Device No Response\r\n"); +#endif + return; + } + } + + if (nextStep == 1) + { + deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + if (s_EnumEntries[deviceInstance->state - 1].process == NULL) + { + deviceInstance->state = s_EnumEntries[deviceInstance->state - 1].successState; /* next state */ + } + else + { + status = s_EnumEntries[deviceInstance->state - 1].process( + deviceInstance); /* process the previous state result */ + if (status == kStatus_USB_Success) /* process success */ + { + deviceInstance->state = s_EnumEntries[deviceInstance->state - 1].successState; + } + else if (status == kStatus_USB_Retry) /* need retry */ + { + deviceInstance->state = s_EnumEntries[deviceInstance->state - 1].retryState; + } + else if (status == kStatus_USB_NotSupported) /* device don't suport by the application */ + { + return; /* unrecoverable fail */ + } + else /* process error, next retry */ + { + if (deviceInstance->enumRetries > 0) /* next whole retry */ + { + deviceInstance->enumRetries--; + deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + deviceInstance->configurationValue = 0; + deviceInstance->state = kStatus_DEV_GetDes8; + } + else + { +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + usb_echo("Device No Response\r\n"); +#endif + return; /* unrecoverable fail */ + } + } + } + } + + if (USB_HostProcessState(deviceInstance) != kStatus_USB_Success) /* process the new state */ + { +#ifdef HOST_ECHO + usb_echo("enumation setup error\r\n"); +#endif + return; + } +} + +static usb_status_t USB_HostProcessState(usb_host_device_instance_t *deviceInstance) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_process_descriptor_param_t getDescriptorParam; + usb_host_transfer_t *transfer; + + /* malloc transfer */ + if (deviceInstance->state != kStatus_DEV_EnumDone) + { + if (USB_HostMallocTransfer(deviceInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + transfer->callbackFn = USB_HostEnumerationTransferCallback; + transfer->callbackParam = deviceInstance; + + /* reset transfer fields */ + transfer->setupPacket.bmRequestType = 0x00; + transfer->setupPacket.wIndex = 0; + transfer->setupPacket.wLength = 0; + transfer->setupPacket.wValue = 0; + } + + switch (deviceInstance->state) + { + case kStatus_DEV_GetDes8: + case kStatus_DEV_GetDes: /* get descriptor state */ + getDescriptorParam.descriptorLength = sizeof(usb_descriptor_device_t); + if (deviceInstance->state == kStatus_DEV_GetDes8) + { + getDescriptorParam.descriptorLength = 8; + } + getDescriptorParam.descriptorBuffer = (uint8_t *)&deviceInstance->deviceDescriptor; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_DEVICE; + getDescriptorParam.descriptorIndex = 0; + getDescriptorParam.languageId = 0; + + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); + break; + case kStatus_DEV_SetAddress: /* set address state */ + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_ADDRESS; + status = USB_HostStandardSetAddress(deviceInstance, transfer, &deviceInstance->allocatedAddress); + break; + + case kStatus_DEV_GetCfg9: /* get 9 bytes configuration state */ + getDescriptorParam.descriptorBuffer = deviceInstance->enumBuffer; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_CONFIGURE; + getDescriptorParam.descriptorIndex = deviceInstance->configurationValue; + getDescriptorParam.descriptorLength = 9; + getDescriptorParam.languageId = 0; + + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); + break; + + case kStatus_DEV_GetCfg: /* get configuration state */ + getDescriptorParam.descriptorBuffer = deviceInstance->configurationDesc; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_CONFIGURE; + getDescriptorParam.descriptorIndex = deviceInstance->configurationValue; + getDescriptorParam.descriptorLength = deviceInstance->configurationLen; + getDescriptorParam.languageId = 0; + + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); + break; + + case kStatus_DEV_SetCfg: /* set configuration state */ + transfer->setupPacket.wValue = + USB_SHORT_TO_LITTLE_ENDIAN(deviceInstance->configuration.configurationDesc->bConfigurationValue); + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_CONFIGURATION; + status = USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0); + break; + + case kStatus_DEV_EnumDone: /* enumeration done state */ + status = USB_HostNotifyDevice(deviceInstance, + kUSB_HostEventEnumerationDone); /* notify device enumeration done */ + if (status == kStatus_USB_Success) + { + deviceInstance->state = kStatus_DEV_AppUsed; + } + break; + + default: + break; + } + + return status; +} + +static usb_status_t USB_HostProcessCallback(usb_host_device_instance_t *deviceInstance) +{ + usb_host_pipe_t *pipe = (usb_host_pipe_t *)deviceInstance->controlPipe; + usb_status_t status = kStatus_USB_Success; + usb_descriptor_configuration_t *configureDesc; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + + switch (deviceInstance->state) + { + case kStatus_DEV_GetDes8: /* process get 8 bytes descriptor result */ + pipe->maxPacketSize = deviceInstance->deviceDescriptor.bMaxPacketSize0; + hostInstance->controllerTable->controllerIoctl( + hostInstance->controllerHandle, kUSB_HostUpdateControlPacketSize, deviceInstance->controlPipe); + break; + + case kStatus_DEV_SetAddress: /* process set address result */ + deviceInstance->setAddress = deviceInstance->allocatedAddress; + hostInstance->controllerTable->controllerIoctl( + hostInstance->controllerHandle, kUSB_HostUpdateControlEndpointAddress, deviceInstance->controlPipe); + break; + + case kStatus_DEV_GetDes: /* process set address result */ + /* NULL */ + break; + + case kStatus_DEV_GetCfg9: /* process get 9 bytes configuration result */ + configureDesc = (usb_descriptor_configuration_t *)&deviceInstance->enumBuffer[0]; + + deviceInstance->configurationLen = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(configureDesc->wTotalLength); + if (deviceInstance->configurationDesc != NULL) + { + USB_OsaMemoryFree(deviceInstance->configurationDesc); + deviceInstance->configurationDesc = NULL; + } + /* for KHCI, the start address and the length should be 4 byte align */ + if ((deviceInstance->configurationLen & 0x03) != 0) + { + deviceInstance->configurationDesc = + (uint8_t *)USB_OsaMemoryAllocate((deviceInstance->configurationLen & 0xFFFFFFFCu) + 4); + } + else + { + deviceInstance->configurationDesc = (uint8_t *)USB_OsaMemoryAllocate(deviceInstance->configurationLen); + } + if (deviceInstance->configurationDesc == NULL) + { + return kStatus_USB_Error; + } + break; + + case kStatus_DEV_GetCfg: /* process get cofiguration result */ + if (((usb_descriptor_configuration_t *)deviceInstance->configurationDesc)->bMaxPower > + USB_HOST_CONFIG_MAX_POWER) + { + return kStatus_USB_Error; + } + deviceInstance->configurationValue++; + if (USB_HostParseDeviceConfigurationDescriptor(deviceInstance) != + kStatus_USB_Success) /* parse configuration descriptor */ + { + return kStatus_USB_Error; + } + + status = USB_HostNotifyDevice(deviceInstance, kUSB_HostEventAttach); + + if (status != kStatus_USB_Success) + { + /* next configuration */ + if (deviceInstance->configurationValue < deviceInstance->deviceDescriptor.bNumConfigurations) + { + return kStatus_USB_Retry; + } + else + { + USB_HostNotifyDevice(deviceInstance, + kUSB_HostEventNotSupported); /* notify application device is not supported */ + return kStatus_USB_NotSupported; + } + } + break; + + case kStatus_DEV_SetCfg: + /* NULL */ + break; + + default: + break; + } + + return status; +} + +static usb_status_t USB_HostNotifyDevice(usb_host_device_instance_t *deviceInstance, uint32_t eventCode) +{ + usb_host_instance_t *hostInstance; + usb_status_t status1 = kStatus_USB_Error; +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + usb_status_t status2 = kStatus_USB_Error; + uint8_t haveHub; + uint8_t haveNoHub; + uint8_t interfaceIndex; +#endif /* USB_HOST_CONFIG_HUB */ + + if (deviceInstance == NULL) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + haveHub = 0; + haveNoHub = 0; + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (((usb_descriptor_interface_t *)deviceInstance->configuration.interfaceList[interfaceIndex].interfaceDesc) + ->bInterfaceClass == USB_HOST_HUB_CLASS_CODE) + { + haveHub = 1; + } + else + { + haveNoHub = 1; + } + } + + if ((haveNoHub == 1) && (hostInstance->deviceCallback != NULL)) + { + status1 = hostInstance->deviceCallback(deviceInstance, &deviceInstance->configuration, + eventCode); /* notify application event */ + } + if (haveHub) + { + status2 = + USB_HostHubDeviceEvent(deviceInstance, &deviceInstance->configuration, eventCode); /* notify hub event */ + } + + if ((status1 == kStatus_USB_Success) || (status2 == kStatus_USB_Success)) /* the device is supported */ + { + return kStatus_USB_Success; + } + else if (eventCode == kUSB_HostEventAttach) /* attach event */ + { + status1 = kStatus_USB_NotSupported; + } + else + { + status1 = kStatus_USB_Error; + } +#else + if (hostInstance->deviceCallback != NULL) + { + status1 = hostInstance->deviceCallback(deviceInstance, &deviceInstance->configuration, + eventCode); /* call host callback function */ + } +#endif + return status1; +} + +static uint8_t USB_HostAllocateDeviceAddress(usb_host_instance_t *hostInstance) +{ + uint8_t address = 0; + uint8_t addressIndex; + uint8_t addressBitIndex; + for (addressIndex = 0; addressIndex < 8; ++addressIndex) /* find the idle address postion byte */ + { + if (hostInstance->addressBitMap[addressIndex] != 0xFF) + { + break; + } + } + if (addressIndex < 8) + { + for (addressBitIndex = 0; addressBitIndex < 8; ++addressBitIndex) /* find the idle address position bit */ + { + if (!(hostInstance->addressBitMap[addressIndex] & (0x01u << addressBitIndex))) + { + hostInstance->addressBitMap[addressIndex] |= (0x01u << addressBitIndex); /* set the allocated bit */ + address = addressIndex * 8 + addressBitIndex + 1; /* the address minimum is 1 */ + break; + } + } + } + return address; +} + +static void USB_HostReleaseDeviceAddress(usb_host_instance_t *hostInstance, uint8_t address) +{ + USB_HostLock(); + hostInstance->addressBitMap[(uint32_t)(address - 1) >> 3] &= + (~(0x01u << (((uint32_t)address - 1) & 0x07U))); /* reset the allocated bit */ + USB_HostUnlock(); +} + +static usb_status_t USB_HostRemoveDeviceInstance(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *currentInstance; + usb_host_device_instance_t *prevInstance; + if ((hostHandle == NULL) || (deviceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* search and remove device instance */ + prevInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + if (prevInstance == deviceHandle) + { + hostInstance->deviceList = prevInstance->next; + return kStatus_USB_Success; + } + else + { + currentInstance = prevInstance->next; + } + + while (currentInstance != NULL) + { + if (currentInstance == deviceHandle) + { + prevInstance->next = currentInstance->next; + return kStatus_USB_Success; + } + prevInstance = currentInstance; + currentInstance = currentInstance->next; + } + + return kStatus_USB_Success; +} + +static void USB_HostReleaseDeviceResource(usb_host_instance_t *hostInstance, usb_host_device_instance_t *deviceInstance) +{ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + uint8_t level = 0; +#endif + /* release device's address */ + if (deviceInstance->setAddress != 0) + { + USB_HostReleaseDeviceAddress(hostInstance, deviceInstance->setAddress); + } + else + { + if (deviceInstance->allocatedAddress != 0) + { + USB_HostReleaseDeviceAddress(hostInstance, deviceInstance->allocatedAddress); + } + } + + /* close control pipe */ + if (deviceInstance->controlPipe != NULL) + { + USB_HostCancelTransfer(hostInstance, deviceInstance->controlPipe, NULL); + if (USB_HostClosePipe(hostInstance, deviceInstance->controlPipe) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + deviceInstance->controlPipe = NULL; + } + + /* free configuration buffer */ + if (deviceInstance->configurationDesc != NULL) + { + USB_OsaMemoryFree(deviceInstance->configurationDesc); + } + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + level = deviceInstance->level; +#endif + + /* free device instance buffer */ + USB_OsaMemoryFree(deviceInstance); + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + /* enable controller attach if root hub */ + if (level == 1) + { + USB_HostControlBus(hostInstance, kUSB_HostBusEnableAttach); + } +#else + /* enable controller attach */ + USB_HostControlBus(hostInstance, kUSB_HostBusEnableAttach); +#endif +} + +static usb_status_t USB_HostParseDeviceConfigurationDescriptor(usb_device_handle deviceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + uint32_t endPos; + usb_descriptor_union_t *unionDes; + usb_host_interface_t *interfaceParse = NULL; + usb_host_ep_t *epParse; + uint8_t *buffer; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + buffer = (uint8_t *)&deviceInstance->configuration; + /* clear the previous parse result, note: end_pos means buffer index here*/ + for (endPos = 0; endPos < sizeof(usb_host_configuration_t); endPos++) + { + buffer[endPos] = 0; + } + for (endPos = 0; endPos < USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE; ++endPos) + { + deviceInstance->interfaceStatus[endPos] = 0; + } + + /* parse configuration descriptor */ + unionDes = (usb_descriptor_union_t *)deviceInstance->configurationDesc; + endPos = (uint32_t)(deviceInstance->configurationDesc + deviceInstance->configurationLen); + + if ((unionDes->common.bLength == USB_DESCRIPTOR_LENGTH_CONFIGURE) && + (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_CONFIGURE)) + { + /* configuration descriptor */ + deviceInstance->configuration.configurationDesc = (usb_descriptor_configuration_t *)unionDes; + deviceInstance->configuration.configurationExtensionLength = 0; + deviceInstance->configuration.configurationExtension = NULL; + deviceInstance->configuration.interfaceCount = 0; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) + { + if (deviceInstance->configuration.configurationExtension == NULL) + { + deviceInstance->configuration.configurationExtension = (uint8_t *)unionDes; + } + if ((unionDes->common.bDescriptorType == 0x00) || + (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + deviceInstance->configuration.configurationExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + + /* interface descriptor */ + deviceInstance->configuration.interfaceCount = 0; + while ((uint32_t)unionDes < endPos) + { + if (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) + { + if (unionDes->interface.bAlternateSetting == 0x00) + { + if (deviceInstance->configuration.interfaceCount >= USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE) + { +#ifdef HOST_ECHO + usb_echo( + "Unsupported Device attached\r\n too many interfaces in one configuration, please increase " + "the USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE value\n"); +#endif + return kStatus_USB_Error; + } + interfaceParse = + &deviceInstance->configuration.interfaceList[deviceInstance->configuration.interfaceCount]; + deviceInstance->configuration.interfaceCount++; + interfaceParse->alternateSettingNumber = 0; + interfaceParse->epCount = 0; + interfaceParse->interfaceDesc = &unionDes->interface; + interfaceParse->interfaceExtensionLength = 0; + interfaceParse->interfaceExtension = NULL; + interfaceParse->interfaceIndex = unionDes->interface.bInterfaceNumber; + if (unionDes->common.bLength == 0x00) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + interfaceParse->interfaceExtension = (uint8_t *)unionDes; + while ((uint32_t)unionDes < endPos) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { + if ((unionDes->common.bDescriptorType == 0x00) || + (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + + /* endpoint descriptor */ + if (interfaceParse->interfaceDesc->bNumEndpoints != 0) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) || + (interfaceParse->interfaceDesc->bNumEndpoints > USB_HOST_CONFIG_INTERFACE_MAX_EP)) + { +#ifdef HOST_ECHO + usb_echo("interface descriptor error\n"); +#endif + return kStatus_USB_Error; + } + for (; interfaceParse->epCount < interfaceParse->interfaceDesc->bNumEndpoints; + (interfaceParse->epCount)++) + { + if (((uint32_t)unionDes >= endPos) || + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { +#ifdef HOST_ECHO + usb_echo("endpoint descriptor error\n"); +#endif + return kStatus_USB_Error; + } + epParse = (usb_host_ep_t *)&interfaceParse->epList[interfaceParse->epCount]; + epParse->epDesc = (usb_descriptor_endpoint_t *)unionDes; + epParse->epExtensionLength = 0; + epParse->epExtension = NULL; + if (unionDes->common.bLength == 0x00) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + epParse->epExtension = (uint8_t *)unionDes; + while ((uint32_t)unionDes < endPos) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)) + { + if ((unionDes->common.bDescriptorType == 0x00) || + (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + epParse->epExtensionLength += unionDes->common.bLength; + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = + (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + } + } + } + else + { + if (interfaceParse == NULL) + { + return kStatus_USB_Error; /* in normal situation this cannot reach */ + } + interfaceParse->alternateSettingNumber++; + if (unionDes->common.bLength == 0x00) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) + { + if ((unionDes->common.bDescriptorType == 0x00) || + (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + } + } + else + { + return kStatus_USB_Error; + } + } + } + + for (endPos = 0; endPos < deviceInstance->configuration.interfaceCount; ++endPos) + { + deviceInstance->interfaceStatus[endPos] = kStatus_interface_Attached; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostAttachDevice(usb_host_handle hostHandle, + uint8_t speed, + uint8_t hubNumber, + uint8_t portNumber, + uint8_t level, + usb_device_handle *deviceHandle) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *newInstance; +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + usb_host_device_instance_t *currentInstance; +#endif + uint8_t address; + usb_host_pipe_init_t pipeInit; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + +/* check whether is the device attached? */ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + currentInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + while (currentInstance != NULL) + { + if ((currentInstance->hubNumber == hubNumber) && (currentInstance->portNumber == portNumber)) + { + *deviceHandle = NULL; +#ifdef HOST_ECHO + usb_echo("device has attached\r\n"); +#endif + return kStatus_USB_Busy; + } + else + { + currentInstance = currentInstance->next; + } + } +#else + if (hostInstance->deviceList != NULL) + { + *deviceHandle = NULL; + usb_echo("device has attached\r\n"); + return kStatus_USB_Busy; + } +#endif + + /* Allocate new device instance */ + newInstance = (usb_host_device_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_device_instance_t)); + if (newInstance == NULL) + { +#ifdef HOST_ECHO + usb_echo("allocate dev instance fail\r\n"); +#endif + return kStatus_USB_AllocFail; + } + + /* new instance fields init */ + newInstance->hostHandle = hostHandle; + newInstance->speed = speed; + newInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + newInstance->enumRetries = USB_HOST_CONFIG_ENUMERATION_MAX_RETRIES; + newInstance->setAddress = 0; + newInstance->deviceAttachState = kStatus_device_Attached; + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + newInstance->hubNumber = hubNumber; + newInstance->portNumber = portNumber; + newInstance->level = level; + + if ((speed != USB_SPEED_HIGH) && (level > 1)) + { + newInstance->hsHubNumber = USB_HostHubGetHsHubNumber(hubNumber); + newInstance->hsHubPort = USB_HostHubGetHsHubPort(hubNumber, portNumber); + } + else + { + newInstance->hsHubNumber = hubNumber; + newInstance->hsHubPort = portNumber; + } +#endif /* USB_HOST_CONFIG_HUB */ + + USB_HostLock(); + /* allocate address && insert to the dev list */ + address = USB_HostAllocateDeviceAddress(hostInstance); + if (address == 0) + { +#ifdef HOST_ECHO + usb_echo("allocate address fail\r\n"); +#endif + USB_HostUnlock(); + USB_OsaMemoryFree(newInstance); + return kStatus_USB_Error; + } + newInstance->allocatedAddress = address; + + newInstance->next = (usb_host_device_instance_t *)hostInstance->deviceList; + hostInstance->deviceList = newInstance; + newInstance->state = kStatus_DEV_Initial; + USB_HostUnlock(); + + /* open control pipe */ + pipeInit.devInstance = newInstance; + pipeInit.pipeType = USB_ENDPOINT_CONTROL; + pipeInit.direction = 0; + pipeInit.endpointAddress = 0; + pipeInit.interval = 0; + pipeInit.maxPacketSize = 8; + pipeInit.numberPerUframe = 0; + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + if (USB_HostOpenPipe(hostHandle, &newInstance->controlPipe, &pipeInit) != kStatus_USB_Success) + { + /* don't need release resource, resource is released when detach */ + *deviceHandle = newInstance; + return kStatus_USB_Error; + } + + /* start enumeration */ + newInstance->state = kStatus_DEV_GetDes8; + USB_HostProcessState(newInstance); /* process enumeration state machine */ + + *deviceHandle = newInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostDetachDevice(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber) +{ + usb_host_device_instance_t *deviceInstance; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + USB_HostLock(); +/* search for device instance handle */ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + while (deviceInstance != NULL) + { + if ((deviceInstance->hubNumber == hubNumber) && (deviceInstance->portNumber == portNumber)) + { + break; + } + deviceInstance = deviceInstance->next; + } +#else + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; +#endif + USB_HostUnlock(); + if (deviceInstance != NULL) + { + return USB_HostDetachDeviceInternal(hostHandle, deviceInstance); /* device instance detach */ + } + return kStatus_USB_Success; +} + +usb_status_t USB_HostDetachDeviceInternal(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + if ((hostHandle == NULL) || (deviceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + deviceInstance->deviceAttachState = kStatus_device_Detached; /* mark the device is detached from host */ + + if (deviceInstance->state >= kStatus_DEV_Initial) /* device instance is valid */ + { + /* detach internally */ + if (deviceInstance->state < kStatus_DEV_AppUsed) /* enumeration is not done */ + { + if (deviceInstance->controlPipe != NULL) + { + USB_HostCancelTransfer(hostInstance, deviceInstance->controlPipe, NULL); + } + + /* remove device instance from host */ + USB_HostRemoveDeviceInstance(hostInstance, deviceInstance); + USB_HostReleaseDeviceResource(hostInstance, deviceInstance); + } + else /* enumeration has be done and notifed application */ + { + USB_HostNotifyDevice(deviceInstance, kUSB_HostEventDetach); /* notify application device detach */ + } + } + + return kStatus_USB_Success; +} + +uint8_t USB_HostGetDeviceAttachState(usb_device_handle deviceHandle) +{ + return deviceHandle ? ((usb_host_device_instance_t *)deviceHandle)->deviceAttachState : 0x0; +} + +usb_status_t USB_HostValidateDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_device_instance_t *searchDev; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + /* search for the device */ + searchDev = (usb_host_device_instance_t *)((usb_host_instance_t *)hostHandle)->deviceList; + while ((searchDev != NULL) && ((usb_device_handle)searchDev != deviceHandle)) + { + searchDev = searchDev->next; + } + + if (searchDev) + { + return kStatus_USB_Success; + } + return kStatus_USB_Error; +} + +static usb_status_t USB_HostControlBus(usb_host_handle hostHandle, uint8_t controlType) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, + &controlType); + + return status; +} + +usb_status_t USB_HostOpenDeviceInterface(usb_device_handle deviceHandle, usb_host_interface_handle interfaceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = NULL; + uint8_t interfaceIndex; + uint8_t index = 0; + + if ((deviceHandle == NULL) || (interfaceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + USB_HostLock(); + /* check host_instance valid? */ + for (; index < USB_HOST_CONFIG_MAX_HOST; ++index) + { + if ((g_UsbHostInstance[index].occupied == 1) && + ((usb_host_instance_t *)(&g_UsbHostInstance[index]) == (hostInstance))) + { + break; + } + } + if (index >= USB_HOST_CONFIG_MAX_HOST) + { + USB_HostUnlock(); + return kStatus_USB_Error; + } + + /* check deviceHandle valid? */ + if (USB_HostValidateDevice(hostInstance, deviceHandle) != kStatus_USB_Success) + { + USB_HostUnlock(); + return kStatus_USB_Error; + } + + /* search interface and set the interface as opened */ + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (&deviceInstance->configuration.interfaceList[interfaceIndex] == interfaceHandle) + { + deviceInstance->interfaceStatus[interfaceIndex] = kStatus_interface_Opened; + break; + } + } + USB_HostUnlock(); + + return kStatus_USB_Success; +} + +usb_status_t USB_HostCloseDeviceInterface(usb_device_handle deviceHandle, usb_host_interface_handle interfaceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = NULL; + uint8_t interfaceIndex; + uint8_t removeLabel = 1; + uint8_t index = 0; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + USB_HostLock(); + /* check host_instance valid? */ + for (; index < USB_HOST_CONFIG_MAX_HOST; ++index) + { + if ((g_UsbHostInstance[index].occupied == 1) && + ((usb_host_instance_t *)(&g_UsbHostInstance[index]) == (hostInstance))) + { + break; + } + } + if (index >= USB_HOST_CONFIG_MAX_HOST) + { + USB_HostUnlock(); + return kStatus_USB_Error; + } + + /* check deviceHandle valid? */ + if (USB_HostValidateDevice(hostInstance, deviceHandle) != kStatus_USB_Success) + { + USB_HostUnlock(); + return kStatus_USB_Error; + } + + if (interfaceHandle != NULL) + { + /* search interface and set the interface as detached */ + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (&deviceInstance->configuration.interfaceList[interfaceIndex] == interfaceHandle) + { + deviceInstance->interfaceStatus[interfaceIndex] = kStatus_interface_Detached; + break; + } + } + } + + if (deviceInstance->deviceAttachState == kStatus_device_Detached) /* device is removed from host */ + { + removeLabel = 1; + /* check all the interfaces of the device are not opened */ + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (deviceInstance->interfaceStatus[interfaceIndex] == kStatus_interface_Opened) + { + removeLabel = 0; + break; + } + } + if (removeLabel == 1) + { + /* remove device instance from host */ + USB_HostRemoveDeviceInstance(hostInstance, deviceInstance); + } + USB_HostUnlock(); + + if (removeLabel == 1) + { + USB_HostReleaseDeviceResource((usb_host_instance_t *)deviceInstance->hostHandle, + deviceInstance); /* release device resource */ + } + } + else + { + USB_HostUnlock(); + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostRemoveDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + uint8_t interfaceIndex = 0; +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + uint8_t level = 0; + uint8_t devHubNo; + uint8_t devPortNo; +#endif + + if ((hostHandle == NULL) || (deviceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + if (deviceInstance->hostHandle != hostHandle) + { + return kStatus_USB_InvalidParameter; + } + + if (USB_HostValidateDevice(hostInstance, deviceInstance) == kStatus_USB_Success) /* device is valid */ + { +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + devHubNo = deviceInstance->hubNumber; + devPortNo = deviceInstance->portNumber; + level = deviceInstance->level; +#endif + + deviceInstance->deviceAttachState = kStatus_device_Detached; + if (deviceInstance->state >= kStatus_DEV_Initial) /* device is valid */ + { + if (deviceInstance->state < kStatus_DEV_AppUsed) /* enumeraion is not done or application don't use */ + { + /* detach internally */ + USB_HostDetachDeviceInternal(hostHandle, deviceHandle); + } + else /* application use the device */ + { + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; + ++interfaceIndex) + { + if (deviceInstance->interfaceStatus[interfaceIndex] == kStatus_interface_Opened) + { +#ifdef HOST_ECHO + usb_echo("error: there is class instance that is not deinited\r\n"); +#endif + break; + } + } + /* remove device instance from host */ + USB_HostRemoveDeviceInstance(hostInstance, deviceInstance); + USB_HostReleaseDeviceResource(hostInstance, deviceInstance); /* release resource */ + } + } + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + if (level == 1) + { + USB_HostControlBus(hostHandle, kUSB_HostBusReset); /* reset controller port */ + USB_HostControlBus(hostHandle, kUSB_HostBusRestart); /* restart controller port */ + } + else + { + USB_HostHubRemovePort(devHubNo, devPortNo); /* reset hub port */ + } +#else + USB_HostControlBus(hostHandle, kUSB_HostBusReset); /* reset controller port */ + USB_HostControlBus(hostHandle, kUSB_HostBusRestart); /* restart controller port */ +#endif /* USB_HOST_CONFIG_HUB */ + } + + return kStatus_USB_Success; +} diff --git a/usb_1.1.0/host/usb_host_devices.h b/usb_1.1.0/host/usb_host_devices.h new file mode 100644 index 0000000..6dd0f31 --- /dev/null +++ b/usb_1.1.0/host/usb_host_devices.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_HOST_DEV_MNG_H_ +#define _USB_HOST_DEV_MNG_H_ + +#include "usb_host.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! + * @addtogroup usb_host_drv + * @{ + */ +/*! @brief States of device instances enumeration */ +typedef enum _usb_host_device_enumeration_status +{ + kStatus_DEV_Notinit = 0, /*!< Device is invalid */ + kStatus_DEV_Initial, /*!< Device has been processed by host driver */ + kStatus_DEV_GetDes8, /*!< Enumeration process: get 8 bytes' device descriptor */ + kStatus_DEV_SetAddress, /*!< Enumeration process: set device address */ + kStatus_DEV_GetDes, /*!< Enumeration process: get device descriptor */ + kStatus_DEV_GetCfg9, /*!< Enumeration process: get 9 bytes' configuration descriptor */ + kStatus_DEV_GetCfg, /*!< Enumeration process: get configuration descriptor */ + kStatus_DEV_SetCfg, /*!< Enumeration process: set configuration */ + kStatus_DEV_EnumDone, /*!< Enumeration is done */ + kStatus_DEV_AppUsed, /*!< This device has been used by application */ +} usb_host_device_enumeration_status_t; + +/*! @brief States of device's interface */ +typedef enum _usb_host_interface_state +{ + kStatus_interface_Attached = 1, /*!< Interface's default status */ + kStatus_interface_Opened, /*!< Interface is used by application */ + kStatus_interface_Detached, /*!< Interface is not used by application */ +} usb_host_interface_state_t; + +/*! @brief States of device */ +typedef enum _usb_host_device_state +{ + kStatus_device_Detached = 0, /*!< Device is used by application */ + kStatus_device_Attached, /*!< Device's default status */ +} usb_host_device_state_t; + +/*! @brief Device instance */ +typedef struct _usb_host_device_instance +{ + struct _usb_host_device_instance *next; /*!< Next device, or NULL */ + usb_host_handle hostHandle; /*!< Host handle */ + usb_host_configuration_t configuration; /*!< Parsed configuration information for the device */ + usb_descriptor_device_t deviceDescriptor; /*!< Standard device descriptor */ + usb_host_pipe_handle controlPipe; /*!< Device's control pipe */ + uint8_t *configurationDesc; /*!< Configuration descriptor pointer */ + uint16_t configurationLen; /*!< Configuration descriptor length */ + uint16_t configurationValue; /*!< Configuration index */ + uint8_t interfaceStatus[USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE]; /*!< Interfaces' status, please reference to + #usb_host_interface_state_t */ + uint8_t enumBuffer[9]; /*!< Buffer for enumeration */ + uint8_t state; /*!< Device state for enumeration */ + uint8_t enumRetries; /*!< Re-enumeration when error in control transfer */ + uint8_t stallRetries; /*!< Re-transfer when stall */ + uint8_t speed; /*!< Device speed */ + uint8_t allocatedAddress; /*!< Temporary address for the device. When set address request succeeds, setAddress is + a value, 1 - 127 */ + uint8_t setAddress; /*!< The address has been set to the device successfully, 1 - 127 */ + uint8_t deviceAttachState; /*!< See the usb_host_device_state_t */ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + /* hub related */ + uint8_t hubNumber; /*!< Device's first connected hub address (root hub = 0) */ + uint8_t portNumber; /*!< Device's first connected hub's port no (1 - 8) */ + uint8_t hsHubNumber; /*!< Device's first connected high-speed hub's address (1 - 8) */ + uint8_t hsHubPort; /*!< Device's first connected high-speed hub's port no (1 - 8) */ + uint8_t level; /*!< Device's level (root device = 0) */ +#endif +} usb_host_device_instance_t; + +typedef struct _usb_host_enum_process_entry +{ + uint8_t successState; /*!< When the last step is successful, the next state value */ + uint8_t retryState; /*!< When the last step need retry, the next state value */ + usb_status_t (*process)(usb_host_device_instance_t *deviceInstance); /*!< When the last step transfer is done, the + function is used to process the transfer + data */ +} usb_host_enum_process_entry_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Calls this function when device attach. + * + * @param hostHandle Host instance handle. + * @param speed Device speed. + * @param hubNumber Device hub no. root device's hub no. is 0. + * @param portNumber Device port no. root device's port no. is 0. + * @param level Device level. root device's level is 1. + * @param deviceHandle Return device handle. + * + * @return kStatus_USB_Success or error codes. + */ +extern usb_status_t USB_HostAttachDevice(usb_host_handle hostHandle, + uint8_t speed, + uint8_t hubNumber, + uint8_t portNumber, + uint8_t level, + usb_device_handle *deviceHandle); + +/*! + * @brief Call this function when device detaches. + * + * @param hostHandle Host instance handle. + * @param hubNumber Device hub no. root device's hub no. is 0. + * @param portNumber Device port no. root device's port no. is 0. + * + * @return kStatus_USB_Success or error codes. + */ +extern usb_status_t USB_HostDetachDevice(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber); + +/*! + * @brief Call this function when device detaches. + * + * @param hostHandle Host instance handle. + * @param deviceHandle Device handle. + * + * @return kStatus_USB_Success or error codes. + */ +extern usb_status_t USB_HostDetachDeviceInternal(usb_host_handle hostHandle, usb_device_handle deviceHandle); + +/*! + * @brief Gets the the device attach/detach state. + * + * @param deviceHandle Device handle. + * + * @return 0x01 - attached; 0x00 - detached. + */ +extern uint8_t USB_HostGetDeviceAttachState(usb_device_handle deviceHandle); + +/*! + * @brief Determine whether the device is attached. + * + * @param hostHandle Host instance pointer. + * @param deviceHandle Device handle. + * + * @return kStatus_USB_Success or error codes. + */ +extern usb_status_t USB_HostValidateDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle); + +/*! @}*/ +#endif /* _USB_HOST_DEV_MNG_H_ */ diff --git a/usb_1.1.0/host/usb_host_framework.c b/usb_1.1.0/host/usb_host_framework.c new file mode 100644 index 0000000..438f0f3 --- /dev/null +++ b/usb_1.1.0/host/usb_host_framework.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#include "usb_host.h" +#include "usb_host_hci.h" +#include "usb_host_devices.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @brief standard control transfer common code. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param buffer data buffer pointer. + * @param bufferLen data length. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostCh9RequestCommon(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + uint8_t *buffer, + uint32_t bufferLen); + +/*! + * @brief standard get status implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardGetStatus(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard set/clear feature implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSetClearFeature(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard set address implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSetAddress(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard set/get descriptor implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSetGetDescriptor(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard get interface implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardGetInterface(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard set interface implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSetInterface(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard sync frame implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSyncFrame(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +usb_status_t USB_HostCh9RequestCommon(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + uint8_t *buffer, + uint32_t bufferLen) +{ + /* initialize transfer */ + transfer->setupPacket.wLength = USB_SHORT_TO_LITTLE_ENDIAN(bufferLen); + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLen; + + if (USB_HostSendSetup(deviceInstance->hostHandle, deviceInstance->controlPipe, transfer) != + kStatus_USB_Success) /* send setup transfer */ + { +#ifdef HOST_ECHO + usb_echo("failt for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(deviceInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} + +usb_status_t USB_HostStandardGetStatus(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_get_status_param_t *statusParam; + + /* initialize transfer */ + statusParam = (usb_host_get_status_param_t *)param; + transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_STANDARD; + if (statusParam->requestType == kRequestDevice) + { + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_DEVICE; + } + else if (statusParam->requestType == kRequestInterface) + { + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + } + else + { + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + } + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(statusParam->interfaceOrEndpoint); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, statusParam->statusBuffer, 2); +} + +usb_status_t USB_HostStandardSetClearFeature(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_process_feature_param_t *featureParam; + + /* initialize transfer */ + featureParam = (usb_host_process_feature_param_t *)param; + if (featureParam->requestType == kRequestDevice) + { + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_DEVICE; + } + else if (featureParam->requestType == kRequestInterface) + { + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + } + else + { + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + } + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(featureParam->featureSelector); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(featureParam->interfaceOrEndpoint); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0); +} + +usb_status_t USB_HostStandardSetAddress(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + uint8_t address; + + /* initialize transfer */ + address = *(uint8_t *)param; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(address); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0); +} + +usb_status_t USB_HostStandardSetGetDescriptor(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_process_descriptor_param_t *descriptorParam; + + /* initialize transfer */ + descriptorParam = (usb_host_process_descriptor_param_t *)param; + transfer->setupPacket.wValue = + ((uint16_t)((uint16_t)descriptorParam->descriptorType << 8) | descriptorParam->descriptorIndex); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(descriptorParam->languageId); + return USB_HostCh9RequestCommon(deviceInstance, transfer, descriptorParam->descriptorBuffer, + descriptorParam->descriptorLength); +} + +usb_status_t USB_HostStandardGetInterface(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_get_interface_param_t *interfaceParam; + + /* initialize transfer */ + interfaceParam = (usb_host_get_interface_param_t *)param; + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(interfaceParam->interface); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, interfaceParam->alternateInterfaceBuffer, 1); +} + +usb_status_t USB_HostStandardSetInterface(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_set_interface_param_t *setParam; + + /* initialize transfer */ + setParam = (usb_host_set_interface_param_t *)param; + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(setParam->interface); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(setParam->alternateSetting); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0); +} + +usb_status_t USB_HostStandardSyncFrame(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_synch_frame_param_t *frameParam; + + /* initialize transfer */ + frameParam = (usb_host_synch_frame_param_t *)param; + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(frameParam->endpoint); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, frameParam->frameNumberBuffer, 2); +} + +usb_status_t USB_HostRequestControl(usb_device_handle deviceHandle, + uint8_t usbRequest, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_status_t status = kStatus_USB_Error; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* reset transfer fields */ + transfer->setupPacket.bmRequestType = 0x00; + transfer->setupPacket.bRequest = usbRequest; + transfer->setupPacket.wIndex = 0; + transfer->setupPacket.wLength = 0; + transfer->setupPacket.wValue = 0; + + switch (usbRequest) + { + case USB_REQUEST_STANDARD_GET_STATUS: /* standard get status request */ + status = USB_HostStandardGetStatus(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_CLEAR_FEATURE: /* standard clear status request */ + case USB_REQUEST_STANDARD_SET_FEATURE: /* standard set feature request */ + status = USB_HostStandardSetClearFeature(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_SET_ADDRESS: /* standard set address request */ + status = USB_HostStandardSetAddress(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_GET_DESCRIPTOR: /* standard get descriptor request */ + case USB_REQUEST_STANDARD_SET_DESCRIPTOR: /* standard set descriptor request */ + if (usbRequest == USB_REQUEST_STANDARD_GET_DESCRIPTOR) + { + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + } + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_GET_CONFIGURATION: /* standard get configuration descriptor request */ + transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + status = + USB_HostCh9RequestCommon((usb_host_device_instance_t *)deviceHandle, transfer, (uint8_t *)param, 1); + break; + + case USB_REQUEST_STANDARD_SET_CONFIGURATION: /* standard set configuration request */ + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(*((uint8_t *)param)); + status = USB_HostCh9RequestCommon((usb_host_device_instance_t *)deviceHandle, transfer, NULL, 0); + break; + + case USB_REQUEST_STANDARD_GET_INTERFACE: /* standard get interface request */ + status = USB_HostStandardGetInterface(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_SET_INTERFACE: /* standard set interface request */ + status = USB_HostStandardSetInterface(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_SYNCH_FRAME: /* standard synch frame request */ + status = USB_HostStandardSyncFrame(deviceInstance, transfer, param); + break; + + default: + break; + } + + return status; +} diff --git a/usb_1.1.0/host/usb_host_framework.h b/usb_1.1.0/host/usb_host_framework.h new file mode 100644 index 0000000..aeca251 --- /dev/null +++ b/usb_1.1.0/host/usb_host_framework.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_HOST_CH9_H_ +#define _USB_HOST_CH9_H_ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @addtogroup usb_host_drv + * @{ + */ + +/*! @brief Request type */ +typedef enum _usb_host_request_type +{ + kRequestDevice = 1U, /*!< Control request object is device */ + kRequestInterface, /*!< Control request object is interface */ + kRequestEndpoint, /*!< Control request object is endpoint */ +} usb_host_request_type_t; + +/*! @brief For USB_REQUEST_STANDARD_CLEAR_FEATURE and USB_REQUEST_STANDARD_SET_FEATURE */ +typedef struct _usb_host_process_feature_param +{ + uint8_t requestType; /*!< See the #usb_host_request_type_t */ + uint8_t featureSelector; /*!< Set/cleared feature */ + uint8_t interfaceOrEndpoint; /*!< Interface or end pointer */ +} usb_host_process_feature_param_t; + +/*! @brief For USB_REQUEST_STANDARD_GET_DESCRIPTOR and USB_REQUEST_STANDARD_SET_DESCRIPTOR */ +typedef struct _usb_host_process_descriptor_param +{ + uint8_t descriptorType; /*!< See the usb_spec.h, such as the USB_DESCRIPTOR_TYPE_DEVICE */ + uint8_t descriptorIndex; /*!< The descriptor index is used to select a specific descriptor (only for configuration + and string descriptors) when several descriptors of the same type are implemented in a + device */ + uint8_t languageId; /*!< It specifies the language ID for string descriptors or is reset to zero for other + descriptors */ + uint8_t *descriptorBuffer; /*!< Buffer pointer */ + uint16_t descriptorLength; /*!< Buffer data length */ +} usb_host_process_descriptor_param_t; + +/*! @brief For USB_REQUEST_STANDARD_GET_INTERFACE */ +typedef struct _usb_host_get_interface_param +{ + uint8_t interface; /*!< Interface number */ + uint8_t *alternateInterfaceBuffer; /*!< Save the transfer result */ +} usb_host_get_interface_param_t; + +/*! @brief For USB_REQUEST_STANDARD_GET_STATUS */ +typedef struct _usb_host_get_status_param +{ + uint8_t requestType; /*!< See the #usb_host_request_type_t */ + uint8_t interfaceOrEndpoint; /*!< Interface number or the end pointer number */ + uint8_t *statusBuffer; /*!< Save the transfer result */ +} usb_host_get_status_param_t; + +/*! @brief For USB_REQUEST_STANDARD_SET_INTERFACE */ +typedef struct _usb_host_set_interface_param +{ + uint8_t alternateSetting; /*!< Alternate setting value */ + uint8_t interface; /*!< Interface number */ +} usb_host_set_interface_param_t; + +/*! @brief For USB_REQUEST_STANDARD_SYNCH_FRAME */ +typedef struct _usb_host_synch_frame_param +{ + uint8_t endpoint; /*!< Endpoint number */ + uint8_t *frameNumberBuffer; /*!< Frame number data buffer */ +} usb_host_synch_frame_param_t; + +/*! @}*/ + +/******************************************************************************* + * API + ******************************************************************************/ + +#endif /* _USB_HOST_CH9_H_ */ diff --git a/usb_1.1.0/host/usb_host_hci.c b/usb_1.1.0/host/usb_host_hci.c new file mode 100644 index 0000000..f50af20 --- /dev/null +++ b/usb_1.1.0/host/usb_host_hci.c @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#include "usb_host.h" +#include "usb_host_hci.h" +#include "usb_host_devices.h" +#include "fsl_device_registers.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +extern uint32_t USB_HostHubGetTotalThinkTime(uint8_t parentHubNo); + +/*! + * @brief get the idle host instance. + * + * @return host instance pointer. + */ +static usb_host_instance_t *USB_HostGetInstance(void); + +/*! + * @brief release host instance. + * + * @param hostInstance host instance pointer. + */ +static void USB_HostReleaseInstance(usb_host_instance_t *hostInstance); + +/*! + * @brief get the khci/ehci interface. + * + * @param controllerId controller id. + * @param controllerTable return controller interface structure. + */ +static void USB_HostGetControllerInterface(uint8_t controllerId, + const usb_host_controller_interface_t **controllerTable); + +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) +extern void USB_HostEhciTestModeInit(usb_device_handle devHandle); +#endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */ +#endif /* USB_HOST_CONFIG_EHCI */ + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief USB host instance resource */ +usb_host_instance_t g_UsbHostInstance[USB_HOST_CONFIG_MAX_HOST]; + +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) +#include "usb_host_ehci.h" +static const usb_host_controller_interface_t s_EhciInterface = \ +{ + USB_HostEhciCreate, USB_HostEhciDestory, USB_HostEhciOpenPipe, USB_HostEhciClosePipe, + USB_HostEhciWritePipe, USB_HostEhciReadpipe, USB_HostEhciIoctl, +}; +#endif /* USB_HOST_CONFIG_EHCI */ + +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) +#include "usb_host_khci.h" +static const usb_host_controller_interface_t s_KhciInterface = \ +{ + USB_HostKhciCreate, USB_HostKhciDestory, USB_HostKhciOpenPipe, USB_HostKhciClosePipe, + USB_HostKhciWritePipe, USB_HostKhciReadpipe, USB_HostKciIoctl, +}; +#endif /* USB_HOST_CONFIG_KHCI */ + +/******************************************************************************* + * Code + ******************************************************************************/ + +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) +/*FUNCTION*---------------------------------------------------------------- +* +* Function Name : usb_test_mode_init +* Returned Value : None +* Comments : +* This function is called by common class to initialize the class driver. It +* is called in response to a select interface call by application +* +*END*--------------------------------------------------------------------*/ +usb_status_t USB_HostTestModeInit(usb_device_handle deviceHandle) +{ +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; +#endif + uint32_t productId; + uint32_t vendorId; + + usb_echo("usb host test init\r\n"); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDevicePID, &productId); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceVID, &vendorId); + usb_echo(" vendor id :0x%x product id:0x%x \r\n", vendorId, productId); + + if ((productId != 0x0200U) && (productId != 0x0101) && (productId != 0x0102) && (productId != 0x0103) && + (productId != 0x0104) && (productId != 0x0105) && (productId != 0x0106) && (productId != 0x0107) && + (productId != 0x0108)) + { + usb_echo("Unsupported Device\r\n"); + } + + if (productId == 0x0200U) + { + usb_echo("PET test device attached\r\n"); + } + else + { +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) + if (hostInstance->controllerTable == &s_EhciInterface) + { + USB_HostEhciTestModeInit(deviceHandle); + } +#endif + } + + return kStatus_USB_Success; +} +#endif + +static usb_host_instance_t *USB_HostGetInstance(void) +{ + uint8_t i = 0; + USB_OSA_SR_ALLOC(); + USB_OSA_ENTER_CRITICAL(); + for (; i < USB_HOST_CONFIG_MAX_HOST; i++) + { + if (g_UsbHostInstance[i].occupied != 1) + { + uint8_t *buffer = (uint8_t *)&g_UsbHostInstance[i]; + for (uint32_t j = 0U; j < sizeof(usb_host_instance_t); j++) + { + buffer[j] = 0x00U; + } + g_UsbHostInstance[i].occupied = 1; + USB_OSA_EXIT_CRITICAL(); + return &g_UsbHostInstance[i]; + } + } + USB_OSA_EXIT_CRITICAL(); + return NULL; +} + +static void USB_HostReleaseInstance(usb_host_instance_t *hostInstance) +{ + USB_OSA_SR_ALLOC(); + USB_OSA_ENTER_CRITICAL(); + hostInstance->occupied = 0; + USB_OSA_EXIT_CRITICAL(); +} + +static void USB_HostGetControllerInterface(uint8_t controllerId, + const usb_host_controller_interface_t **controllerTable) +{ +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) + if (controllerId == kUSB_ControllerKhci0) + { + *controllerTable = &s_KhciInterface; + } +#endif /* USB_HOST_CONFIG_KHCI */ + +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) + if (controllerId == kUSB_ControllerEhci0) + { + *controllerTable = &s_EhciInterface; + } +#endif /* USB_HOST_CONFIG_EHCI */ +} + +usb_status_t USB_HostInit(uint8_t controllerId, usb_host_handle *hostHandle, host_callback_t callbackFn) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = NULL; + usb_host_transfer_t *transferPrev = NULL; + uint8_t i = 0; + + hostInstance = USB_HostGetInstance(); /* get one host instance */ + if (hostInstance == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* get khci/ehci API table */ + USB_HostGetControllerInterface(controllerId, &hostInstance->controllerTable); + if (hostInstance->controllerTable == NULL) + { + USB_HostReleaseInstance(hostInstance); + return kStatus_USB_ControllerNotFound; + } + + /* judge the controller interface one time at here */ + if ((hostInstance->controllerTable->controllerCreate == NULL) || + (hostInstance->controllerTable->controllerDestory == NULL) || + (hostInstance->controllerTable->controllerOpenPipe == NULL) || + (hostInstance->controllerTable->controllerClosePipe == NULL) || + (hostInstance->controllerTable->controllerWritePipe == NULL) || + (hostInstance->controllerTable->controllerReadPipe == NULL) || + (hostInstance->controllerTable->controllerIoctl == NULL)) + { + return kStatus_USB_Error; + } + + /* HOST instance init*/ + hostInstance->controllerId = controllerId; + hostInstance->deviceCallback = callbackFn; + hostInstance->deviceList = NULL; + if (kStatus_USB_OSA_Success != USB_OsaMutexCreate(&hostInstance->hostMutex)) + { + USB_HostReleaseInstance(hostInstance); +#ifdef HOST_ECHO + usb_echo("host init: create host mutex fail\r\n"); +#endif + return kStatus_USB_Error; + } + + /* initialize transfer list */ + + hostInstance->transferHead = &hostInstance->transferList[0]; + transferPrev = hostInstance->transferHead; + for (i = 1; i < USB_HOST_CONFIG_MAX_TRANSFERS; ++i) + { + transferPrev->next = &hostInstance->transferList[i]; + transferPrev = transferPrev->next; + } + + /* controller create */ + status = + hostInstance->controllerTable->controllerCreate(controllerId, hostInstance, &(hostInstance->controllerHandle)); + if ((status != kStatus_USB_Success) || (hostInstance->controllerHandle == NULL)) + { + USB_OsaMutexDestroy(hostInstance->hostMutex); + USB_HostReleaseInstance(hostInstance); +#ifdef HOST_ECHO + usb_echo("host init: controller init fail\r\n"); +#endif + return kStatus_USB_Error; + } + + *hostHandle = hostInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostDeinit(usb_host_handle hostHandle) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *deviceInstance = NULL; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* device list detach */ + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + while (deviceInstance != NULL) + { + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + USB_HostDetachDeviceInternal(hostHandle, deviceInstance); + } + + /* controller instance destory */ + status = hostInstance->controllerTable->controllerDestory(hostInstance->controllerHandle); + hostInstance->controllerHandle = NULL; + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host controller destory fail\r\n"); +#endif + } + + /* resource release */ + if (hostInstance->hostMutex) + { + USB_OsaMutexDestroy(hostInstance->hostMutex); + hostInstance->hostMutex = NULL; + } + USB_HostReleaseInstance(hostInstance); + + return status; +} + +usb_status_t USB_HostOpenPipe(usb_host_handle hostHandle, + usb_host_pipe_handle *pipeHandle, + usb_host_pipe_init_t *pipeInit) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeInit == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* call controller open pipe interface */ + status = hostInstance->controllerTable->controllerOpenPipe(hostInstance->controllerHandle, pipeHandle, pipeInit); + + return status; +} + +usb_status_t USB_HostClosePipe(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* call controller close pipe interface */ + status = hostInstance->controllerTable->controllerClosePipe(hostInstance->controllerHandle, pipeHandle); + + return status; +} + +usb_status_t USB_HostSend(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle, usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeHandle == NULL) || (transfer == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* initialize transfer */ + transfer->transferSofar = 0; + transfer->direction = USB_OUT; + + USB_HostLock(); /* This api can be called by host task and app task */ +/* keep this code: in normal situation application will guarantee the device is attached when call send/receive function + */ +#if 0 + if ((USB_HostValidateDevice(pipe_ptr->deviceHandle) != kStatus_USB_Success) || (!(USB_HostGetDeviceAttachState(pipe_ptr->deviceHandle)))) + { + USB_HostUnlock(); + return status; + } +#endif +/* call controller write pipe interface */ +#if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + if (transfer->transferLength > 0) + { + USB_CacheFlushLines((void *)transfer->transferBuffer, transfer->transferLength); + } +#endif + status = hostInstance->controllerTable->controllerWritePipe(hostInstance->controllerHandle, pipeHandle, transfer); + + USB_HostUnlock(); + return status; +} + +usb_status_t USB_HostSendSetup(usb_host_handle hostHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeHandle == NULL) || (transfer == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* initialize transfer */ + transfer->transferSofar = 0; + transfer->next = NULL; + transfer->setupStatus = 0; + if ((transfer->setupPacket.bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_IN) + { + transfer->direction = USB_IN; + } + else + { + transfer->direction = USB_OUT; + } + + USB_HostLock(); /* This API can be called by host task and application task */ +/* keep this code: in normal situation application will guarantee the device is attached when call send/receive function + */ +#if 0 + if ((USB_HostValidateDevice(pipe_ptr->deviceHandle) != kStatus_USB_Success) || (!(USB_HostGetDeviceAttachState(pipe_ptr->deviceHandle)))) + { + USB_HostUnlock(); + return status; + } +#endif +/* call controller write pipe interface */ +#if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + if (transfer->transferLength > 0) + { + USB_CacheFlushLines((void *)transfer->transferBuffer, transfer->transferLength); + } +#endif + status = hostInstance->controllerTable->controllerWritePipe(hostInstance->controllerHandle, pipeHandle, transfer); + + USB_HostUnlock(); + return status; +} + +usb_status_t USB_HostRecv(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle, usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeHandle == NULL) || (transfer == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* initialize transfer */ + transfer->transferSofar = 0; + transfer->direction = USB_IN; + + USB_HostLock(); /* This API can be called by host task and application task */ +/* keep this code: in normal situation application will guarantee the device is attached when call send/receive function + */ +#if 0 + if ((USB_HostValidateDevice(pipe_ptr->deviceHandle) != kStatus_USB_Success) || (!(USB_HostGetDeviceAttachState(pipe_ptr->deviceHandle)))) + { + USB_HostUnlock(); + return status; + } +#endif + +#if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + if (transfer->transferLength > 0) + { + USB_CacheInvalidateLines((void *)transfer->transferBuffer, transfer->transferLength); + } +#endif + status = hostInstance->controllerTable->controllerReadPipe(hostInstance->controllerHandle, pipeHandle, transfer); + + USB_HostUnlock(); + return status; +} + +usb_status_t USB_HostCancelTransfer(usb_host_handle hostHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_cancel_param_t cancelParam; + + if ((hostHandle == NULL) || (pipeHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* initialize cancel parameter */ + cancelParam.pipeHandle = pipeHandle; + cancelParam.transfer = transfer; + + /* USB_HostLock(); This api can be called by host task and app task */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostCancelTransfer, + &cancelParam); + /* USB_HostUnlock(); */ + + return status; +} + +usb_status_t USB_HostMallocTransfer(usb_host_handle hostHandle, usb_host_transfer_t **transfer) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (transfer == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* get one from the transfer_head */ + USB_HostLock(); + if (hostInstance->transferHead != NULL) + { + *transfer = hostInstance->transferHead; + hostInstance->transferHead = hostInstance->transferHead->next; + USB_HostUnlock(); + return kStatus_USB_Success; + } + else + { + *transfer = NULL; + USB_HostUnlock(); + return kStatus_USB_Error; + } +} + +usb_status_t USB_HostFreeTransfer(usb_host_handle hostHandle, usb_host_transfer_t *transfer) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + if (transfer == NULL) + { + return kStatus_USB_Success; + } + + /* release one to the transfer_head */ + USB_HostLock(); + transfer->next = hostInstance->transferHead; + hostInstance->transferHead = transfer; + USB_HostUnlock(); + return kStatus_USB_Success; +} + +usb_status_t USB_HostHelperGetPeripheralInformation(usb_device_handle deviceHandle, + uint32_t infoCode, + uint32_t *infoValue) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + if ((deviceHandle == NULL) || (infoValue == NULL)) + { + return kStatus_USB_InvalidParameter; + } + + switch (infoCode) + { + case kUSB_HostGetDeviceAddress: /* device address */ + *infoValue = (uint32_t)deviceInstance->setAddress; + break; + + case kUSB_HostGetDeviceControlPipe: /* device control pipe */ + *infoValue = (uint32_t)deviceInstance->controlPipe; + break; + + case kUSB_HostGetHostHandle: /* device host handle */ + *infoValue = (uint32_t)deviceInstance->hostHandle; + break; + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + case kUSB_HostGetDeviceHubNumber: /* device hub address */ + *infoValue = (uint32_t)deviceInstance->hubNumber; + break; + + case kUSB_HostGetDevicePortNumber: /* device port no */ + *infoValue = (uint32_t)deviceInstance->portNumber; + break; + + case kUSB_HostGetDeviceLevel: /* device level */ + *infoValue = (uint32_t)deviceInstance->level; + break; + + case kUSB_HostGetDeviceHSHubNumber: /* device high-speed hub address */ + *infoValue = (uint32_t)deviceInstance->hsHubNumber; + break; + + case kUSB_HostGetDeviceHSHubPort: /* device high-speed hub port no */ + *infoValue = (uint32_t)deviceInstance->hsHubPort; + break; + + case kUSB_HostGetHubThinkTime: /* device hub think time */ + *infoValue = USB_HostHubGetTotalThinkTime(deviceInstance->hubNumber); + break; +#else + case kUSB_HostGetDeviceHubNumber: /* device hub address */ + case kUSB_HostGetDevicePortNumber: /* device port no */ + case kUSB_HostGetDeviceHSHubNumber: /* device high-speed hub address */ + case kUSB_HostGetDeviceHSHubPort: /* device high-speed hub port no */ + case kUSB_HostGetHubThinkTime: /* device hub think time */ + *infoValue = 0; + break; + case kUSB_HostGetDeviceLevel: /* device level */ + *infoValue = 1; + break; +#endif /* USB_HOST_CONFIG_HUB */ + + case kUSB_HostGetDeviceSpeed: /* device speed */ + *infoValue = (uint32_t)deviceInstance->speed; + break; + + case kUSB_HostGetDevicePID: /* device pid */ + *infoValue = (uint32_t)USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(deviceInstance->deviceDescriptor.idProduct); + break; + + case kUSB_HostGetDeviceVID: /* device vid */ + *infoValue = (uint32_t)USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(deviceInstance->deviceDescriptor.idVendor); + break; + + case kUSB_HostGetDeviceConfigIndex: /* device config index */ + *infoValue = (uint32_t)deviceInstance->configurationValue - 1U; + break; + + default: + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHelperParseAlternateSetting(usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + usb_host_interface_t *interface) +{ + uint32_t endPosition; + usb_descriptor_union_t *unionDes; + usb_host_ep_t *epParse; + + if (interfaceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (alternateSetting == 0) + { + return kStatus_USB_InvalidParameter; + } + + /* parse configuration descriptor */ + /* interface extend descriptor start */ + unionDes = (usb_descriptor_union_t *)(((usb_host_interface_t *)interfaceHandle)->interfaceExtension); + /* interface extend descriptor end */ + endPosition = (uint32_t)unionDes + ((usb_host_interface_t *)interfaceHandle)->interfaceExtensionLength; + + /* search for the alternate setting interface descritpor */ + while ((uint32_t)unionDes < endPosition) + { + if (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) + { + if (unionDes->interface.bAlternateSetting == alternateSetting) + { + break; + } + else + { + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + } + else + { + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + } + if ((uint32_t)unionDes >= endPosition) + { + return kStatus_USB_Error; + } + + /* initialize interface handle structure instance */ + interface->interfaceDesc = &unionDes->interface; + interface->alternateSettingNumber = 0; + interface->epCount = 0; + interface->interfaceExtension = NULL; + interface->interfaceExtensionLength = 0; + interface->interfaceIndex = unionDes->interface.bInterfaceNumber; + + /* search for endpoint descriptor start position */ + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + interface->interfaceExtension = (uint8_t *)unionDes; + while ((uint32_t)unionDes < endPosition) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { + interface->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + + /* parse endpoint descriptor */ + if (interface->interfaceDesc->bNumEndpoints != 0) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) || + (interface->interfaceDesc->bNumEndpoints > USB_HOST_CONFIG_INTERFACE_MAX_EP)) + { +#ifdef HOST_ECHO + usb_echo("interface descriptor error\n"); +#endif + return kStatus_USB_Error; + } + for (; interface->epCount < interface->interfaceDesc->bNumEndpoints; (interface->epCount)++) + { + if (((uint32_t)unionDes >= endPosition) || + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { +#ifdef HOST_ECHO + usb_echo("endpoint descriptor error\n"); +#endif + return kStatus_USB_Error; + } + epParse = (usb_host_ep_t *)&interface->epList[interface->epCount]; + epParse->epDesc = (usb_descriptor_endpoint_t *)unionDes; + epParse->epExtensionLength = 0; + epParse->epExtension = NULL; + interface->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + epParse->epExtension = (uint8_t *)unionDes; + while ((uint32_t)unionDes < endPosition) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)) + { + epParse->epExtensionLength += unionDes->common.bLength; + interface->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + } + } + + return kStatus_USB_Success; +} + +void USB_HostGetVersion(uint32_t *version) +{ + if (version) + { + *version = + (uint32_t)USB_MAKE_VERSION(USB_STACK_VERSION_MAJOR, USB_STACK_VERSION_MINOR, USB_STACK_VERSION_BUGFIX); + } +} diff --git a/usb_1.1.0/host/usb_host_hci.h b/usb_1.1.0/host/usb_host_hci.h new file mode 100644 index 0000000..f73c8f3 --- /dev/null +++ b/usb_1.1.0/host/usb_host_hci.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_HOST_HCI_H_ +#define _USB_HOST_HCI_H_ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief USB host lock */ +#define USB_HostLock() USB_OsaMutexLock(hostInstance->hostMutex) +/*! @brief USB host unlock */ +#define USB_HostUnlock() USB_OsaMutexUnlock(hostInstance->hostMutex) + +/*! + * @addtogroup usb_host_controller_driver + * @{ + */ + +/*! @brief USB host controller control code */ +typedef enum _usb_host_controller_control +{ + kUSB_HostCancelTransfer = 1U, /*!< Cancel transfer code */ + kUSB_HostBusControl, /*!< Bus control code */ + kUSB_HostGetFrameNumber, /*!< Get frame number code */ + kUSB_HostUpdateControlEndpointAddress, /*!< Update control endpoint address */ + kUSB_HostUpdateControlPacketSize, /*!< Update control endpoint maximum packet size */ +} usb_host_controller_control_t; + +/*! @brief USB host controller bus control code */ +typedef enum _usb_host_bus_control +{ + kUSB_HostBusReset = 1U, /*!< Reset bus */ + kUSB_HostBusRestart, /*!< Restart bus */ + kUSB_HostBusEnableAttach, /*!< Enable attach */ + kUSB_HostBusDisableAttach, /*!< Disable attach*/ +} usb_host_bus_control_t; + +/*! @brief USB host controller interface structure */ +typedef struct _usb_host_controller_interface +{ + usb_status_t (*controllerCreate)( + uint8_t controllerId, + usb_host_handle upperLayerHandle, + usb_host_controller_handle *controllerHandle); /*!< Create a controller instance function prototype*/ + usb_status_t (*controllerDestory)( + usb_host_controller_handle controllerHandle); /*!< Destroy a controller instance function prototype*/ + usb_status_t (*controllerOpenPipe)(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle *pipeHandle, + usb_host_pipe_init_t *pipeInit); /*!< Open a controller pipe function prototype*/ + usb_status_t (*controllerClosePipe)( + usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle); /*!< Close a controller pipe function prototype*/ + usb_status_t (*controllerWritePipe)(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); /*!< Write data to a pipe function prototype*/ + usb_status_t (*controllerReadPipe)(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); /*!< Read data from a pipe function prototype*/ + usb_status_t (*controllerIoctl)(usb_host_controller_handle controllerHandle, + uint32_t ioctlEvent, + void *ioctlParam); /*!< Control a controller function prototype*/ +} usb_host_controller_interface_t; + +/*! @}*/ + +/*! + * @addtogroup usb_host_drv + * @{ + */ + +/*! @brief USB host instance structure */ +typedef struct _usb_host_instance +{ + void *controllerHandle; /*!< The low level controller handle*/ + host_callback_t deviceCallback; /*!< Device attach/detach callback*/ + usb_osa_mutex_handle hostMutex; /*!< Host layer mutex*/ + usb_host_transfer_t transferList[USB_HOST_CONFIG_MAX_TRANSFERS]; /*!< Transfer resource*/ + usb_host_transfer_t *transferHead; /*!< Idle transfer head*/ + const usb_host_controller_interface_t *controllerTable; /*!< KHCI/EHCI interface*/ + void *deviceList; /*!< Device list*/ + uint8_t addressBitMap[16]; /*!< Used for address allocation. The first bit is the address 1, second bit is the + address 2*/ + uint8_t occupied; /*!< 0 - the instance is not occupied; 1 - the instance is occupied*/ + uint8_t controllerId; /*!< The controller ID*/ +} usb_host_instance_t; + +/*! @}*/ + +#endif /* _USB_HOST_HCI_H_ */ diff --git a/usb_1.1.0/host/usb_host_khci.c b/usb_1.1.0/host/usb_host_khci.c new file mode 100644 index 0000000..57af624 --- /dev/null +++ b/usb_1.1.0/host/usb_host_khci.c @@ -0,0 +1,1886 @@ +/* + * Copyright (c) 2015 -2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) +#include "usb_host.h" +#include "usb_host_hci.h" +#include "fsl_device_registers.h" +#include "usb_host_khci.h" +#include "usb_host_devices.h" + +/******************************************************************************* + * Variables + ******************************************************************************/ +#if defined(__ICCCF__) || defined(__ICCARM__) +#pragma segment = "USB_BDT_Z" +#pragma data_alignment = 512 +__no_init static uint8_t bdt[512] @"USB_BDT_Z"; +#elif defined(__GNUC__) +__attribute__((aligned(512))) static uint8_t bdt[512]; +#elif defined(__CC_ARM) +__align(512) uint8_t bdt[512]; +#else +#error Unsupported compiler, please use IAR, Keil or arm gcc compiler and rebuild the project. +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ +/*! + * @brief get the 2 power value of uint32_t. + * + * @param data input uint32_t value. + * + */ +static uint32_t _USB_HostKhciGetRoundUpPow2(uint32_t data) +{ + uint8_t i = 0U; + + if ((data == 1U) || (data == 0U)) + { + return data; + } + while (data != 1U) + { + data = data >> 1U; + i++; + } + return 1U << (i); +} + +/*! + * @brief get the current host khci frame number count. + * + * @param handle Pointer of the host KHCI state structure. + * + * @return current frame number count. + */ +static uint32_t _USB_HostKhciGetFrameCount(usb_host_controller_handle handle) +{ + uint32_t tempFrameCount; + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle; + + tempFrameCount = usbHostPointer->usbRegBase->FRMNUMH; + + return (uint16_t)((tempFrameCount << 8U) | (usbHostPointer->usbRegBase->FRMNUML)); +} + +/*! + * @brief get the total of host khci frame number count. + * + * @param usbHostPointer Pointer of the host KHCI state structure. + * + * @return total of frame number count. + */ +static uint32_t _USB_HostKhciGetFrameCountSum(usb_khci_host_state_struct_t *usbHostPointer) +{ + static uint32_t totalFrameNumber = 0U; + static uint16_t oldFrameNumber = 0U; + uint16_t frameNumber = 0xFFFFU; + + frameNumber = _USB_HostKhciGetFrameCount((usb_host_controller_handle)usbHostPointer); + + if (frameNumber < oldFrameNumber) + { + totalFrameNumber += 2048U; + } + + oldFrameNumber = frameNumber; + + return (frameNumber + totalFrameNumber); +} + +/*! + * @brief host khci delay. + * + * @param usbHostPointer Pointer of the host KHCI state structure. + * @param ms milliseconds. + * + */ +static void _USB_HostKhciDelay(usb_khci_host_state_struct_t *usbHostPointer, uint32_t ms) +{ + uint32_t sofStart; + uint32_t sofEnd; + sofStart = _USB_HostKhciGetFrameCountSum(usbHostPointer); + + do + { + sofEnd = _USB_HostKhciGetFrameCountSum(usbHostPointer); + } while ((sofEnd - sofStart) < ms); +} + +/*! + * @brief Device KHCI isr function. + * + * The function is KHCI interrupt service routine. + * + * @param hostHandle The host handle. + */ +void USB_HostKhciIsrFunction(void *hostHandle) +{ + usb_khci_host_state_struct_t *usbHostPointer; + + uint8_t status; + + if (hostHandle == NULL) + { + return; + } + + usbHostPointer = (usb_khci_host_state_struct_t *)((usb_host_instance_t *)hostHandle)->controllerHandle; + + while (1U) + { + status = (uint8_t)((usbHostPointer->usbRegBase->ISTAT)); + status &= (uint8_t)(usbHostPointer->usbRegBase->INTEN); + + if (!status) + { + break; + } + + usbHostPointer->usbRegBase->ISTAT = status; + + if (status & USB_ISTAT_SOFTOK_MASK) + { + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_SOF_TOK); + } + + if (status & USB_ISTAT_ATTACH_MASK) + { + usbHostPointer->usbRegBase->INTEN &= (~USB_INTEN_ATTACHEN_MASK); + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_ATTACH); + } + + if (status & USB_ISTAT_TOKDNE_MASK) + { + /* atom transaction done - token done */ + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_TOK_DONE); + } + + if (status & USB_ISTAT_USBRST_MASK) + { + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_RESET); + } + } +} + +/*! + * @brief Handle khci host controller attach event. + * + * The function is used to handle attach event when a device is attached to khci host controller, the process is detect + * the line state, do bus reset, and call device attached function. + * + * @param usbHostPointer Pointer of the host KHCI state structure. + * + */ +static void _USB_HostKhciAttach(usb_khci_host_state_struct_t *usbHostPointer) +{ + uint8_t speed; + uint8_t temp; + usb_device_handle deviceHandle; + uint8_t index = 0U; + + usbHostPointer->usbRegBase->CTL |= USB_CTL_ODDRST_MASK; + usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK; + usbHostPointer->usbRegBase->ADDR = ((usbHostPointer->usbRegBase->ADDR & (~USB_ADDR_ADDR_MASK)) | + ((((0U) << USB_ADDR_ADDR_SHIFT) & USB_ADDR_ADDR_MASK))); + usbHostPointer->usbRegBase->ADDR &= (~USB_ADDR_LSEN_MASK); + + /* here wait for about 120ms to check line state */ + for (volatile uint32_t i = 0U; i < 2000000U; i++) + { + __ASM("nop"); + } + + do + { + temp = ((usbHostPointer->usbRegBase->CTL) & USB_CTL_JSTATE_MASK) ? 0U : 1U; + for (volatile uint32_t i = 0U; i < 100000U; i++) + { + __ASM("nop"); + } + speed = ((usbHostPointer->usbRegBase->CTL) & USB_CTL_JSTATE_MASK) ? 0U : 1U; + index++; + } while ((temp != speed) && (index < USB_KHCI_MAX_SPEED_DETECTION_COUNT)); + + if (temp != speed) + { +#ifdef HOST_ECHO + usb_echo("speed not match!\n"); +#endif + usbHostPointer->usbRegBase->INTEN |= USB_INTEN_ATTACHEN_MASK; + return; + } + if (((usbHostPointer->usbRegBase->CTL) & USB_CTL_SE0_MASK) == USB_CTL_SE0_MASK) + { + usbHostPointer->usbRegBase->INTEN |= USB_INTEN_ATTACHEN_MASK; + return; + } + + if (speed == USB_SPEED_FULL) + { + usbHostPointer->usbRegBase->ADDR &= (~USB_ADDR_LSEN_MASK); + } + else if (speed == USB_SPEED_LOW) + { + usbHostPointer->usbRegBase->ENDPOINT[0U].ENDPT = USB_ENDPT_HOSTWOHUB_MASK; + usbHostPointer->usbRegBase->ADDR |= USB_ADDR_LSEN_MASK; + } + else + { + } + + usbHostPointer->usbRegBase->CTL |= USB_CTL_USBENSOFEN_MASK; + + usbHostPointer->usbRegBase->ISTAT = 0xffU; + usbHostPointer->usbRegBase->INTEN &= (~(USB_INTEN_TOKDNEEN_MASK | USB_INTEN_USBRSTEN_MASK)); + + /* Do USB bus reset here */ + usbHostPointer->usbRegBase->CTL |= USB_CTL_RESET_MASK; + _USB_HostKhciDelay(usbHostPointer, 30U); + usbHostPointer->usbRegBase->CTL &= (~USB_CTL_RESET_MASK); + +#ifdef USBCFG_OTG + _USB_HostKhciDelay(usbHostPointer, 30U); +#else + _USB_HostKhciDelay(usbHostPointer, 100U); +#endif + usbHostPointer->usbRegBase->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK; + usbHostPointer->usbRegBase->INTEN |= (USB_INTEN_TOKDNEEN_MASK | USB_INTEN_USBRSTEN_MASK); + usbHostPointer->deviceAttached++; + USB_OsaEventClear(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_TOK_DONE); + USB_HostAttachDevice(usbHostPointer->hostHandle, speed, 0U, 0U, 1, &deviceHandle); + + usbHostPointer->txBd = 0U; + usbHostPointer->rxBd = 0U; +} + +/*! + * @brief Handle khci host controller bus reset event. + * + * The function is used to handle khci host controller bus reset event, reset event also is used for khci detached + * detecction. + * + * @param usbHostPointer Pointer of the host KHCI state structure. + * + */ +static void _USB_HostKhciReset(usb_khci_host_state_struct_t *usbHostPointer) +{ + volatile uint32_t i = 0xfffU; + /* clear attach flag */ + usbHostPointer->usbRegBase->ISTAT = USB_ISTAT_ATTACH_MASK; + while (i--) + { + __ASM("nop"); + } + /* Test the presence of USB device */ + if ((usbHostPointer->usbRegBase->ISTAT) & USB_ISTAT_ATTACH_MASK) + { + /* device attached, so really normal reset was performed */ + usbHostPointer->usbRegBase->INTEN |= USB_ISTAT_USBRST_MASK; + usbHostPointer->usbRegBase->ADDR = ((usbHostPointer->usbRegBase->ADDR & (~USB_ADDR_ADDR_MASK)) | + ((((0U) << USB_ADDR_ADDR_SHIFT) & USB_ADDR_ADDR_MASK))); + usbHostPointer->usbRegBase->ENDPOINT[0U].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK; + } + else + { + /* device was detached,, notify about detach */ + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_DETACH); + } +} + +/*! + * @brief Handle khci host controller bus detach event. + * + * @param usbHostPointer Pointer of the host KHCI state structure. + * + */ +static void _USB_HostKhciDetach(usb_khci_host_state_struct_t *usbHostPointer) +{ + if (usbHostPointer->deviceAttached > 0) + { + usbHostPointer->deviceAttached--; + } + else + { + return; + } + USB_HostDetachDevice(usbHostPointer->hostHandle, 0U, 0U); + /* Enable USB week pull-downs, useful for detecting detach (effectively bus discharge) */ + usbHostPointer->usbRegBase->USBCTRL |= USB_USBCTRL_PDE_MASK; + /* Remove suspend state */ + usbHostPointer->usbRegBase->USBCTRL &= (~USB_USBCTRL_SUSP_MASK); + + usbHostPointer->usbRegBase->CTL |= USB_CTL_ODDRST_MASK; + + usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK; + + usbHostPointer->txBd = 0U; + usbHostPointer->rxBd = 0U; + + usbHostPointer->usbRegBase->ISTAT = 0xffU; + USB_OsaEventClear(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG); +} + +/*! + * @brief get a right transfer from periodic and async list. + * + * This function return a right transfer for khci atom transfer, the function implemented simple USB transaction + * dispatch algorithm. + * + * @param handle Pointer of the host khci controller handle. + * @param transfer Pointer of pointer of transfer node struct, will get the a tr quest pointer if operator + * success, will get NULL pointer if fail. + * + */ +static void _USB_HostKhciGetRightTrRequest(usb_host_controller_handle handle, usb_host_transfer_t **transfer) +{ + usb_host_transfer_t *tempTransfer; + usb_host_transfer_t *firstTransfer; + usb_host_transfer_t *prevTtransfer; + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle; + uint32_t frame_number; + + if (handle == NULL) + { + *transfer = NULL; + return; + } + + USB_HostKhciLock(); + /* First check whether periodic list is active, will get transfer from periodic list */ + if (usbHostPointer->periodicListAvtive) + { + prevTtransfer = tempTransfer = usbHostPointer->periodicListPointer; + frame_number = _USB_HostKhciGetFrameCount(usbHostPointer); + /* Will get the transfer if the pipe frame count and current frame count is equal */ + while (tempTransfer != NULL) + { + if ((tempTransfer->transferPipe->currentCount != frame_number) && + (frame_number % tempTransfer->transferPipe->interval == 0U) && + (tempTransfer->transferPipe->pipeType == USB_ENDPOINT_INTERRUPT)) + { + tempTransfer->transferPipe->currentCount = frame_number; + *transfer = firstTransfer = tempTransfer; + /* Will move the selected interrupt transfer to end of the periodic list */ + if ((tempTransfer->transferPipe->pipeType == USB_ENDPOINT_INTERRUPT) && (tempTransfer->next != NULL)) + { + if (tempTransfer == usbHostPointer->periodicListPointer) + { + usbHostPointer->periodicListPointer = tempTransfer->next; + } + else + { + prevTtransfer->next = tempTransfer->next; + } + while (tempTransfer != NULL) + { + prevTtransfer = tempTransfer; + tempTransfer = tempTransfer->next; + } + prevTtransfer->next = firstTransfer; + firstTransfer->next = NULL; + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG); + } + USB_HostKhciUnlock(); + return; + } + prevTtransfer = tempTransfer; + tempTransfer = tempTransfer->next; + } + } + /* will get the first transfer from active list if no active transfer in async list */ + if (usbHostPointer->asyncListAvtive) + { + firstTransfer = tempTransfer = usbHostPointer->asyncListPointer; + *transfer = firstTransfer; + + if (tempTransfer->next != NULL) + { + usbHostPointer->asyncListPointer = tempTransfer->next; + } + else + { + USB_HostKhciUnlock(); + return; + } + tempTransfer = tempTransfer->next; + while (tempTransfer != NULL) + { + prevTtransfer = tempTransfer; + tempTransfer = tempTransfer->next; + } + prevTtransfer->next = firstTransfer; + firstTransfer->next = NULL; + } + USB_HostKhciUnlock(); +} + +/*! + * @brief unlink transfer from periodic and async khci transfer list. + * + * @param handle Pointer of the host khci controller handle. + * @param transfer Pointer of transfer node struct, which will be unlink from transfer list. + * + */ +static void _USB_HostKhciUnlinkTrRequestFromList(usb_host_controller_handle handle, usb_host_transfer_t *transfer) +{ + usb_host_transfer_t *temptr = NULL; + usb_host_transfer_t *pretr = NULL; + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle; + + if ((handle == NULL) || (transfer == NULL)) + { + return; + } + + USB_HostKhciLock(); + if (usbHostPointer->asyncListAvtive == 1U) + { + temptr = usbHostPointer->asyncListPointer; + if (transfer == temptr) + { + usbHostPointer->asyncListPointer = temptr->next; + } + else + { + while (temptr != NULL) + { + pretr = temptr; + temptr = temptr->next; + if (transfer == temptr) + { + pretr->next = temptr->next; + break; + } + } + } + if (usbHostPointer->asyncListPointer == NULL) + { + usbHostPointer->asyncListAvtive = 0U; + } + } + if (usbHostPointer->periodicListAvtive == 1U) + { + temptr = usbHostPointer->periodicListPointer; + if (transfer == temptr) + { + usbHostPointer->periodicListPointer = temptr->next; + } + else + { + while (temptr != NULL) + { + pretr = temptr; + temptr = temptr->next; + if (transfer == temptr) + { + pretr->next = temptr->next; + break; + } + } + } + if (usbHostPointer->periodicListPointer == NULL) + { + usbHostPointer->periodicListAvtive = 0U; + } + } + USB_HostKhciUnlock(); +} + +/*! + * @brief link transfer to periodic and async khci transfer list. + * + * @param handle Pointer of the host khci controller handle. + * @param transfer Pointer of transfer node struct, which will be link to transfer list. + * + */ +static usb_status_t _USB_HostKhciLinkTrRequestToList(usb_host_controller_handle controllerHandle, + usb_host_transfer_t *transfer) +{ + usb_host_transfer_t *temptransfer; + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle; + + if ((transfer == NULL)) + { + return kStatus_USB_InvalidParameter; + } + + USB_HostKhciLock(); + if ((transfer->transferPipe->pipeType == USB_ENDPOINT_ISOCHRONOUS) || + (transfer->transferPipe->pipeType == USB_ENDPOINT_INTERRUPT)) + { + if (usbHostPointer->periodicListAvtive == 0U) + { + usbHostPointer->periodicListPointer = transfer; + transfer->next = NULL; + usbHostPointer->periodicListAvtive = 1U; + } + else + { + temptransfer = usbHostPointer->periodicListPointer; + while (temptransfer->next != NULL) + { + temptransfer = temptransfer->next; + } + temptransfer->next = transfer; + transfer->next = NULL; + } + } + else if ((transfer->transferPipe->pipeType == USB_ENDPOINT_CONTROL) || + (transfer->transferPipe->pipeType == USB_ENDPOINT_BULK)) + { + if (usbHostPointer->asyncListAvtive == 0U) + { + usbHostPointer->asyncListPointer = transfer; + transfer->next = NULL; + usbHostPointer->asyncListAvtive = 1U; + } + else + { + temptransfer = usbHostPointer->asyncListPointer; + while (temptransfer->next != NULL) + { + temptransfer = temptransfer->next; + } + temptransfer->next = transfer; + transfer->next = NULL; + } + } + else + { + } + USB_HostKhciUnlock(); + return kStatus_USB_Success; +} + +/*! + * @brief khci process tranfer callback function. + * + * @param controllerHandle Pointer of the host khci controller handle. + * @param transfer Pointer of transfer , which will be process callback. + * @param err The return value of transfer. + * + */ +static void _USB_HostKhciProcessTrCallback(usb_host_controller_handle controllerHandle, + usb_host_transfer_t *transfer, + int32_t err) +{ + usb_status_t status = kStatus_USB_Success; + + if (err == USB_KHCI_ATOM_TR_STALL) + { + status = kStatus_USB_TransferStall; + } + else if ((err == USB_KHCI_ATOM_TR_NAK) || (err >= 0)) + { + status = kStatus_USB_Success; + + if (err == USB_KHCI_ATOM_TR_NAK) + { + status = kStatus_USB_TransferFailed; + } + } + else if (err < 0) + { + status = kStatus_USB_TransferFailed; + } + else + { + } + + transfer->callbackFn(transfer->callbackParam, transfer, status); +} + +/*! + * @brief khci transaction done process function. + * + * @param usbHostPointer Pointer of the host khci controller handle. + * @param transfer Pointer of transfer node struct, which will be handled process done. + *1400 + */ +static int32_t _USB_HostKhciTransactionDone(usb_khci_host_state_struct_t *usbHostPointer, usb_host_transfer_t *transfer) +{ + uint32_t bd; + uint8_t err; + int32_t transferResult = 0U; + uint32_t type = kTr_Unknown; + uint32_t *bdPointer = NULL; + usb_host_pipe_t *pipeDescPointer = transfer->transferPipe; + + if (pipeDescPointer->pipeType == USB_ENDPOINT_CONTROL) + { + if (transfer->setupStatus == kTransfer_Setup0) + { + type = kTr_Ctrl; + } + else if ((transfer->setupStatus == kTransfer_Setup1)) + { + if (transfer->transferLength) + { + if (transfer->direction == USB_IN) + { + type = kTr_In; + } + else + { + type = kTr_Out; + } + } + else + { + type = kTr_In; + } + } + else if (transfer->setupStatus == kTransfer_Setup2) + { + if (transfer->transferLength) + { + if (transfer->direction == USB_IN) + { + type = kTr_Out; + } + else + { + type = kTr_In; + } + } + else + { + type = kTr_In; + } + } + else if (transfer->setupStatus == kTransfer_Setup3) + { + type = kTr_In; + } + else + { + } + } + else + { + if (pipeDescPointer->direction == USB_IN) + { + type = kTr_In; + } + else if (pipeDescPointer->direction == USB_OUT) + { + type = kTr_Out; + } + else + { + } + } + switch (type) + { + case kTr_Ctrl: + case kTr_Out: + usbHostPointer->txBd ^= 1U; + bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 1, usbHostPointer->txBd); + usbHostPointer->txBd ^= 1U; + break; + + case kTr_In: + usbHostPointer->rxBd ^= 1U; + bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 0U, usbHostPointer->rxBd); + usbHostPointer->rxBd ^= 1U; + break; + + default: + bdPointer = NULL; + break; + } + + if (bdPointer == NULL) + { + return -1; + } + + bd = *bdPointer; + err = usbHostPointer->usbRegBase->ERRSTAT; + if (err & (USB_ERRSTAT_PIDERR_MASK | USB_ERRSTAT_CRC5EOF_MASK | USB_ERRSTAT_CRC16_MASK | USB_ERRSTAT_DFN8_MASK | + USB_ERRSTAT_DMAERR_MASK | USB_ERRSTAT_BTSERR_MASK)) + { + transferResult = -(int32_t)err; + return transferResult; + } + else + { + if (bd & USB_KHCI_BD_OWN) + { +#ifdef HOST_ECHO + usb_echo("Own bit is not clear 0x%x\n", (unsigned int)bd); +#endif + *bdPointer = 0U; + } + if ((pipeDescPointer->pipeType == USB_ENDPOINT_ISOCHRONOUS)) + { + transferResult = (bd >> 16) & 0x3ffU; + } + else + { + switch (bd >> 2 & 0xfU) + { + case 0x03: /* Last Transfer status is DATA0 */ + case 0x0b: /* Last Transfer status is DATA1 */ + case 0x02: /* Last Transfer status is ACK */ + transferResult = (bd >> 16) & 0x3ffU; + /* switch data toggle */ + pipeDescPointer->nextdata01 ^= 1U; + break; + + case 0x0e: /* Last Transfer status is STALL */ + transferResult = USB_KHCI_ATOM_TR_STALL; + break; + + case 0x0a: /* Last Transfer status is NAK */ + transferResult = USB_KHCI_ATOM_TR_NAK; + break; + + case 0x00: /* Last Transfer status is bus timeout **/ + transferResult = USB_KHCI_ATOM_TR_BUS_TIMEOUT; + break; + + case 0x0f: /* Last Transfer status is data error */ + transferResult = USB_KHCI_ATOM_TR_DATA_ERROR; + break; + default: + break; + } + } + } + + if ((kTr_In == type) && (0 == usbHostPointer->sXferSts.isDmaAlign)) + { + usbHostPointer->sXferSts.isDmaAlign = 1U; + if (transferResult > 0) + { + for (int j = 0; j < transferResult; j++) + { + usbHostPointer->sXferSts.rxBufOrig[j] = usbHostPointer->sXferSts.rxBuf[j]; + } + } + } + return transferResult; +} + +/*! + * @brief khci atom transaction process function. + * + * @param usbHostPointer Pointer of the host khci controller instance. + * @param type The USB transfer type. + * @param pipeDescPointer Pointer of usb pipe desc. + * @param bufPointer The memory address is needed to be transferred. + * @param len Transferred data length. + * + * @return 0 mean sucess or other opertor failure error code. + * + */ +static int32_t _USB_HostKhciAtomNonblockingTransaction(usb_khci_host_state_struct_t *usbHostPointer, + uint32_t type, + usb_host_pipe_t *pipeDescPointer, + uint8_t *bufPointer, + uint32_t len) +{ + uint32_t *bdPointer = NULL; + uint8_t *buf = bufPointer; + int32_t transferResult; + uint32_t speed; + uint32_t address; + uint32_t level; + uint8_t counter = 0U; + uint32_t eventBit; + usb_osa_status_t osaStatus; + uint8_t epCtlVal; + + len = (len > pipeDescPointer->maxPacketSize) ? pipeDescPointer->maxPacketSize : len; + USB_HostHelperGetPeripheralInformation(pipeDescPointer->deviceHandle, kUSB_HostGetDeviceLevel, &level); + USB_HostHelperGetPeripheralInformation(pipeDescPointer->deviceHandle, kUSB_HostGetDeviceSpeed, &speed); + USB_HostHelperGetPeripheralInformation(pipeDescPointer->deviceHandle, kUSB_HostGetDeviceAddress, &address); + + if (speed == USB_SPEED_LOW) + { + usbHostPointer->usbRegBase->ADDR |= USB_ADDR_LSEN_MASK; + } + else + { + usbHostPointer->usbRegBase->ADDR &= (~USB_ADDR_LSEN_MASK); + } + usbHostPointer->usbRegBase->ADDR = ((usbHostPointer->usbRegBase->ADDR & (~USB_ADDR_ADDR_MASK)) | + ((((address) << USB_ADDR_ADDR_SHIFT) & USB_ADDR_ADDR_MASK))); + +#if (FSL_FEATURE_USB_KHCI_HOST_ENABLED) + epCtlVal = (level == 1 ? USB_ENDPT_HOSTWOHUB_MASK : 0U) | USB_ENDPT_RETRYDIS_MASK | USB_ENDPT_EPTXEN_MASK | + USB_ENDPT_EPRXEN_MASK | + ((pipeDescPointer->pipeType == USB_ENDPOINT_ISOCHRONOUS ? 0 : USB_ENDPT_EPHSHK_MASK)); +#else + epCtlVal = USB_ENDPT_EPTXEN_MASK | USB_ENDPT_EPRXEN_MASK | + ((pipeDescPointer->pipeType == USB_ENDPOINT_ISOCHRONOUS ? 0 : USB_ENDPT_EPHSHK_MASK)); +#endif + usbHostPointer->usbRegBase->ENDPOINT[0U].ENDPT = epCtlVal; + + transferResult = 0U; + counter = 0U; + /* wait for USB conttoller is ready, and with timeout */ + while ((usbHostPointer->usbRegBase->CTL) & USB_CTL_TXSUSPENDTOKENBUSY_MASK) + { + _USB_HostKhciDelay(usbHostPointer, 1U); + osaStatus = USB_OsaEventWait(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_TOK_DONE, 0U, 1, &eventBit); + if (osaStatus == kStatus_USB_OSA_Success) + { + transferResult = USB_KHCI_ATOM_TR_RESET; + break; + } + else + { + counter++; + if (counter >= 3) + { + transferResult = USB_KHCI_ATOM_TR_CRC_ERROR; + return transferResult; + } + } + } + + if (!transferResult) + { +#if defined(FSL_FEATURE_USB_KHCI_DYNAMIC_SOF_THRESHOLD_COMPARE_ENABLED) && \ + (FSL_FEATURE_USB_KHCI_DYNAMIC_SOF_THRESHOLD_COMPARE_ENABLED == 1U) + if (speed == USB_SPEED_LOW) + { + usbHostPointer->usbRegBase->SOFTHLD = (len * 12 * 7 / 6 + KHCICFG_THSLD_DELAY) / 8; + } + else + { + usbHostPointer->usbRegBase->SOFTHLD = (len * 7 / 6 + KHCICFG_THSLD_DELAY) / 8; + } +#endif + usbHostPointer->usbRegBase->ERRSTAT = 0xffU; + + if ((kTr_In == type) && ((len & USB_MEM4_ALIGN_MASK) || ((uint32_t)bufPointer & USB_MEM4_ALIGN_MASK))) + { + if ((usbHostPointer->khciSwapBufPointer != NULL) && (len <= USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER)) + { + buf = (uint8_t *)USB_MEM4_ALIGN((uint32_t)(usbHostPointer->khciSwapBufPointer + 4)); + usbHostPointer->sXferSts.rxBuf = buf; + usbHostPointer->sXferSts.rxBufOrig = bufPointer; + usbHostPointer->sXferSts.rxLen = len; + usbHostPointer->sXferSts.isDmaAlign = 0U; + } + } + else + { + usbHostPointer->sXferSts.isDmaAlign = 1U; + } + + switch (type) + { + case kTr_Ctrl: + bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 1, usbHostPointer->txBd); + *(bdPointer + 1U) = USB_LONG_TO_LITTLE_ENDIAN((uint32_t)buf); + *bdPointer = USB_LONG_TO_LITTLE_ENDIAN(USB_KHCI_BD_BC(len) | USB_KHCI_BD_OWN); + usbHostPointer->usbRegBase->TOKEN = + (USB_TOKEN_TOKENENDPT((uint8_t)pipeDescPointer->endpointAddress) | USB_TOKEN_TOKENPID(0xD)); + usbHostPointer->txBd ^= 1U; + break; + case kTr_In: + bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 0U, usbHostPointer->rxBd); + *(bdPointer + 1U) = USB_LONG_TO_LITTLE_ENDIAN((uint32_t)buf); + *bdPointer = USB_LONG_TO_LITTLE_ENDIAN(USB_KHCI_BD_BC(len) | USB_KHCI_BD_OWN | + USB_KHCI_BD_DATA01(pipeDescPointer->nextdata01)); + usbHostPointer->usbRegBase->TOKEN = + (USB_TOKEN_TOKENENDPT((uint8_t)pipeDescPointer->endpointAddress) | USB_TOKEN_TOKENPID(0x9)); + usbHostPointer->rxBd ^= 1U; + break; + case kTr_Out: + bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 1, usbHostPointer->txBd); + *(bdPointer + 1U) = USB_LONG_TO_LITTLE_ENDIAN((uint32_t)buf); + *bdPointer = USB_LONG_TO_LITTLE_ENDIAN(USB_KHCI_BD_BC(len) | USB_KHCI_BD_OWN | + USB_KHCI_BD_DATA01(pipeDescPointer->nextdata01)); + usbHostPointer->usbRegBase->TOKEN = + (USB_TOKEN_TOKENENDPT((uint8_t)pipeDescPointer->endpointAddress) | USB_TOKEN_TOKENPID(0x1)); + usbHostPointer->txBd ^= 1U; + break; + default: + bdPointer = NULL; + break; + } + } + + return transferResult; +} + +/*! + * @brief khci host start tramsfer. + * + * @param handle Pointer of the host khci controller handle. + * @param transfer Pointer of transfer node struct, which will transfer. + * + * @retval kKhci_TrTransmiting khci host transaction prime successfully, will enter next stage. + * @retval kKhci_TrTransmitDone khci host transaction prime unsuccessfully, will enter exit stage. + * + */ +static khci_tr_state_t _USB_HostKhciStartTranfer(usb_host_controller_handle handle, usb_host_transfer_t *transfer) +{ + static int32_t transferResult; + uint8_t *buf; + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle; + + if (transfer->transferPipe->pipeType == USB_ENDPOINT_CONTROL) + { + if ((transfer->setupStatus == kTransfer_Setup0)) + { + transferResult = _USB_HostKhciAtomNonblockingTransaction(usbHostPointer, kTr_Ctrl, transfer->transferPipe, + (uint8_t *)&transfer->setupPacket, 8U); + } + else if (transfer->setupStatus == kTransfer_Setup1) + { + if (transfer->transferLength) + { + buf = transfer->transferBuffer; + buf += transfer->transferSofar; + transferResult = _USB_HostKhciAtomNonblockingTransaction( + usbHostPointer, (transfer->direction == USB_IN) ? kTr_In : kTr_Out, transfer->transferPipe, buf, + transfer->transferLength - transfer->transferSofar); + } + else + { + transfer->transferPipe->nextdata01 = 1U; + transfer->setupStatus = kTransfer_Setup3; + transferResult = + _USB_HostKhciAtomNonblockingTransaction(usbHostPointer, kTr_In, transfer->transferPipe, 0U, 0U); + } + } + else if (transfer->setupStatus == kTransfer_Setup2) + { + if (transfer->transferLength) + { + transfer->transferPipe->nextdata01 = 1U; + + transferResult = _USB_HostKhciAtomNonblockingTransaction( + usbHostPointer, (transfer->direction == USB_IN) ? kTr_Out : kTr_In, transfer->transferPipe, 0U, 0U); + } + else + { + transfer->transferPipe->nextdata01 = 1U; + transferResult = + _USB_HostKhciAtomNonblockingTransaction(usbHostPointer, kTr_In, transfer->transferPipe, 0U, 0U); + } + } + else if (transfer->setupStatus == kTransfer_Setup3) + { + transfer->transferPipe->nextdata01 = 1U; + transferResult = + _USB_HostKhciAtomNonblockingTransaction(usbHostPointer, kTr_In, transfer->transferPipe, 0U, 0U); + } + else + { + } + } + else + { + buf = transfer->transferBuffer; + buf += transfer->transferSofar; + transferResult = _USB_HostKhciAtomNonblockingTransaction( + usbHostPointer, (transfer->transferPipe->direction == USB_IN) ? kTr_In : kTr_Out, transfer->transferPipe, + buf, transfer->transferLength - transfer->transferSofar); + } + + transfer->transferResult = transferResult; + + if (transfer->transferResult == 0U) + { + usbHostPointer->trState = kKhci_TrTransmiting; + } + else + { + usbHostPointer->trState = kKhci_TrTransmitDone; + } + return (khci_tr_state_t)usbHostPointer->trState; +} + +/*! + * @brief khci host finish tramsfer. + * + * @param handle Pointer of the host khci controller handle. + * @param transfer Pointer of transfer node struct, which will be transfer. + * + * @retval kKhci_TrGetMsg The current of transaction is transfer done, will enter first stage. + * @retval kKhci_TrTransmitDone All of khci host transaction of the transfer have transfer done, will enter exit + * stage. + * + */ +static khci_tr_state_t _USB_HostKhciFinishTranfer(usb_host_controller_handle handle, usb_host_transfer_t *transfer) +{ + static int32_t transferResult; + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle; + + transfer->transferResult = transferResult = _USB_HostKhciTransactionDone(usbHostPointer, transfer); + if (transferResult >= 0) + { + if (transfer->transferPipe->pipeType == USB_ENDPOINT_CONTROL) + { + if ((transfer->setupStatus == kTransfer_Setup2) || (transfer->setupStatus == kTransfer_Setup3)) + { + usbHostPointer->trState = kKhci_TrTransmitDone; + } + else + { + usbHostPointer->trState = kKhci_TrStartTransmit; + if (transfer->setupStatus == kTransfer_Setup1) + { + transfer->transferSofar += transferResult; + if (((transfer->transferLength - transfer->transferSofar) <= 0U) || + (transferResult < transfer->transferPipe->maxPacketSize)) + { + transfer->setupStatus++; + } + } + else + { + transfer->setupStatus++; + } + } + } + else + { + transfer->transferSofar += transferResult; + if (((transfer->transferLength - transfer->transferSofar) == 0U) || + (transferResult < transfer->transferPipe->maxPacketSize)) + { + usbHostPointer->trState = kKhci_TrTransmitDone; + } + else + { + usbHostPointer->trState = kKhci_TrStartTransmit; + } + } + } + else + { + if ((transferResult == USB_KHCI_ATOM_TR_NAK)) + { + if (transfer->transferPipe->pipeType == USB_ENDPOINT_INTERRUPT) + { + usbHostPointer->trState = kKhci_TrGetMsg; + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG); + } + else + { + if ((_USB_HostKhciGetFrameCountSum(usbHostPointer) - transfer->frame) > transfer->nakTimeout) + { + usbHostPointer->trState = kKhci_TrTransmitDone; + transfer->transferResult = USB_KHCI_ATOM_TR_BUS_TIMEOUT; + } + else + { + usbHostPointer->trState = kKhci_TrGetMsg; + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG); + } + } + } + else + { + usbHostPointer->trState = kKhci_TrTransmitDone; + } + } + return (khci_tr_state_t)usbHostPointer->trState; +} + +/*! + * @brief host khci controller transfer clear up + * + * The function is used to handle controller transfer clear up. + * @param handle Pointer of the host khci controller handle. + * + * + */ +void _USB_HostKhciTransferClearUp(usb_host_controller_handle controllerHandle) +{ + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle; + usb_host_transfer_t *trCancel; + + USB_HostKhciLock(); + trCancel = usbHostPointer->periodicListPointer; + USB_HostKhciUnlock(); + while (trCancel != NULL) + { + _USB_HostKhciUnlinkTrRequestFromList(controllerHandle, trCancel); + trCancel->callbackFn(trCancel->callbackParam, trCancel, kStatus_USB_TransferCancel); + USB_HostKhciLock(); + trCancel = usbHostPointer->periodicListPointer; + USB_HostKhciUnlock(); + } + + USB_HostKhciLock(); + trCancel = usbHostPointer->asyncListPointer; + USB_HostKhciUnlock(); + while (trCancel != NULL) + { + _USB_HostKhciUnlinkTrRequestFromList(controllerHandle, trCancel); + trCancel->callbackFn(trCancel->callbackParam, trCancel, kStatus_USB_TransferCancel); + USB_HostKhciLock(); + trCancel = usbHostPointer->asyncListPointer; + USB_HostKhciUnlock(); + } + usbHostPointer->trState = kKhci_TrGetMsg; +} + +/*! + * @brief host khci controller transfer state machine + * + * The function is used to handle controller transfer state machine. + * @param handle Pointer of the host khci controller handle. + * @param transfer Pointer of transfer node struct, which will be transfer. + * + * + */ +void _USB_HostKhciTransferStateMachine(usb_host_controller_handle controllerHandle, usb_host_transfer_t **ptransfer) +{ + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle; + usb_host_transfer_t *transfer = *ptransfer; + usb_host_transfer_t *tempTransfer = NULL; + uint32_t eventBit = 0; + + switch (usbHostPointer->trState) + { + case kKhci_TrGetMsg: + transfer = NULL; + _USB_HostKhciGetRightTrRequest(controllerHandle, &transfer); + if (transfer != NULL) + { + *ptransfer = transfer; + usbHostPointer->trState = _USB_HostKhciStartTranfer(controllerHandle, transfer); + usbHostPointer->trState = kKhci_TrTransmiting; + } + break; + + case kKhci_IsoTrGetMsg: + *ptransfer = NULL; + if (usbHostPointer->periodicListAvtive) + { + tempTransfer = usbHostPointer->periodicListPointer; + while (tempTransfer != NULL) + { + if ((_USB_HostKhciGetFrameCount(usbHostPointer) % tempTransfer->transferPipe->interval == 0U) && + (tempTransfer->transferPipe->pipeType == USB_ENDPOINT_ISOCHRONOUS)) + { + *ptransfer = tempTransfer; + + _USB_HostKhciStartTranfer(controllerHandle, tempTransfer); + usbHostPointer->trState = kKhci_TrTransmiting; + if (kStatus_USB_OSA_Success == USB_OsaEventWait(usbHostPointer->khciEventPointer, + USB_KHCI_EVENT_TOK_DONE, 0U, 0, &eventBit)) + { + if (eventBit & USB_KHCI_EVENT_TOK_DONE) + { + _USB_HostKhciTransactionDone(usbHostPointer, tempTransfer); + _USB_HostKhciUnlinkTrRequestFromList(usbHostPointer, tempTransfer); + _USB_HostKhciProcessTrCallback(usbHostPointer, tempTransfer, transfer->transferResult); + usbHostPointer->trState = kKhci_TrGetMsg; + } + } + else + { + usbHostPointer->trState = kKhci_TrTransmiting; + } + break; + } + tempTransfer = tempTransfer->next; + } + } + if (*ptransfer == NULL) + { + usbHostPointer->trState = kKhci_TrGetMsg; + } + break; + + case kKhci_TrStartTransmit: + if (transfer != NULL) + { + usbHostPointer->trState = _USB_HostKhciStartTranfer(controllerHandle, transfer); + } + break; + + case kKhci_TrTransmiting: + if (transfer != NULL) + { + if ((_USB_HostKhciGetFrameCountSum(usbHostPointer) - transfer->frame) > USB_TIMEOUT_OTHER) + { + if ((transfer->transferPipe->pipeType == USB_ENDPOINT_CONTROL) || + (transfer->transferPipe->pipeType == USB_ENDPOINT_BULK)) + { + /* clear current bdt status */ + _USB_HostKhciTransactionDone(usbHostPointer, transfer); + usbHostPointer->trState = kKhci_TrTransmitDone; + transfer->transferResult = USB_KHCI_ATOM_TR_BUS_TIMEOUT; + return; + } + } + } + break; + + case kKhci_TrTransmitDone: + if (transfer != NULL) + { + _USB_HostKhciUnlinkTrRequestFromList(usbHostPointer, transfer); + _USB_HostKhciProcessTrCallback(usbHostPointer, transfer, transfer->transferResult); + usbHostPointer->trState = kKhci_TrGetMsg; + if ((usbHostPointer->asyncListAvtive == 1U) || (usbHostPointer->periodicListAvtive == 1U)) + { + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG); + } + } + break; + + default: + break; + } +} + +/*! + * @brief khci task function. + * + * The function is used to handle KHCI controller message. + * In the BM environment, this function should be called periodically in the main function. + * And in the RTOS environment, this function should be used as a function entry to create a task. + * + * @param hostHandle The host handle. + */ +void USB_HostKhciTaskFunction(void *hostHandle) +{ + volatile ptr_usb_host_khci_state_struct_t usbHostPointer; + uint32_t eventBit = 0; + static usb_host_transfer_t *transfer; + + if (hostHandle == NULL) + { + return; + } + + usbHostPointer = (usb_khci_host_state_struct_t *)(((usb_host_instance_t *)hostHandle)->controllerHandle); + if (USB_OsaEventWait(usbHostPointer->khciEventPointer, 0xff, 0U, 1U, &eventBit) == + kStatus_USB_OSA_Success) /* wait all event */ + { + if (eventBit & USB_KHCI_EVENT_ATTACH) + { + _USB_HostKhciAttach(usbHostPointer); + usbHostPointer->trState = kKhci_TrGetMsg; + } + if (eventBit & USB_KHCI_EVENT_RESET) + { + _USB_HostKhciReset(usbHostPointer); + } + if (eventBit & USB_KHCI_EVENT_DETACH) + { + _USB_HostKhciDetach(usbHostPointer); + } + if (eventBit & USB_KHCI_EVENT_SOF_TOK) + { + if ((kKhci_TrGetMsg == usbHostPointer->trState) && (usbHostPointer->deviceAttached)) + { + usbHostPointer->trState = kKhci_IsoTrGetMsg; + _USB_HostKhciTransferStateMachine(usbHostPointer, &transfer); + } + } + if (eventBit & USB_KHCI_EVENT_TOK_DONE) + { + if (transfer != NULL) + { + usbHostPointer->trState = + _USB_HostKhciFinishTranfer(((usb_host_instance_t *)hostHandle)->controllerHandle, transfer); + } + } + } + if (usbHostPointer->deviceAttached) + { + _USB_HostKhciTransferStateMachine(usbHostPointer, &transfer); + } + else + { + _USB_HostKhciTransferClearUp(usbHostPointer); + } +} + +/*! + * @brief create the USB host khci instance. + * + * This function initializes the USB host khci controller driver. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * @param hostHandle The host level handle. + * @param controllerHandle Return the controller instance handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_AllocFail allocate memory fail. + * @retval kStatus_USB_Error host mutex create fail, KHCI/EHCI mutex or KHCI/EHCI event create fail. + * Or, KHCI/EHCI IP initialize fail. + * + */ +usb_status_t USB_HostKhciCreate(uint8_t controllerId, + usb_host_handle hostHandle, + usb_host_controller_handle *controllerHandle) +{ + usb_khci_host_state_struct_t *usbHostPointer; + usb_status_t status = kStatus_USB_Success; + usb_osa_status_t osaStatus; + uint32_t usb_base_addrs[] = USB_BASE_ADDRS; + + if (((controllerId - kUSB_ControllerKhci0) >= (uint8_t)USB_HOST_CONFIG_KHCI) || + ((controllerId - kUSB_ControllerKhci0) >= (sizeof(usb_base_addrs) / sizeof(uint32_t)))) + { + return kStatus_USB_ControllerNotFound; + } + + usbHostPointer = (usb_khci_host_state_struct_t *)USB_OsaMemoryAllocate(sizeof(usb_khci_host_state_struct_t)); + if (NULL == usbHostPointer) + { + *controllerHandle = NULL; + return kStatus_USB_AllocFail; + } + + /* Allocate the USB Host Pipe Descriptors */ + usbHostPointer->pipeDescriptorBasePointer = NULL; + usbHostPointer->hostHandle = hostHandle; + *controllerHandle = (usb_host_handle)usbHostPointer; + + if (NULL == (usbHostPointer->khciSwapBufPointer = + (uint8_t *)USB_OsaMemoryAllocate(USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER + 4))) + { +#ifdef HOST_DEBUG_ + usb_echo("usbHostPointer->khciSwapBufPointer- memory allocation failed"); +#endif + USB_HostKhciDestory(controllerHandle); + return kStatus_USB_AllocFail; + } + + /* init khci mutext */ + osaStatus = USB_OsaMutexCreate(&usbHostPointer->khciMutex); + if (osaStatus != kStatus_USB_OSA_Success) + { +#ifdef HOST_ECHO + usb_echo("khci mutex init fail\r\n"); +#endif + USB_HostKhciDestory(controllerHandle); + return kStatus_USB_Error; + } + + USB_OsaEventCreate(&usbHostPointer->khciEventPointer, 1U); + if (usbHostPointer->khciEventPointer == NULL) + { +#ifdef HOST_ECHO + usb_echo(" memalloc failed in usb_khci_init\n"); +#endif + + return kStatus_USB_AllocFail; + } /* Endif */ + + usbHostPointer->usbRegBase = (USB_Type *)usb_base_addrs[controllerId - kUSB_ControllerKhci0]; + + usbHostPointer->asyncListAvtive = 0U; + usbHostPointer->periodicListAvtive = 0U; + usbHostPointer->periodicListPointer = NULL; + usbHostPointer->asyncListPointer = NULL; + usbHostPointer->sXferSts.isDmaAlign = 0U; + + /* set internal register pull down */ + usbHostPointer->usbRegBase->CTL = USB_CTL_SE0_MASK; + + /* Reset USB CTRL register */ + usbHostPointer->usbRegBase->CTL = 0UL; + usbHostPointer->usbRegBase->ISTAT = 0xffU; + /* Enable week pull-downs, useful for detecting detach (effectively bus discharge) */ + usbHostPointer->usbRegBase->USBCTRL |= USB_USBCTRL_PDE_MASK; + /* Remove suspend state */ + usbHostPointer->usbRegBase->USBCTRL &= (~USB_USBCTRL_SUSP_MASK); + usbHostPointer->usbRegBase->CTL |= USB_CTL_ODDRST_MASK; + + usbHostPointer->usbRegBase->BDTPAGE1 = (uint8_t)((uint32_t)USB_KHCI_BDT_BASE >> 8U); + usbHostPointer->usbRegBase->BDTPAGE2 = (uint8_t)((uint32_t)USB_KHCI_BDT_BASE >> 16); + usbHostPointer->usbRegBase->BDTPAGE3 = (uint8_t)((uint32_t)USB_KHCI_BDT_BASE >> 24); + /* Set SOF threshold */ + usbHostPointer->usbRegBase->SOFTHLD = 255; + + usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK; + /* Wait for attach interrupt */ + usbHostPointer->usbRegBase->INTEN |= (USB_INTEN_ATTACHEN_MASK);// | USB_INTEN_SOFTOKEN_MASK); +#if defined(FSL_FEATURE_USB_KHCI_DYNAMIC_SOF_THRESHOLD_COMPARE_ENABLED) && \ + (FSL_FEATURE_USB_KHCI_DYNAMIC_SOF_THRESHOLD_COMPARE_ENABLED == 1U) + usbHostPointer->usbRegBase->MISCCTRL |= USB_MISCCTRL_SOFDYNTHLD_MASK; +#endif + usbHostPointer->trState = kKhci_TrGetMsg; + return status; +} + +/*! + * @brief destroy USB host khci instance. + * + * This function de-initialize the USB host khci controller driver. + * + * @param handle the controller handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + */ +usb_status_t USB_HostKhciDestory(usb_host_controller_handle controllerHandle) +{ + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle; + + usbHostPointer->usbRegBase->INTEN &= (~0xFFU); + + usbHostPointer->usbRegBase->ADDR = ((usbHostPointer->usbRegBase->ADDR & (~USB_ADDR_ADDR_MASK)) | + ((((0U) << USB_ADDR_ADDR_SHIFT) & USB_ADDR_ADDR_MASK))); + usbHostPointer->usbRegBase->CTL &= (~0xFFu); + usbHostPointer->usbRegBase->USBCTRL |= USB_USBCTRL_PDE_MASK; + usbHostPointer->usbRegBase->USBCTRL |= USB_USBCTRL_SUSP_MASK; + usbHostPointer->usbRegBase->ADDR &= (~USB_ADDR_LSEN_MASK); + + if (NULL != usbHostPointer->khciEventPointer) + { + USB_OsaEventDestroy(usbHostPointer->khciEventPointer); + } + if (NULL != usbHostPointer->khciMutex) + { + USB_OsaMutexDestroy(usbHostPointer->khciMutex); + } + + if (NULL != usbHostPointer->khciSwapBufPointer) + { + USB_OsaMemoryFree(usbHostPointer->khciSwapBufPointer); + usbHostPointer->khciSwapBufPointer = NULL; + } + + USB_OsaMemoryFree(usbHostPointer); + usbHostPointer = NULL; + + return kStatus_USB_Success; +} + +/*! + * @brief open USB host pipe. + * + * This function open one pipe according to the pipeInitPointer parameter. + * + * @param controllerHandle the controller handle. + * @param pipeHandlePointer the pipe handle pointer, it is used to return the pipe handle. + * @param pipeInitPointer it is used to initialize the pipe. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_Error there is no idle pipe. +* +*/ +usb_status_t USB_HostKhciOpenPipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle *pipeHandlePointer, + usb_host_pipe_init_t *pipeInitPointer) +{ + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle; + usb_host_pipe_t *pipePointer; + usb_host_pipe_t *prePipePointer; + usb_host_pipe_t *tempPipePointer; + + USB_OSA_SR_ALLOC(); + USB_OSA_ENTER_CRITICAL(); + pipePointer = (usb_host_pipe_t *)USB_OsaMemoryAllocate(sizeof(usb_host_pipe_t)); + if (pipePointer == NULL) + { + USB_OsaMemoryFree(usbHostPointer); + return kStatus_USB_AllocFail; + } + else + { + if (usbHostPointer->pipeDescriptorBasePointer == NULL) + { + usbHostPointer->pipeDescriptorBasePointer = pipePointer; + } + else + { + tempPipePointer = usbHostPointer->pipeDescriptorBasePointer; + while (NULL != tempPipePointer) + { + prePipePointer = tempPipePointer; + tempPipePointer = tempPipePointer->next; + } + prePipePointer->next = pipePointer; + } + pipePointer->next = NULL; + } + USB_OSA_EXIT_CRITICAL(); + + pipePointer->deviceHandle = pipeInitPointer->devInstance; + pipePointer->endpointAddress = pipeInitPointer->endpointAddress; + pipePointer->direction = pipeInitPointer->direction; + pipePointer->interval = pipeInitPointer->interval; + pipePointer->maxPacketSize = pipeInitPointer->maxPacketSize; + pipePointer->pipeType = pipeInitPointer->pipeType; + pipePointer->numberPerUframe = pipeInitPointer->numberPerUframe; + pipePointer->nakCount = pipeInitPointer->nakCount; + pipePointer->nextdata01 = 0U; + pipePointer->open = (uint8_t)1U; + pipePointer->currentCount = 0xffffU; + + if (pipePointer->pipeType == USB_ENDPOINT_ISOCHRONOUS) + { + pipePointer->interval = 1 << (pipeInitPointer->interval - 1U); + } + else + { + pipePointer->interval = _USB_HostKhciGetRoundUpPow2(pipeInitPointer->interval); + } + *pipeHandlePointer = pipePointer; + + return kStatus_USB_Success; +} + +/*! + * @brief close USB host pipe. + * + * This function close one pipe and release the related resources. + * + * @param controllerHandle the controller handle. + * @param pipeHandle the closing pipe handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + */ +usb_status_t USB_HostKhciClosePipe(usb_host_controller_handle controllerHandle, usb_host_pipe_handle pipeHandle) +{ + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle; + usb_host_pipe_t *pipePointer = (usb_host_pipe_t *)pipeHandle; + usb_host_pipe_t *prePipePointer; + + USB_OSA_SR_ALLOC(); + USB_OSA_ENTER_CRITICAL(); + + if ((pipePointer != NULL) && (pipePointer->open == (uint8_t)1U)) + { + if (pipeHandle == usbHostPointer->pipeDescriptorBasePointer) + { + usbHostPointer->pipeDescriptorBasePointer = usbHostPointer->pipeDescriptorBasePointer->next; + USB_OsaMemoryFree(pipeHandle); + } + else + { + pipePointer = usbHostPointer->pipeDescriptorBasePointer; + prePipePointer = pipePointer; + while (NULL != pipePointer) + { + if ((pipePointer->open) && (pipePointer == pipeHandle)) + { + prePipePointer->next = pipePointer->next; + if (NULL != pipePointer) + { + USB_OsaMemoryFree(pipePointer); + pipePointer = NULL; + } + break; + } + prePipePointer = pipePointer; + pipePointer = pipePointer->next; + } + } + } + else + { +#ifdef HOST_ECHO + usb_echo("usb_khci_close_pipe invalid pipe \n"); +#endif + } + USB_OSA_EXIT_CRITICAL(); + + return kStatus_USB_Success; +} + +/*! + * @brief send data to pipe. + * + * This function request to send the transfer to the specified pipe. + * + * @param controllerHandle the controller handle. + * @param pipeHandle the sending pipe handle. + * @param transfer the transfer which will be wrote. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_LackSwapBuffer there is no swap buffer for KHCI. + * + */ +usb_status_t USB_HostKhciWritePipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle; + + usb_host_pipe_t *pipePointer = (usb_host_pipe_t *)pipeHandle; + + transfer->transferPipe = pipePointer; + transfer->retry = RETRY_TIME; + + if (pipePointer->endpointAddress == 0U) + { + if ((transfer->direction == USB_IN) && (transfer->transferBuffer != NULL) && + ((transfer->transferLength & USB_MEM4_ALIGN_MASK) || + ((uint32_t)transfer->transferBuffer & USB_MEM4_ALIGN_MASK))) + { + if (usbHostPointer->khciSwapBufPointer == NULL) + { + return kStatus_USB_LackSwapBuffer; + } + if (pipePointer->maxPacketSize > USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER) + { + return kStatus_USB_LackSwapBuffer; + } + } + transfer->setupStatus = kTransfer_Setup0; + + if (transfer->transferLength) + { + if (transfer->direction == USB_IN) + { + transfer->nakTimeout = USB_TIMEOUT_TOHOST; + } + else + { + transfer->nakTimeout = USB_TIMEOUT_TODEVICE; + } + } + else + { + transfer->nakTimeout = USB_TIMEOUT_NODATA; + } + } + else + { + if (pipePointer->nakCount == 0U) + { + transfer->nakTimeout = USB_TIMEOUT_DEFAULT; + } + else + { + transfer->nakTimeout = pipePointer->nakCount * NAK_RETRY_TIME; + } + } + transfer->frame = _USB_HostKhciGetFrameCountSum(usbHostPointer); + + _USB_HostKhciLinkTrRequestToList(controllerHandle, transfer); + + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG); + + return status; +} + +/*! + * @brief receive data from pipe. + * + * This function request to receive the transfer from the specified pipe. + * + * @param controllerHandle the controller handle. + * @param pipeHandle the receiving pipe handle. + * @param transfer the transfer which will be read. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_LackSwapBuffer there is no swap buffer for KHCI. + * + */ +usb_status_t USB_HostKhciReadpipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle; + usb_host_pipe_t *pipePointer = (usb_host_pipe_t *)pipeHandle; + + if ((transfer->transferLength & USB_MEM4_ALIGN_MASK) || ((uint32_t)transfer->transferBuffer & USB_MEM4_ALIGN_MASK)) + { + if (usbHostPointer->khciSwapBufPointer == NULL) + { + return kStatus_USB_LackSwapBuffer; + } + if (pipePointer->maxPacketSize > USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER) + { + return kStatus_USB_LackSwapBuffer; + } + } + + transfer->transferPipe = pipePointer; + transfer->transferSofar = 0U; + if (pipePointer->nakCount == 0U) + { + transfer->nakTimeout = USB_TIMEOUT_DEFAULT; + } + else + { + transfer->nakTimeout = pipePointer->nakCount * NAK_RETRY_TIME; + } + transfer->retry = RETRY_TIME; + transfer->frame = _USB_HostKhciGetFrameCountSum(usbHostPointer); + + _USB_HostKhciLinkTrRequestToList(controllerHandle, transfer); + USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG); + + return status; +} + +/*! + * @brief cancel pipe's transfers. + * + * @param handle Pointer of the host khci controller handle. + * @param pipePointer Pointer of the pipe. + * @param trPointer The canceling transfer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t _USB_HostKhciCancelPipe(usb_host_controller_handle handle, + usb_host_pipe_t *pipePointer, + usb_host_transfer_t *trPointer) +{ + usb_host_transfer_t *temptr = NULL; + usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle; + + if ((pipePointer->pipeType == USB_ENDPOINT_ISOCHRONOUS) || (pipePointer->pipeType == USB_ENDPOINT_INTERRUPT)) + { + temptr = usbHostPointer->periodicListPointer; + } + else if ((pipePointer->pipeType == USB_ENDPOINT_CONTROL) || (pipePointer->pipeType == USB_ENDPOINT_BULK)) + { + temptr = usbHostPointer->asyncListPointer; + } + else + { + } + + while (temptr != NULL) + { + if (((usb_host_pipe_t *)(temptr->transferPipe) == pipePointer) && + ((trPointer == NULL) || (trPointer == temptr))) + { + _USB_HostKhciUnlinkTrRequestFromList(handle, temptr); + temptr->callbackFn(temptr->callbackParam, temptr, kStatus_USB_TransferCancel); + return kStatus_USB_Success; + } + temptr = temptr->next; + } + + return kStatus_USB_Success; +} + +/*! + * @brief khci bus control. + * + * @param handle Pointer of the host khci controller handle. + * @param busControl Bus control code. + * + * @return kStatus_USB_Success + */ +static usb_status_t _USB_HostKhciBusControl(usb_host_controller_handle handle, uint8_t busControl) +{ + ptr_usb_host_khci_state_struct_t usbHostPointer = (usb_khci_host_state_struct_t *)handle; + if (busControl == kUSB_HostBusReset) + { + usbHostPointer->usbRegBase->CTL |= USB_CTL_RESET_MASK; + /* wait for 30 milliseconds (2.5 is minimum for reset, 10 recommended) */ + _USB_HostKhciDelay(usbHostPointer, 30U); + usbHostPointer->usbRegBase->CTL &= (~USB_CTL_RESET_MASK); + usbHostPointer->usbRegBase->CTL |= USB_CTL_ODDRST_MASK; + usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK; + + usbHostPointer->txBd = 0U; + usbHostPointer->rxBd = 0U; + } + else if (busControl == kUSB_HostBusRestart) + { + usbHostPointer->deviceAttached = 0U; + + usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK; + usbHostPointer->usbRegBase->ISTAT = 0xffU; + /* Now, enable only USB interrupt attach for host mode */ + usbHostPointer->usbRegBase->INTEN |= USB_INTEN_ATTACHEN_MASK; + } + else if (busControl == kUSB_HostBusEnableAttach) + { + if (usbHostPointer->deviceAttached <= 0) + { + usbHostPointer->usbRegBase->INTEN |= USB_INTEN_ATTACHEN_MASK; + } + } + else if (busControl == kUSB_HostBusDisableAttach) + { + usbHostPointer->usbRegBase->INTEN &= (~USB_INTEN_ATTACHEN_MASK); + } + else + { + } + + return kStatus_USB_Success; +} + +/*! + * @brief io control khci. + * + * This function implemented khci io control khci. + * + * @param controllerHandle the controller handle. + * @param ioctlEvent please reference to enumeration host_busControl_t. + * @param ioctlParam the control parameter. + * + * @retval kStatus_USB_Success io ctrol successfully. + * @retval kStatus_USB_InvalidHandle The controllerHandle is a NULL pointer. + */ +usb_status_t USB_HostKciIoctl(usb_host_controller_handle controllerHandle, uint32_t ioctlEvent, void *ioctlParam) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_cancel_param_t *param; + + if (controllerHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + switch (ioctlEvent) + { + case kUSB_HostCancelTransfer: + param = (usb_host_cancel_param_t *)ioctlParam; + status = _USB_HostKhciCancelPipe(controllerHandle, (usb_host_pipe_t *)param->pipeHandle, param->transfer); + break; + + case kUSB_HostBusControl: + status = _USB_HostKhciBusControl(controllerHandle, *((uint8_t *)ioctlParam)); + break; + + case kUSB_HostGetFrameNumber: + *((uint32_t *)ioctlParam) = _USB_HostKhciGetFrameCount(controllerHandle); + break; + + default: + break; + } + return status; +} +#endif /* USB_HOST_CONFIG_KHCI */ diff --git a/usb_1.1.0/host/usb_host_khci.h b/usb_1.1.0/host/usb_host_khci.h new file mode 100644 index 0000000..38884c7 --- /dev/null +++ b/usb_1.1.0/host/usb_host_khci.h @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2015 -2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_HOST_KHCI_H__ +#define __USB_HOST_KHCI_H__ + +/******************************************************************************* + * KHCI driver private structures, enumerations, macros, functions + ******************************************************************************/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define USB_KHCI_MAX_SPEED_DETECTION_COUNT 3 + +/* usb khci atom transaction error results */ +#define USB_KHCI_ATOM_TR_PID_ERROR (-1) +#define USB_KHCI_ATOM_TR_EOF_ERROR (-2) +#define USB_KHCI_ATOM_TR_CRC_ERROR (-4) +#define USB_KHCI_ATOM_TR_TO (-16) +#define USB_KHCI_ATOM_TR_DMA_ERROR (-32) +#define USB_KHCI_ATOM_TR_BTS_ERROR (-128) +#define USB_KHCI_ATOM_TR_NAK (-256) +#define USB_KHCI_ATOM_TR_DATA_ERROR (-512) +#define USB_KHCI_ATOM_TR_STALL (-1024) +#define USB_KHCI_ATOM_TR_RESET (-2048) +#define USB_KHCI_ATOM_TR_BUS_TIMEOUT (-4096) +#define USB_KHCI_ATOM_TR_INVALID (-8192) + +/* KHCI event bits */ +#define USB_KHCI_EVENT_ATTACH 0x01 +#define USB_KHCI_EVENT_RESET 0x02 +#define USB_KHCI_EVENT_TOK_DONE 0x04 +#define USB_KHCI_EVENT_SOF_TOK 0x08 +#define USB_KHCI_EVENT_DETACH 0x10 +#define USB_KHCI_EVENT_MSG 0x20 +#define USB_KHCI_EVENT_ISO_MSG 0x40 +#define USB_KHCI_EVENT_NAK_MSG 0x80 +#define USB_KHCI_EVENT_MASK 0xff + +typedef enum _transfer_status +{ + kTransfer_Idle = 0, + kTransfer_Setup0, + kTransfer_Setup1, + kTransfer_Setup2, + kTransfer_Setup3, +} transfer_status_t; + +typedef enum _khci_intr_type +{ + kIntr_UsbRst = 0x01, + kIntr_Error = 0x02, + kIntr_SofTok = 0x04, + kIntr_TokDne = 0x08, + kIntr_Sleep = 0x10, + kIntr_Resume = 0x20, + kIntr_Attach = 0x40, + kIntr_Stall = 0x80, +} khci_intr_type_t; + +typedef enum _tr_type +{ + kTr_Ctrl = 0, + kTr_In, + kTr_Out, + kTr_OutHndsk, + kTr_InHndsk, + kTr_Unknown +} tr_type_t; + +/* Transaction type */ +typedef enum _tr_request_type +{ + kTr_MsgUnknown = 0, /*Unknown - not used */ + kTr_MsgSetup, /* Set up transaction */ + kTr_MsgSend, /* Send transaction */ + kTr_MsgRecv /* Receive transaction */ +} tr_request_type_t; + +typedef enum tr_request_state +{ + kTr_MsgIdle = 0, /*Normal transfer */ + kTr_MsgNak, /* NAK transfer */ + kTr_BusTimeout, +} tr_request_state_t; + +typedef enum khci_tr_state +{ + kKhci_TrGetMsg = 0, + kKhci_IsoTrGetMsg, + kKhci_TrStartTransmit, + kKhci_TrTransmiting, + kKhci_TrTransmitDone, + kKhci_TrNone +} khci_tr_state_t; + +/* Defines the USB KHCI time out value from USB specification */ +#define USB_TIMEOUT_NODATA (500) +#define USB_TIMEOUT_TOHOST (5000) +#define USB_TIMEOUT_TODEVICE (5000) +#define USB_TIMEOUT_OTHER (10000) +#define USB_TIMEOUT_DEFAULT (500) + +#define NAK_RETRY_TIME (1) +#define RETRY_TIME (3) + +/* Define USB buffer descriptor operator MACRO definitions; This part is not included in header files */ +#define USB_KHCI_BDT_BASE ((uint32_t *)(&bdt[0])) +#define USB_KHCI_BD_PTR(ep, rxtx, odd) \ + ((((uint32_t)USB_KHCI_BDT_BASE) & 0xfffffe00U) | ((ep & 0x0fu) << 5) | ((rxtx & 1u) << 4) | ((odd & 1u) << 3)) + +#define USB_KHCI_BD_CTRL(ep, rxtx, odd) (*((uint32_t *)USB_KHCI_BD_PTR(ep, rxtx, odd))) +#define USB_KHCI_BD_CTRL_RX(ep, odd) (*((uint32_t *)USB_KHCI_BD_PTR(ep, 0, odd))) +#define USB_KHCI_BD_CTRL_TX(ep, odd) (*((uint32_t *)USB_KHCI_BD_PTR(ep, 1, odd))) + +#define USB_KHCI_BD_ADDR(ep, rxtx, odd) (*((uint32_t *)USB_KHCI_BD_PTR(ep, rxtx, odd) + 1)) +#define USB_KHCI_BD_ADDR_RX(ep, odd) (*((uint32_t *)USB_KHCI_BD_PTR(ep, 0, odd) + 1)) +#define USB_KHCI_BD_ADDR_TX(ep, odd) (*((uint32_t *)USB_KHCI_BD_PTR(ep, 1, odd) + 1)) + +/* Define USB buffer descriptor definitions; This part is not included in header files */ +#define USB_KHCI_BD_BC(n) ((n & 0x3ffu) << 16) +#define USB_KHCI_BD_OWN 0x80u +#define USB_KHCI_BD_DATA01(n) ((n & 1u) << 6) +#define USB_KHCI_BD_DATA0 USB_KHCI_BD_DATA01(0u) +#define USB_KHCI_BD_DATA1 USB_KHCI_BD_DATA01(1u) +#define USB_KHCI_BD_KEEP 0x20u +#define USB_KHCI_BD_NINC 0x10u +#define USB_KHCI_BD_DTS 0x08u +#define USB_KHCI_BD_STALL 0x04u +#define USB_KHCI_BD_PID(n) ((n & 0x0fu) << 2) + +#define USB_HostKhciLock() USB_OsaMutexLock(usbHostPointer->khciMutex) +#define USB_HostKhciUnlock() USB_OsaMutexUnlock(usbHostPointer->khciMutex) + +typedef struct _khci_xfer_sts +{ + uint32_t rxLen; + uint8_t *rxBuf; + uint8_t *rxBufOrig; + uint8_t isDmaAlign; +} khci_xfer_sts_t; + +/******************************************************************************* + * KHCI driver public structures, enumerations, macros, functions + ******************************************************************************/ + +/*! + * @addtogroup usb_host_controller_khci + * @{ + */ + +/*! @brief The value programmed into the threshold register must reserve enough time to ensure the worst case + transaction completes. In general, the worst case transaction is an IN token followed by a data packet from the target + followed by the response from the host. The actual time required is a function of the maximum packet size on the bus. Set the + KHCICFG_THSLD_DELAY to 0x65 to meet the worst case.*/ + +#define KHCICFG_THSLD_DELAY 0x65 + +/*! @brief KHCI controller driver instance structure */ +typedef struct _usb_khci_host_state_struct +{ + volatile USB_Type *usbRegBase; /*!< The base address of the register */ + void *hostHandle; /*!< Related host handle*/ + usb_host_pipe_t *pipeDescriptorBasePointer; /*!< Pipe descriptor bas pointer*/ + usb_osa_event_handle khciEventPointer; /*!< KHCI event*/ + usb_osa_mutex_handle khciMutex; /*!< KHCI mutex*/ + usb_host_transfer_t + *periodicListPointer; /*!< KHCI periodic list pointer, which link is an interrupt and an ISO transfer request*/ + usb_host_transfer_t *asyncListPointer; /*!< KHCI async list pointer, which link controls and bulk transfer request*/ + khci_xfer_sts_t sXferSts; /*!< KHCI transfer status structure for the DAM ALIGN workaround */ + uint8_t *khciSwapBufPointer; /*!< KHCI swap buffer pointer for the DAM ALIGN workaround*/ + volatile uint32_t trState; /*!< KHCI transfer state*/ + uint8_t asyncListAvtive; /*!< KHCI async list is active*/ + uint8_t periodicListAvtive; /*!< KHCI periodic list is active*/ + uint8_t rxBd; /*!< RX buffer descriptor toggle bits*/ + uint8_t txBd; /*!< TX buffer descriptor toggle bits*/ + uint8_t deviceSpeed; /*!< Device speed*/ + int8_t deviceAttached; /*!< Device attach/detach state */ +} usb_khci_host_state_struct_t, *ptr_usb_host_khci_state_struct_t; + +#ifdef __cplusplus +extern "C" { +#endif +/*! + * @name USB host KHCI APIs + * @{ + */ + +/*! + * @brief Creates the USB host KHCI instance. + * + * This function initializes the USB host KHCI controller driver. + * + * @param controllerId The controller ID of the USB IP. See the enumeration usb_controller_index_t. + * @param hostHandle The host level handle. + * @param controllerHandle Returns the controller instance handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_AllocFail Allocates memory failed. + * @retval kStatus_USB_Error Host mutex create failed, KHCI mutex or KHCI event create failed. + * Or, KHCI IP initialize failed. + */ +extern usb_status_t USB_HostKhciCreate(uint8_t controllerId, + usb_host_handle hostHandle, + usb_host_controller_handle *controllerHandle); + +/*! + * @brief Destroys the USB host KHCI instance. + * + * This function deinitializes the USB host KHCI controller driver. + * + * @param controllerHandle The controller handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + */ +extern usb_status_t USB_HostKhciDestory(usb_host_controller_handle controllerHandle); + +/*! + * @brief Opens the USB host pipe. + * + * This function opens a pipe according to the pipe_init_ptr parameter. + * + * @param controllerHandle The controller handle. + * @param pipeHandlePointer The pipe handle pointer used to return the pipe handle. + * @param pipeInitPointer It is used to initialize the pipe. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_Error There is no idle pipe. + * + */ +extern usb_status_t USB_HostKhciOpenPipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle *pipeHandlePointer, + usb_host_pipe_init_t *pipeInitPointer); + +/*! + * @brief Closes the USB host pipe. + * + * This function closes a pipe and frees the related resources. + * + * @param controllerHandle The controller handle. + * @param pipeHandle The closing pipe handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + */ +extern usb_status_t USB_HostKhciClosePipe(usb_host_controller_handle controllerHandle, usb_host_pipe_handle pipeHandle); + +/*! + * @brief Sends data to the pipe. + * + * This function requests to send the transfer to the specified pipe. + * + * @param controllerHandle The controller handle. + * @param pipeHandle The sending pipe handle. + * @param transfer The transfer information. + * + * @retval kStatus_USB_Success Send successful. + * @retval kStatus_USB_LackSwapBuffer There is no swap buffer for KHCI. + */ +extern usb_status_t USB_HostKhciWritePipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); + +/*! + * @brief Receives data from the pipe. + * + * This function requests to receive the transfer from the specified pipe. + * + * @param controllerHandle The controller handle. + * @param pipeHandle The receiving pipe handle. + * @param transfer The transfer information. + * + * @retval kStatus_USB_Success Receive successful. + * @retval kStatus_USB_LackSwapBuffer There is no swap buffer for KHCI. + */ +extern usb_status_t USB_HostKhciReadpipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); + +/*! + * @brief Controls the KHCI. + * + * This function controls the KHCI. + * + * @param controllerHandle The controller handle. + * @param ioctlEvent See the enumeration host_bus_control_t. + * @param ioctlParam The control parameter. + * + * @retval kStatus_USB_Success Cancel successful. + * @retval kStatus_USB_InvalidHandle The controllerHandle is a NULL pointer. + */ +extern usb_status_t USB_HostKciIoctl(usb_host_controller_handle controllerHandle, + uint32_t ioctlEvent, + void *ioctlParam); + +/*! @}*/ +#ifdef __cplusplus +} +#endif +/*! @}*/ +#endif /* __USB_HOST_KHCI_H__ */ diff --git a/usb_1.1.0/include/usb.h b/usb_1.1.0/include/usb.h new file mode 100644 index 0000000..8241732 --- /dev/null +++ b/usb_1.1.0/include/usb.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_H__ +#define __USB_H__ + +#include +#include +#include "usb_osa.h" +#include "usb_misc.h" +#include "usb_spec.h" + +/*! + * @addtogroup usb_drv + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief Defines USB stack major version */ +#define USB_STACK_VERSION_MAJOR (1U) +/*! @brief Defines USB stack minor version */ +#define USB_STACK_VERSION_MINOR (1U) +/*! @brief Defines USB stack bugfix version */ +#define USB_STACK_VERSION_BUGFIX (0U) + +/*! @brief USB stack version definition */ +#define USB_MAKE_VERSION(major, minor, bugfix) (((major) << 16) | ((minor) << 8) | (bugfix)) + +/*! @brief USB error code */ +typedef enum _usb_status +{ + kStatus_USB_Success = 0x00U, /*!< Success */ + kStatus_USB_Error, /*!< Failed */ + + kStatus_USB_Busy, /*!< Busy */ + kStatus_USB_InvalidHandle, /*!< Invalid handle */ + kStatus_USB_InvalidParameter, /*!< Invalid parameter */ + kStatus_USB_InvalidRequest, /*!< Invalid request */ + kStatus_USB_ControllerNotFound, /*!< Controller cannot be found */ + kStatus_USB_InvalidControllerInterface, /*!< Invalid controller interface */ + + kStatus_USB_NotSupported, /*!< Configuration is not supported */ + kStatus_USB_Retry, /*!< Enumeration get configuration retry */ + kStatus_USB_TransferStall, /*!< Transfer stalled */ + kStatus_USB_TransferFailed, /*!< Transfer failed */ + kStatus_USB_AllocFail, /*!< Allocation failed */ + kStatus_USB_LackSwapBuffer, /*!< Insufficient swap buffer for KHCI */ + kStatus_USB_TransferCancel, /*!< The transfer cancelled */ + kStatus_USB_BandwidthFail, /*!< Allocate bandwidth failed */ + kStatus_USB_MSDStatusFail, /*!< For MSD, the CSW status means fail */ +} usb_status_t; + +/*! @brief USB host handle type define */ +typedef void *usb_host_handle; + +/*! @brief USB device handle type define. For device stack it is the whole device handle; for host stack it is the + * attached device instance handle*/ +typedef void *usb_device_handle; + +/*! @brief USB OTG handle type define */ +typedef void *usb_otg_handle; + +/*! @brief USB controller ID */ +typedef enum _usb_controller_index +{ + kUSB_ControllerKhci0 = 0U, /*!< KHCI 0U */ + kUSB_ControllerKhci1, /*!< KHCI 1U, Currently, there are no platforms which have two KHCI IPs, this is reserved + to be used in the future. */ + kUSB_ControllerEhci0, /*!< EHCI 0U */ + kUSB_ControllerEhci1, /*!< EHCI 1U, Currently, there are no platforms which have two KHCI IPs, this is reserved + to be used in the future. */ +} usb_controller_index_t; + +/** +* @brief USB stack version fields +*/ +typedef struct _usb_version +{ + uint8_t major; /*!< Major */ + uint8_t minor; /*!< Minor */ + uint8_t bugfix; /*!< Bug fix */ +} usb_version_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! @} */ + +#endif /* __USB_H__ */ diff --git a/usb_1.1.0/include/usb_khci.h b/usb_1.1.0/include/usb_khci.h new file mode 100644 index 0000000..c60346f --- /dev/null +++ b/usb_1.1.0/include/usb_khci.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_KHCI_H__ +#define __USB_KHCI_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define USB_KHCI_BDT_DEVICE_OUT_TOKEN (0x01U) +#define USB_KHCI_BDT_DEVICE_IN_TOKEN (0x09U) +#define USB_KHCI_BDT_DEVICE_SETUP_TOKEN (0x0DU) + +#define USB_KHCI_BDT_OWN (0x80U) +#define USB_KHCI_BDT_DATA01(x) ((((uint32_t)(x)) & 0x01U) << 0x06U) +#define USB_KHCI_BDT_BC(x) ((((uint32_t)(x)) & 0x3FFU) << 0x10U) +#define UBS_KHCI_BDT_KEEP (0x20U) +#define UBS_KHCI_BDT_NINC (0x10U) +#define USB_KHCI_BDT_DTS (0x08U) +#define USB_KHCI_BDT_STALL (0x04U) + +typedef enum _usb_khci_interrupt_type +{ + kUSB_KhciInterruptReset = 0x01U, + kUSB_KhciInterruptError = 0x02U, + kUSB_KhciInterruptSofToken = 0x04U, + kUSB_KhciInterruptTokenDone = 0x08U, + kUSB_KhciInterruptSleep = 0x10U, + kUSB_KhciInterruptResume = 0x20U, + kUSB_KhciInterruptAttach = 0x40U, + kUSB_KhciInterruptStall = 0x80U, +} usb_khci_interrupt_type_t; + +#endif /* __USB_KHCI_H__ */ diff --git a/usb_1.1.0/include/usb_misc.h b/usb_1.1.0/include/usb_misc.h new file mode 100644 index 0000000..576cfeb --- /dev/null +++ b/usb_1.1.0/include/usb_misc.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_MISC_H__ +#define __USB_MISC_H__ + +#ifndef ENDIANNESS + +#error ENDIANNESS should be defined, and then rebulid the project. + +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Define USB printf */ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +extern int DbgConsole_Printf(const char *fmt_s, ...); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#define usb_echo DbgConsole_Printf + +#if defined(__ICCARM__) + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED __packed +#endif + +#ifndef STRUCT_UNPACKED +#define STRUCT_UNPACKED +#endif + +#elif defined(__GNUC__) + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED +#endif + +#ifndef STRUCT_UNPACKED +#define STRUCT_UNPACKED __attribute__((__packed__)) +#endif + +#elif defined(__CC_ARM) + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED _Pragma("pack(1U)") +#endif + +#ifndef STRUCT_UNPACKED +#define STRUCT_UNPACKED _Pragma("pack()") +#endif + +#endif + +#define USB_SHORT_GET_LOW(x) (((uint16_t)x) & 0xFFU) +#define USB_SHORT_GET_HIGH(x) ((uint8_t)(((uint16_t)x) >> 8U) & 0xFFU) + +#define USB_LONG_GET_BYTE0(x) ((uint8_t)(((uint32_t)(x))) & 0xFFU) +#define USB_LONG_GET_BYTE1(x) ((uint8_t)(((uint32_t)(x)) >> 8U) & 0xFFU) +#define USB_LONG_GET_BYTE2(x) ((uint8_t)(((uint32_t)(x)) >> 16U) & 0xFFU) +#define USB_LONG_GET_BYTE3(x) ((uint8_t)(((uint32_t)(x)) >> 24U) & 0xFFU) + +#define USB_MEM4_ALIGN_MASK (0x03U) + +/* accessory macro */ +#define USB_MEM4_ALIGN(n) ((n + 3U) & (0xFFFFFFFCu)) +#define USB_MEM32_ALIGN(n) ((n + 31U) & (0xFFFFFFE0u)) +#define USB_MEM64_ALIGN(n) ((n + 63U) & (0xFFFFFFC0u)) + +/* big/little endian */ +#define SWAP2BYTE_CONST(n) ((((n)&0x00FFU) << 8U) | (((n)&0xFF00U) >> 8U)) +#define SWAP4BYTE_CONST(n) \ + ((((n)&0x000000FFU) << 24U) | (((n)&0x0000FF00U) << 8U) | (((n)&0x00FF0000U) >> 8U) | (((n)&0xFF000000U) >> 24U)) + +#if (ENDIANNESS == BIG_ENDIAN) + +#define USB_SHORT_TO_LITTLE_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_TO_LITTLE_ENDIAN(n) SWAP4BYTE_CONST(n) +#define USB_SHORT_FROM_LITTLE_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_FROM_LITTLE_ENDIAN(n) SWAP2BYTE_CONST(n) + +#define USB_SHORT_TO_BIG_ENDIAN(n) (n) +#define USB_LONG_TO_BIG_ENDIAN(n) (n) +#define USB_SHORT_FROM_BIG_ENDIAN(n) (n) +#define USB_LONG_FROM_BIG_ENDIAN(n) (n) + +#define USB_LONG_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((n >> 24U) & 0xFFU); \ + m[1] = ((n >> 16U) & 0xFFU); \ + m[2] = ((n >> 8U) & 0xFFU); \ + m[3] = (n & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(n) \ + ((uint32_t)(((uint32_t)n[0] << 24U) | ((uint32_t)n[1] << 16U) | ((uint32_t)n[2] << 8U) | ((uint32_t)n[3] << 0U))) + +#define USB_LONG_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[3] = ((n >> 24U) & 0xFFU); \ + m[2] = ((n >> 16U) & 0xFFU); \ + m[1] = ((n >> 8U) & 0xFFU); \ + m[0] = (n & 0xFFU); \ + } + +#define USB_LONG_FROM_BIG_ENDIAN_ADDRESS(n) \ + ((uint32_t)(((uint32_t)n[3] << 24U) | ((uint32_t)n[2] << 16U) | ((uint32_t)n[1] << 8U) | ((uint32_t)n[0] << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((n >> 8U) & 0xFFU); \ + m[1] = (n & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(n) ((uint32_t)(((uint32_t)n[0] << 8U) | ((uint32_t)n[1] << 0U))) + +#define USB_SHORT_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[1] = ((n >> 8U) & 0xFFU); \ + m[0] = (n & 0xFFU); \ + } + +#define USB_SHORT_FROM_BIG_ENDIAN_ADDRESS(n) ((uint32_t)(((uint32_t)n[1] << 8U) | ((uint32_t)n[0] << 0U))) + +#else + +#define USB_SHORT_TO_LITTLE_ENDIAN(n) (n) +#define USB_LONG_TO_LITTLE_ENDIAN(n) (n) +#define USB_SHORT_FROM_LITTLE_ENDIAN(n) (n) +#define USB_LONG_FROM_LITTLE_ENDIAN(n) (n) + +#define USB_SHORT_TO_BIG_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_TO_BIG_ENDIAN(n) SWAP4BYTE_CONST(n) +#define USB_SHORT_FROM_BIG_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_FROM_BIG_ENDIAN(n) SWAP4BYTE_CONST(n) + +#define USB_LONG_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[3] = ((n >> 24U) & 0xFFU); \ + m[2] = ((n >> 16U) & 0xFFU); \ + m[1] = ((n >> 8U) & 0xFFU); \ + m[0] = (n & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(n) \ + ((uint32_t)(((uint32_t)n[3] << 24U) | ((uint32_t)n[2] << 16U) | ((uint32_t)n[1] << 8U) | ((uint32_t)n[0] << 0U))) + +#define USB_LONG_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((n >> 24U) & 0xFFU); \ + m[1] = ((n >> 16U) & 0xFFU); \ + m[2] = ((n >> 8U) & 0xFFU); \ + m[3] = (n & 0xFFU); \ + } + +#define USB_LONG_FROM_BIG_ENDIAN_ADDRESS(n) \ + ((uint32_t)(((uint32_t)n[0] << 24U) | ((uint32_t)n[1] << 16U) | ((uint32_t)n[2] << 8U) | ((uint32_t)n[3] << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[1] = ((n >> 8U) & 0xFFU); \ + m[0] = (n & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(n) ((uint32_t)(((uint32_t)n[1] << 8U) | ((uint32_t)n[0] << 0U))) + +#define USB_SHORT_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((n >> 8U) & 0xFFU); \ + m[1] = (n & 0xFFU); \ + } + +#define USB_SHORT_FROM_BIG_ENDIAN_ADDRESS(n) ((uint32_t)(((uint32_t)n[0] << 8U) | ((uint32_t)n[1] << 0U))) +#endif + +/* + * The following MACROs (USB_GLOBAL, USB_BDT, USB_RAM_ADDRESS_ALGINMENT_512) are only used for USB device stack. + * The USB device global variables are put into the section m_usb_global or m_usb_bdt by using the MACRO + * USB_GLOBAL and USB_BDT. In this way, the USB device global variables can be linked into USB dadicated RAM + * by changing the linker file. This feature can only be enabled when the USB dadicated RAM is not less than 2K Bytes. + */ +#if defined(__ICCARM__) + +#define USB_GLOBAL _Pragma("location = \"m_usb_global\"") +#define USB_BDT _Pragma("location = \"m_usb_bdt\"") +#define USB_RAM_ADDRESS_ALGINMENT_512 _Pragma("data_alignment = 512U") + +#elif defined(__CC_ARM) + +#define USB_GLOBAL __attribute__((section("m_usb_global"))) __attribute__((zero_init)) +#define USB_BDT __attribute__((section("m_usb_bdt"))) __attribute__((zero_init)) +#define USB_RAM_ADDRESS_ALGINMENT_512 __attribute__((aligned(512U))) + +#elif defined(__GNUC__) + +#define USB_GLOBAL __attribute__((section("m_usb_global"))) +#define USB_BDT __attribute__((section("m_usb_bdt"))) +#define USB_RAM_ADDRESS_ALGINMENT_512 __attribute__((aligned(512U))) + +#else +#error The tool-chain is not supported. +#endif + +#endif /* __USB_MISC_H__ */ diff --git a/usb_1.1.0/include/usb_spec.h b/usb_1.1.0/include/usb_spec.h new file mode 100644 index 0000000..108b0c8 --- /dev/null +++ b/usb_1.1.0/include/usb_spec.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_SPEC_H__ +#define __USB_SPEC_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* USB speed (the value cannot be changed because EHCI QH use the value directly)*/ +#define USB_SPEED_FULL (0x00U) +#define USB_SPEED_LOW (0x01U) +#define USB_SPEED_HIGH (0x02U) + +/* Set up packet structure */ +typedef struct _usb_setup_struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} usb_setup_struct_t; + +/* USB standard descriptor endpoint type */ +#define USB_ENDPOINT_CONTROL (0x00U) +#define USB_ENDPOINT_ISOCHRONOUS (0x01U) +#define USB_ENDPOINT_BULK (0x02U) +#define USB_ENDPOINT_INTERRUPT (0x03U) + +/* USB standard descriptor transfer direction (cannot change the value because iTD use the value directly) */ +#define USB_OUT (0U) +#define USB_IN (1U) + +/* USB standard descriptor length */ +#define USB_DESCRIPTOR_LENGTH_DEVICE (0x12U) +#define USB_DESCRIPTOR_LENGTH_CONFIGURE (0x09U) +#define USB_DESCRIPTOR_LENGTH_INTERFACE (0x09U) +#define USB_DESCRIPTOR_LENGTH_ENDPOINT (0x07U) +#define USB_DESCRIPTOR_LENGTH_DEVICE_QUALITIER (0x0AU) + +/* USB standard descriptor type */ +#define USB_DESCRIPTOR_TYPE_DEVICE (0x01U) +#define USB_DESCRIPTOR_TYPE_CONFIGURE (0x02U) +#define USB_DESCRIPTOR_TYPE_STRING (0x03U) +#define USB_DESCRIPTOR_TYPE_INTERFACE (0x04U) +#define USB_DESCRIPTOR_TYPE_ENDPOINT (0x05U) +#define USB_DESCRIPTOR_TYPE_DEVICE_QUALITIER (0x06U) +#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION (0x07U) +#define USB_DESCRIPTOR_TYPE_INTERFAACE_POWER (0x08U) +#define USB_DESCRIPTOR_TYPE_OTG (0x09U) +#define USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION (0x0BU) + +#define USB_DESCRIPTOR_TYPE_HID (0x21U) +#define USB_DESCRIPTOR_TYPE_HID_REPORT (0x22U) +#define USB_DESCRIPTOR_TYPE_HID_PHYSICAL (0x23U) + +/* USB standard request type */ +#define USB_REQUEST_TYPE_DIR_MASK (0x80U) +#define USB_REQUEST_TYPE_DIR_SHIFT (7U) +#define USB_REQUEST_TYPE_DIR_OUT (0x00U) +#define USB_REQUEST_TYPE_DIR_IN (0x80U) + +#define USB_REQUEST_TYPE_TYPE_MASK (0x60U) +#define USB_REQUEST_TYPE_TYPE_SHIFT (5U) +#define USB_REQUEST_TYPE_TYPE_STANDARD (0U) +#define USB_REQUEST_TYPE_TYPE_CLASS (0x20U) +#define USB_REQUEST_TYPE_TYPE_VENDOR (0x40U) + +#define USB_REQUEST_TYPE_RECIPIENT_MASK (0x1FU) +#define USB_REQUEST_TYPE_RECIPIENT_SHIFT (0U) +#define USB_REQUEST_TYPE_RECIPIENT_DEVICE (0x00U) +#define USB_REQUEST_TYPE_RECIPIENT_INTERFACE (0x01U) +#define USB_REQUEST_TYPE_RECIPIENT_ENDPOINT (0x02U) +#define USB_REQUEST_TYPE_RECIPIENT_OTHER (0x03U) + +/* USB standard request */ +#define USB_REQUEST_STANDARD_GET_STATUS (0x00U) +#define USB_REQUEST_STANDARD_CLEAR_FEATURE (0x01U) +#define USB_REQUEST_STANDARD_SET_FEATURE (0x03U) +#define USB_REQUEST_STANDARD_SET_ADDRESS (0x05U) +#define USB_REQUEST_STANDARD_GET_DESCRIPTOR (0x06U) +#define USB_REQUEST_STANDARD_SET_DESCRIPTOR (0x07U) +#define USB_REQUEST_STANDARD_GET_CONFIGURATION (0x08U) +#define USB_REQUEST_STANDARD_SET_CONFIGURATION (0x09U) +#define USB_REQUEST_STANDARD_GET_INTERFACE (0x0AU) +#define USB_REQUEST_STANDARD_SET_INTERFACE (0x0BU) +#define USB_REQUEST_STANDARD_SYNCH_FRAME (0x0CU) + +/* USB standard request GET Status */ +#define USB_REQUEST_STANDARD_GET_STATUS_DEVICE_SELF_POWERED_SHIFT (0U) +#define USB_REQUEST_STANDARD_GET_STATUS_DEVICE_REMOTE_WARKUP_SHIFT (1U) + +#define USB_REQUEST_STANDARD_GET_STATUS_ENDPOINT_HALT_MASK (0x01U) +#define USB_REQUEST_STANDARD_GET_STATUS_ENDPOINT_HALT_SHIFT (0U) + +/* USB standard request CLEAR/SET feature */ +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT (0U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP (1U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_TEST_MODE (2U) + +/* USB standard descriptor configure bmAttributes */ +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_D7_MASK (0x80U) +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_D7_SHIFT (7U) + +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_MASK (0x40U) +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_SHIFT (6U) + +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_REMOTE_WAKEUP_MASK (0x20U) +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_REMOTE_WAKEUP_SHIFT (5U) + +/* USB standard descriptor endpoint bmAttributes */ +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK (0x80U) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT (7U) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT (0U) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN (0x80U) + +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK (0x0FU) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_SHFIT (0U) + +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK (0x03U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_NUMBER_SHFIT (0U) + +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_MASK (0x0CU) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_SHFIT (2U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_NO_SYNC (0x00U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_ASYNC (0x04U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_ADAPTIVE (0x08U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_SYNC (0x0CU) + +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_MASK (0x30U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_SHFIT (4U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_DATA_ENDPOINT (0x00U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_FEEDBACK_ENDPOINT (0x10U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_IMPLICIT_FEEDBACK_DATA_ENDPOINT (0x20U) + +#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK (0x07FFu) +#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK (0x1800u) +#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_SHFIT (11U) + +/* Language structure */ +typedef struct _usb_language +{ + uint8_t **string; /* The Strings descriptor array */ + uint32_t *length; /* The strings descriptor length array */ + uint16_t languageId; /* The language id of current language */ +} usb_language_t; + +typedef struct _usb_language_list +{ + uint8_t *languageString; /* The String 0U pointer */ + uint32_t stringLength; /* The String 0U Length */ + usb_language_t *languageList; /* The language list */ + uint8_t count; /* The language count */ +} usb_language_list_t; + +typedef struct _usb_descriptor_common +{ + uint8_t bLength; /* Size of this descriptor in bytes */ + uint8_t bDescriptorType; /* DEVICE Descriptor Type */ + uint8_t bData[1]; /* Data */ +} usb_descriptor_common_t; + +typedef struct _usb_descriptor_device +{ + uint8_t bLength; /* Size of this descriptor in bytes */ + uint8_t bDescriptorType; /* DEVICE Descriptor Type */ + uint8_t bcdUSB[2]; /* UUSB Specification Release Number in Binary-Coded Decimal, e.g. 0x0200U */ + uint8_t bDeviceClass; /* Class code */ + uint8_t bDeviceSubClass; /* Sub-Class code */ + uint8_t bDeviceProtocol; /* Protocol code */ + uint8_t bMaxPacketSize0; /* Maximum packet size for endpoint zero */ + uint8_t idVendor[2]; /* Vendor ID (assigned by the USB-IF) */ + uint8_t idProduct[2]; /* Product ID (assigned by the manufacturer) */ + uint8_t bcdDevice[2]; /* Device release number in binary-coded decimal */ + uint8_t iManufacturer; /* Index of string descriptor describing manufacturer */ + uint8_t iProduct; /* Index of string descriptor describing product */ + uint8_t iSerialNumber; /* Index of string descriptor describing the device serial number */ + uint8_t bNumConfigurations; /* Number of possible configurations */ +} usb_descriptor_device_t; + +typedef struct _usb_descriptor_configuration +{ + uint8_t bLength; /* Descriptor size in bytes = 9U */ + uint8_t bDescriptorType; /* CONFIGURATION type = 2U or 7U */ + uint8_t wTotalLength[2]; /* Length of concatenated descriptors */ + uint8_t bNumInterfaces; /* Number of interfaces, this configuration. */ + uint8_t bConfigurationValue; /* Value to set this configuration. */ + uint8_t iConfiguration; /* Index to configuration string */ + uint8_t bmAttributes; /* Configuration characteristics */ + uint8_t bMaxPower; /* Maximum power from bus, 2 mA units */ +} usb_descriptor_configuration_t; + +typedef struct _usb_descriptor_interface +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} usb_descriptor_interface_t; + +typedef struct _usb_descriptor_endpoint +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint8_t wMaxPacketSize[2]; + uint8_t bInterval; +} usb_descriptor_endpoint_t; + +typedef union _usb_descriptor_union +{ + usb_descriptor_common_t common; /* Common descriptor */ + usb_descriptor_device_t device; /* Device descriptor */ + usb_descriptor_configuration_t configuration; /* Configuration descriptor */ + usb_descriptor_interface_t interface; /* Interface descriptor */ + usb_descriptor_endpoint_t endpoint; /* Endpoint descriptor */ +} usb_descriptor_union_t; + +#endif /* __USB_SPEC_H__ */ diff --git a/usb_1.1.0/osa/usb_osa.h b/usb_1.1.0/osa/usb_osa.h new file mode 100644 index 0000000..ee898c3 --- /dev/null +++ b/usb_1.1.0/osa/usb_osa.h @@ -0,0 +1,578 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_OSA_H__ +#define __USB_OSA_H__ + +/*! + * @addtogroup usb_os_abstraction + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Define big endian */ +#define BIG_ENDIAN (0U) +/*! @brief Define little endian */ +#define LITTLE_ENDIAN (1U) + +/*! @brief Define current endian */ +#define ENDIANNESS LITTLE_ENDIAN + +/*! @brief Define USB OSA event handle */ +typedef void *usb_osa_event_handle; + +/*! @brief Define USB OSA semaphore handle */ +typedef void *usb_osa_sem_handle; + +/*! @brief Define USB OSA mutex handle */ +typedef void *usb_osa_mutex_handle; + +/*! @brief Define USB OSA message queue handle */ +typedef void *usb_osa_msgq_handle; + +/*! @brief USB OSA error code */ +typedef enum _usb_osa_status +{ + kStatus_USB_OSA_Success = 0x00U, /*!< Success */ + kStatus_USB_OSA_Error, /*!< Failed */ + kStatus_USB_OSA_TimeOut, /*!< Timeout occurs while waiting */ +} usb_osa_status_t; + +/*! @brief The event flags are cleared automatically or manually.*/ +typedef enum _usb_osa_event_mode +{ + kUSB_OsaEventManualClear = 0U, /*!< The flags of the event is cleared manually. */ + kUSB_OsaEventAutoClear = 1U, /*!< The flags of the event is cleared automatically. */ +} usb_osa_event_mode_t; + +#define USB_STACK_FREERTOS +/* Include required header file based on RTOS selection */ +#if defined(USB_STACK_BM) + +#include "usb_osa_bm.h" + +#elif defined(USB_STACK_FREERTOS) + +#include "usb_osa_freertos.h" + +#elif defined(USB_STACK_UCOSII) + +#include "usb_osa_ucosii.h" + +#elif defined(USB_STACK_UCOSIII) + +#include "usb_osa_ucosiii.h" + +#else + +#error Not define RTOS in file "usb_osa.h". + +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name USB OSA Memory Management + * @{ + */ + +/*! + * @brief Reserves the requested amount of memory in bytes. + * + * The function is used to reserve the requested amount of memory in bytes and initializes it to 0. + * + * @param length Amount of bytes to reserve. + * + * @return Pointer to the reserved memory. NULL if memory can't be allocated. + */ +void *USB_OsaMemoryAllocate(uint32_t length); + +/*! + * @brief Frees the memory previously reserved. + * + * The function is used to free the memory block previously reserved. + * + * @param p Pointer to the start of the memory block previously reserved. + * + */ +extern void USB_OsaMemoryFree(void *p); + +/* @} */ + +/*! + * @name USB OSA Event + * @{ + */ + +/*! + * @brief Creates an event object with all flags cleared. + * + * This function creates an event object and sets its clear mode. If the clear mode + * is kUSB_OsaEventAutoClear, when a task gets the event flags, these flags are + * cleared automatically. If the clear mode is kUSB_OsaEventManualClear, the flags must + * be cleared manually. + * + * @param handle It is an out parameter, which is used to return the pointer of the event object. + * @param flag The event is auto-clear or manual-clear. See the enumeration #usb_osa_event_mode_t. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_event_handle eventHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaEventCreate(&eventHandle, kUSB_OsaEventManualClear); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventCreate(usb_osa_event_handle *handle, uint32_t flag); + +/*! + * @brief Destroys a created event object. + * + * @param handle Pointer to the event object. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaEventDestroy(eventHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventDestroy(usb_osa_event_handle handle); + +/*! + * @brief Sets an event flag. + * + * Sets specified flags for an event object. + * + * @param handle Pointer to the event object. + * @param bitMask Event flags to be set. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaEventSet(eventHandle, 0x01U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventSet(usb_osa_event_handle handle, uint32_t bitMask); + +/*! + * @brief Waits for an event flag. + * + * This function waits for a combination of flags to be set in an event object. + * An applications can wait for any/all bits to be set. This function can + * get the flags that wake up the waiting task. + * + * @param handle Pointer to the event object. + * @param bitMask Event flags to wait. + * @param flag Wait all flags or any flag to be set. 0U - wait any flag, others, wait all flags. + * @param timeout The maximum number of milliseconds to wait for the event. + * If the wait condition is not met, passing 0U + * waits indefinitely when the environment is an RTOS and returns the kStatus_OSA_Timeout + * immediately. Pass any value for the bare metal. + * @param bitSet Flags that wake up the waiting task are obtained by this parameter. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + uint32_t bitSet; + ... + usbOsaStatus = USB_OsaEventWait(eventHandle, 0x01U, 0U, 0U, &bitSet); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventWait( + usb_osa_event_handle handle, uint32_t bitMask, uint32_t flag, uint32_t timeout, uint32_t *bitSet); + +/*! + * @brief Checks an event flag. + * + * This function checks for a combination of flags to be set in an event object. + * + * @param handle Pointer to the event object. + * @param bitMask Event flags to check. + * @param bitSet Flags have been set. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + uint32_t bitSet; + ... + usbOsaStatus = USB_OsaEventCheck(eventHandle, 0x01U, &bitSet); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventCheck(usb_osa_event_handle handle, uint32_t bitMask, uint32_t *bitSet); + +/*! + * @brief Clears an event flag. + * + * This function clears flags of an event object. + * + * @param handle Pointer to the event object + * @param bitMask Event flags to be cleared. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaEventClear(eventHandle, 0x01U); + @endcode + */ +extern usb_osa_status_t USB_OsaEventClear(usb_osa_event_handle handle, uint32_t bitMask); +/* @} */ + +/*! + * @name USB OSA Semaphore + * @{ + */ + +/*! + * @brief Creates a semaphore with a given value. + * + * This function creates a semaphore and sets the default count. + * + * @param handle It is an out parameter, which is used to return pointer of the semaphore object. + * @param count Initializes a value of the semaphore. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaSemCreate(&semHandle, 1U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemCreate(usb_osa_sem_handle *handle, uint32_t count); + +/*! + * @brief Destroys a semaphore object. + * + * This function destroys a semaphore object. + * + * @param handle Pointer to the semaphore. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaSemDestroy(semHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemDestroy(usb_osa_sem_handle handle); + +/*! + * @brief Posts a semaphore. + * + * This function wakes up a task waiting on the semaphore. If a task is not pending, increases the semaphore's + value. + * + * @param handle Pointer to the semaphore. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaSemPost(semHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemPost(usb_osa_sem_handle handle); + +/*! + * @brief Waits on a semaphore. + * + * This function checks the semaphore's value. If it is positive, it decreases the semaphore's value and return + kStatus_OSA_Success. + * + * @param handle Pointer to the semaphore. + * @param timeout The maximum number of milliseconds to wait for the semaphore. + * If the wait condition is not met, pass 0U + * waits indefinitely when environment is RTOS. And return kStatus_OSA_Timeout + * immediately for bare metal no matter what value has been passed. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaSemWait(semHandle, 0U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemWait(usb_osa_sem_handle handle, uint32_t timeout); +/* @} */ + +/*! + * @name USB OSA Mutex + * @{ + */ + +/*! + * @brief Creates a mutex. + * + * This function creates a mutex and sets it to an unlocked status. + * + * @param handle It is out parameter, which is used to return the pointer of the mutex object. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaMutexCreate(&mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexCreate(usb_osa_mutex_handle *handle); + +/*! + * @brief Destroys a mutex. + * + * This function destroys a mutex and sets it to an unlocked status. + * + * @param handle Pointer to the mutex. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMutexDestroy(mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexDestroy(usb_osa_mutex_handle handle); + +/*! + * @brief Waits for a mutex and locks it. + * + * This function checks the mutex status. If it is unlocked, it locks it and returns the + * kStatus_OSA_Success. Otherwise, it waits forever to lock in RTOS and returns the + * kStatus_OSA_Success immediately for bare metal. + * + * @param handle Pointer to the mutex. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMutexLock(mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexLock(usb_osa_mutex_handle handle); + +/*! + * @brief Unlocks a mutex. + * + * This function unlocks a mutex. + * + * @param handle Pointer to the mutex. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMutexUnlock(mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexUnlock(usb_osa_mutex_handle handle); +/* @} */ + +/*! + * @name USB OSA Message Queue + * @{ + */ + +/*! + * @brief Creates a message queue. + * + * This function creates a message queue. + * + * @param handle It is an out parameter, which is used to return a pointer of the message queue object. + * @param count The count of elements in the queue. + * @param size Size of every elements in words. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaMsgqCreate(msgqHandle, 8U, 4U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqCreate(usb_osa_msgq_handle *handle, uint32_t count, uint32_t size); + +/*! + * @brief Destroys a message queue. + * + * This function destroys a message queue. + * + * @param handle Pointer to a message queue. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqDestroy(msgqHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqDestroy(usb_osa_msgq_handle handle); + +/*! + * @brief Sends a message. + * + * This function sends a message to the tail of the message queue. + * + * @param handle Pointer to a message queue. + * @param msg The pointer to a message to be put into the queue. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + message_struct_t message; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqSend(msgqHandle, &message); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqSend(usb_osa_msgq_handle handle, void *msg); + +/*! + * @brief Receives a message. + * + * This function receives a message from the head of the message queue. + * + * @param handle Pointer to a message queue. + * @param msg The pointer to save a received message. + * @param timeout The maximum number of milliseconds to wait for a message. + * If the wait condition is not met, passing 0U + * waits indefinitely when an environment is RTOS and returns the kStatus_OSA_Timeout + * immediately for bare metal. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + message_struct_t message; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqRecv(msgqHandle, &message, 0U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqRecv(usb_osa_msgq_handle handle, void *msg, uint32_t timeout); + +/*! + * @brief Checks a message queue and receives a message if the queue is not empty. + * + * This function checks a message queue and receives a message if the queue is not empty. + * + * @param handle Pointer to a message queue. + * @param msg The pointer to save a received message. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + message_struct_t message; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqCheck(msgqHandle, &message); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqCheck(usb_osa_msgq_handle handle, void *msg); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/* @} */ + +#endif /* __USB_OSA_H__ */ diff --git a/usb_1.1.0/osa/usb_osa_bm.c b/usb_1.1.0/osa/usb_osa_bm.c new file mode 100644 index 0000000..01e45ff --- /dev/null +++ b/usb_1.1.0/osa/usb_osa_bm.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "stdint.h" +#include "usb.h" +#include "usb_osa.h" +#include "stdlib.h" +#include "fsl_device_registers.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define USB_OSA_BM_EVENT_COUNT (2U) +#define USB_OSA_BM_SEM_COUNT (1U) +#define USB_OSA_BM_MSGQ_COUNT (1U) +#define USB_OSA_BM_MSG_COUNT (8U) +#define USB_OSA_BM_MSG_SIZE (4U) + +/* BM Event status structure */ +typedef struct _usb_osa_event_struct +{ + uint32_t value; /* Event mask */ + uint32_t flag; /* Event flags, includes auto clear flag */ + uint8_t isUsed; /* Is used */ +} usb_osa_event_struct_t; + +/* BM semaphore status structure */ +typedef struct _usb_osa_sem_struct +{ + uint32_t value; /* Semaphore count */ + uint8_t isUsed; /* Is used */ +} usb_osa_sem_struct_t; + +/* BM msg status structure */ +typedef struct _usb_osa_msg_struct +{ + uint32_t msg[USB_OSA_BM_MSG_SIZE]; /* Message entity pointer */ +} usb_osa_msg_struct_t; + +/* BM msgq status structure */ +typedef struct _usb_osa_msgq_struct +{ + usb_osa_msg_struct_t msgs[USB_OSA_BM_MSG_COUNT]; /* Message entity list */ + uint32_t count; /* Max message entity count */ + uint32_t msgSize; /* Size of each message */ + uint32_t msgCount; /* Valid messages */ + uint32_t index; /* The first empty message entity index */ + uint32_t current; /* The vaild message index */ + uint8_t isUsed; /* Is used */ +} usb_osa_msgq_struct_t; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +USB_GLOBAL static usb_osa_sem_struct_t s_UsbBmSemStruct[USB_OSA_BM_SEM_COUNT]; +USB_GLOBAL static usb_osa_event_struct_t s_UsbBmEventStruct[USB_OSA_BM_EVENT_COUNT]; +USB_GLOBAL static usb_osa_msgq_struct_t s_UsbBmMsgqStruct[USB_OSA_BM_MSGQ_COUNT]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +void *USB_OsaMemoryAllocate(uint32_t length) +{ + void *p = (void *)malloc(length); + uint8_t *temp = (uint8_t *)p; + if (p) + { + for (uint32_t count = 0U; count < length; count++) + { + temp[count] = 0U; + } + } + return p; +} + +void USB_OsaMemoryFree(void *p) +{ + free(p); +} + +void USB_OsaEnterCritical(uint8_t *sr) +{ + *sr = __get_PRIMASK(); + __ASM("CPSID I"); +} + +void USB_OsaExitCritical(uint8_t sr) +{ + __set_PRIMASK(sr); +} + +usb_osa_status_t USB_OsaEventCreate(usb_osa_event_handle *handle, uint32_t flag) +{ + usb_osa_event_struct_t *event = NULL; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + for (uint32_t i = 0; i < USB_OSA_BM_EVENT_COUNT; i++) + { + if (0 == s_UsbBmEventStruct[i].isUsed) + { + event = &s_UsbBmEventStruct[i]; + break; + } + } + + if (NULL == event) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + event->value = 0U; + event->flag = flag; + event->isUsed = 1; + *handle = event; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaEventDestroy(usb_osa_event_handle handle) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + event->isUsed = 0; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventSet(usb_osa_event_handle handle, uint32_t bitMask) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + event->value |= bitMask; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventWait( + usb_osa_event_handle handle, uint32_t bitMask, uint32_t flag, uint32_t timeout, uint32_t *bitSet) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + uint32_t bits; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + bits = event->value & bitMask; + if (flag) + { + if (bits != bitMask) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + } + else + { + if (!bits) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + } + if (bitSet) + { + *bitSet = bits; + } + if (event->flag) + { + event->value &= ~bits; + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventCheck(usb_osa_event_handle handle, uint32_t bitMask, uint32_t *bitSet) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + uint32_t bits; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + bits = event->value & bitMask; + + if (!bits) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + if (bitSet) + { + *bitSet = bits; + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventClear(usb_osa_event_handle handle, uint32_t bitMask) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + uint32_t bits; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + bits = event->value & bitMask; + event->value &= ~bits; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaSemCreate(usb_osa_sem_handle *handle, uint32_t count) +{ + usb_osa_sem_struct_t *sem = NULL; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + for (uint32_t i = 0; i < USB_OSA_BM_SEM_COUNT; i++) + { + if (0 == s_UsbBmSemStruct[i].isUsed) + { + sem = &s_UsbBmSemStruct[i]; + break; + } + } + if (NULL == sem) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + sem->value = count; + sem->isUsed = 1; + *handle = sem; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaSemDestroy(usb_osa_sem_handle handle) +{ + usb_osa_sem_struct_t *sem = (usb_osa_sem_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + sem->isUsed = 0; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaSemPost(usb_osa_sem_handle handle) +{ + usb_osa_sem_struct_t *sem = (usb_osa_sem_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + sem->value++; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaSemWait(usb_osa_sem_handle handle, uint32_t timeout) +{ + usb_osa_sem_struct_t *sem = (usb_osa_sem_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + if (sem->value) + { + sem->value--; + } + else + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexCreate(usb_osa_mutex_handle *handle) +{ + if (!handle) + { + return kStatus_USB_OSA_Error; + } + *handle = (usb_osa_mutex_handle)0xFFFF0000U; + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexDestroy(usb_osa_mutex_handle handle) +{ + return kStatus_USB_OSA_Success; +} +usb_osa_status_t USB_OsaMutexLock(usb_osa_mutex_handle handle) +{ + return kStatus_USB_OSA_Success; +} +usb_osa_status_t USB_OsaMutexUnlock(usb_osa_mutex_handle handle) +{ + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqCreate(usb_osa_msgq_handle *handle, uint32_t count, uint32_t size) +{ + usb_osa_msgq_struct_t *msgq = NULL; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + + for (uint32_t i = 0; i < USB_OSA_BM_MSGQ_COUNT; i++) + { + if (0 == s_UsbBmMsgqStruct[i].isUsed) + { + msgq = &s_UsbBmMsgqStruct[i]; + break; + } + } + if ((NULL == msgq) || (count > USB_OSA_BM_MSG_COUNT) || (size > USB_OSA_BM_MSG_SIZE)) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + msgq->count = count; + msgq->msgSize = size; + msgq->msgCount = 0U; + msgq->index = 0U; + msgq->current = 0U; + msgq->isUsed = 1; + *handle = msgq; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqDestroy(usb_osa_msgq_handle handle) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + msgq->isUsed = 0; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqSend(usb_osa_msgq_handle handle, void *msg) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + usb_osa_msg_struct_t *msgEntity; + uint32_t *p; + uint32_t *q; + uint32_t count; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + if (msgq->msgCount >= msgq->count) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + msgEntity = &msgq->msgs[msgq->index]; + p = (uint32_t *)&msgEntity->msg[0]; + q = (uint32_t *)msg; + + for (count = 0U; count < msgq->msgSize; count++) + { + p[count] = q[count]; + } + + if (0U == msgq->msgCount) + { + msgq->current = msgq->index; + } + + msgq->msgCount++; + msgq->index++; + msgq->index = msgq->index % msgq->count; + + USB_OSA_EXIT_CRITICAL(); + + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqRecv(usb_osa_msgq_handle handle, void *msg, uint32_t timeout) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + usb_osa_msg_struct_t *msgEntity; + uint32_t *p; + uint32_t *q; + uint32_t count; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + if (msgq->msgCount < 1U) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + + msgEntity = &msgq->msgs[msgq->current]; + q = (uint32_t *)&msgEntity->msg[0]; + p = (uint32_t *)msg; + + for (count = 0U; count < msgq->msgSize; count++) + { + p[count] = q[count]; + } + + msgq->msgCount--; + msgq->current++; + msgq->current = msgq->current % msgq->count; + + USB_OSA_EXIT_CRITICAL(); + + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqCheck(usb_osa_msgq_handle handle, void *msg) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + uint32_t msgCount; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + msgCount = msgq->msgCount; + USB_OSA_EXIT_CRITICAL(); + + if (msgCount) + { + if (kStatus_USB_OSA_Success == USB_OsaMsgqRecv(msgq, msg, 0U)) + { + return kStatus_USB_OSA_Success; + } + } + + return kStatus_USB_OSA_Error; +} diff --git a/usb_1.1.0/osa/usb_osa_bm.h b/usb_1.1.0/osa/usb_osa_bm.h new file mode 100644 index 0000000..e3232d3 --- /dev/null +++ b/usb_1.1.0/osa/usb_osa_bm.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_OSA_BM_H__ +#define __USB_OSA_BM_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define USB_OSA_SR_ALLOC() uint8_t usbOsaCurrentSr; +#define USB_OSA_ENTER_CRITICAL() USB_OsaEnterCritical(&usbOsaCurrentSr) +#define USB_OSA_EXIT_CRITICAL() USB_OsaExitCritical(usbOsaCurrentSr) + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +extern void USB_OsaEnterCritical(uint8_t *sr); +extern void USB_OsaExitCritical(uint8_t sr); + +#if defined(__cplusplus) +} +#endif + +#endif /* __USB_OSA_BM_H__ */ diff --git a/usb_1.1.0/osa/usb_osa_freertos.c b/usb_1.1.0/osa/usb_osa_freertos.c new file mode 100644 index 0000000..0fcaabb --- /dev/null +++ b/usb_1.1.0/osa/usb_osa_freertos.c @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stdint.h" +#include "fsl_device_registers.h" +#include "usb.h" +#include "usb_osa.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define MSEC_TO_TICK(msec) ((1000L + ((uint32_t)configTICK_RATE_HZ * (uint32_t)(msec - 1U))) / 1000L) +#define TICKS_TO_MSEC(tick) ((tick)*1000uL / (uint32_t)configTICK_RATE_HZ) + +/* FreeRTOS Event status structure */ +typedef struct _usb_osa_event_struct +{ + EventGroupHandle_t handle; /* The event handle */ + uint32_t flag; /* Event flags, includes auto clear flag */ +} usb_osa_event_struct_t; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +void *USB_OsaMemoryAllocate(uint32_t length) +{ + void *p = (void *)pvPortMalloc(length); + uint8_t *temp = (uint8_t *)p; + if (p) + { + for (uint32_t count = 0U; count < length; count++) + { + temp[count] = 0U; + } + } + return p; +} + +void USB_OsaMemoryFree(void *p) +{ + vPortFree(p); +} +void USB_OsaEnterCritical(uint8_t *sr) +{ + if (__get_IPSR()) + { + *sr = portSET_INTERRUPT_MASK_FROM_ISR(); + } + else + { + portENTER_CRITICAL(); + } +} + +void USB_OsaExitCritical(uint8_t sr) +{ + if (__get_IPSR()) + { + portCLEAR_INTERRUPT_MASK_FROM_ISR(sr); + } + else + { + portEXIT_CRITICAL(); + } +} + +usb_osa_status_t USB_OsaEventCreate(usb_osa_event_handle *handle, uint32_t flag) +{ + usb_osa_event_struct_t *event; + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + event = (usb_osa_event_struct_t *)USB_OsaMemoryAllocate(sizeof(usb_osa_event_struct_t)); + if (NULL == event) + { + return kStatus_USB_OSA_Error; + } + + event->handle = xEventGroupCreate(); + if (NULL == event->handle) + { + USB_OsaMemoryFree(event); + return kStatus_USB_OSA_Error; + } + event->flag = flag; + *handle = event; + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaEventDestroy(usb_osa_event_handle handle) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + if (handle) + { + if (event->handle) + { + vEventGroupDelete(event->handle); + } + USB_OsaMemoryFree(handle); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventSet(usb_osa_event_handle handle, uint32_t bitMask) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + portBASE_TYPE taskToWake = pdFALSE; + if (handle) + { + if (__get_IPSR()) + { + if (pdPASS == xEventGroupSetBitsFromISR(event->handle, (EventBits_t)bitMask, &taskToWake)) + { + portYIELD_FROM_ISR(taskToWake); + } + } + else + { + xEventGroupSetBits(event->handle, (EventBits_t)bitMask); + } + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventWait( + usb_osa_event_handle handle, uint32_t bitMask, uint32_t flag, uint32_t timeout, uint32_t *bitSet) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + BaseType_t autoClear; + EventBits_t bits; + + if (handle) + { + if (!timeout) + { + timeout = portMAX_DELAY; + } + else + { + timeout = MSEC_TO_TICK(timeout); + } + + if (event->flag) + { + autoClear = pdTRUE; + } + else + { + autoClear = pdFALSE; + } + + bits = xEventGroupWaitBits(event->handle, (EventBits_t)bitMask, autoClear, (BaseType_t)flag, timeout); + + if (bitSet) + { + *bitSet = bits & ((EventBits_t)bitMask); + if (*bitSet) + { + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_TimeOut; + } + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventCheck(usb_osa_event_handle handle, uint32_t bitMask, uint32_t *bitSet) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + EventBits_t bits; + + if (handle) + { + if (__get_IPSR()) + { + bits = xEventGroupGetBitsFromISR(event->handle); + } + else + { + bits = xEventGroupGetBits(event->handle); + } + bits = (bits & bitMask); + if (bits) + { + if (bitSet) + { + *bitSet = bits & ((EventBits_t)bitMask); + } + return kStatus_USB_OSA_Success; + } + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventClear(usb_osa_event_handle handle, uint32_t bitMask) +{ + EventBits_t ev; + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + + if (handle) + { + if (__get_IPSR()) + { + xEventGroupClearBitsFromISR(event->handle, (EventBits_t)bitMask); + } + else + { + ev = xEventGroupClearBits(event->handle, (EventBits_t)bitMask); + if (ev == 0) + { + return kStatus_USB_OSA_Error; + } + } + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaSemCreate(usb_osa_sem_handle *handle, uint32_t count) +{ + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + *handle = (usb_osa_sem_handle)xSemaphoreCreateCounting(0xFFU, count); + if (NULL == (*handle)) + { + return kStatus_USB_OSA_Error; + } + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaSemDestroy(usb_osa_sem_handle handle) +{ + if (handle) + { + vSemaphoreDelete(handle); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaSemPost(usb_osa_sem_handle handle) +{ + xSemaphoreHandle sem = (xSemaphoreHandle)handle; + portBASE_TYPE taskToWake = pdFALSE; + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + if (__get_IPSR()) + { + if (pdPASS == xSemaphoreGiveFromISR(sem, &taskToWake)) + { + portYIELD_FROM_ISR(taskToWake); + return kStatus_USB_OSA_Success; + } + } + else + { + if (pdTRUE == xSemaphoreGive(sem)) + { + return kStatus_USB_OSA_Success; + } + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaSemWait(usb_osa_sem_handle handle, uint32_t timeout) +{ + xSemaphoreHandle sem = (xSemaphoreHandle)handle; + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + if (!timeout) + { + timeout = portMAX_DELAY; + } + else + { + timeout = MSEC_TO_TICK(timeout); + } + + if (pdFALSE == xSemaphoreTake(sem, timeout)) + { + return kStatus_USB_OSA_TimeOut; + } + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexCreate(usb_osa_mutex_handle *handle) +{ + if (!handle) + { + return kStatus_USB_OSA_Error; + } + *handle = (usb_osa_mutex_handle)xSemaphoreCreateRecursiveMutex(); + if (NULL == *handle) + { + return kStatus_USB_OSA_Error; + } + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexDestroy(usb_osa_mutex_handle handle) +{ + if (!handle) + { + return kStatus_USB_OSA_Error; + } + vSemaphoreDelete((xSemaphoreHandle)handle); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexLock(usb_osa_mutex_handle handle) +{ + xSemaphoreHandle mutex = (xSemaphoreHandle)handle; + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + if (xSemaphoreTakeRecursive(mutex, portMAX_DELAY) == pdFALSE) + { + return kStatus_USB_OSA_TimeOut; + } + + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexUnlock(usb_osa_mutex_handle handle) +{ + xSemaphoreHandle mutex = (xSemaphoreHandle)handle; + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + if (xSemaphoreGiveRecursive(mutex) == pdFALSE) + { + return kStatus_USB_OSA_Error; + } + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqCreate(usb_osa_msgq_handle *handle, uint32_t count, uint32_t size) +{ + if (!handle) + { + return kStatus_USB_OSA_Error; + } + *handle = xQueueCreate(count, size * sizeof(uint32_t)); + if (NULL == *handle) + { + return kStatus_USB_OSA_Error; + } + + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqDestroy(usb_osa_msgq_handle handle) +{ + if (!handle) + { + return kStatus_USB_OSA_Error; + } + vQueueDelete((xQueueHandle)handle); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqSend(usb_osa_msgq_handle handle, void *msg) +{ + xQueueHandle msgq = (xQueueHandle)handle; + portBASE_TYPE taskToWake = pdFALSE; + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + if (__get_IPSR()) + { + if (pdPASS == xQueueSendToBackFromISR(msgq, msg, &taskToWake)) + { + portYIELD_FROM_ISR(taskToWake); + return kStatus_USB_OSA_Success; + } + } + else + { + if (pdPASS == xQueueSendToBack(msgq, msg, 0U)) + { + return kStatus_USB_OSA_Success; + } + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaMsgqRecv(usb_osa_msgq_handle handle, void *msg, uint32_t timeout) +{ + xQueueHandle msgq = (xQueueHandle)handle; + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + if (!timeout) + { + timeout = portMAX_DELAY; + } + else + { + timeout = MSEC_TO_TICK(timeout); + } + if (pdPASS != xQueueReceive(msgq, msg, timeout)) + { + return kStatus_USB_OSA_TimeOut; + } + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqCheck(usb_osa_msgq_handle handle, void *msg) +{ + xQueueHandle msgq = (xQueueHandle)handle; + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + if (uxQueueMessagesWaiting(msgq)) + { + if (pdPASS == xQueueReceive(msgq, msg, 1U)) + { + return kStatus_USB_OSA_Success; + } + } + + return kStatus_USB_OSA_Error; +} diff --git a/usb_1.1.0/osa/usb_osa_freertos.h b/usb_1.1.0/osa/usb_osa_freertos.h new file mode 100644 index 0000000..b6f7bb1 --- /dev/null +++ b/usb_1.1.0/osa/usb_osa_freertos.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USB_OSA_FREERTOS_H__ +#define __USB_OSA_FREERTOS_H__ + +#if defined(__IAR_SYSTEMS_ICC__) +/** + * Workaround to disable MISRA C message suppress warnings for IAR compiler. + * http://supp.iar.com/Support/?note=24725 + */ +#define MISRAC_DISABLE \ + _Pragma( \ + "diag_suppress= \ + Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,Pm011,\ + Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\ + Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\ + Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\ + Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\ + Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\ + Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\ + Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\ + Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\ + Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\ + Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\ + Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\ + Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\ + Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\ + Pm155") + +#define MISRAC_ENABLE \ + _Pragma( \ + "diag_default= \ + Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,Pm011,\ + Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\ + Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\ + Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\ + Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\ + Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\ + Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\ + Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\ + Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\ + Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\ + Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\ + Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\ + Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\ + Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\ + Pm155") +#else +/* Empty MISRA C macros for other toolchains. */ +#define MISRAC_DISABLE +#define MISRAC_ENABLE +#endif + +MISRAC_DISABLE +#include "FreeRTOS.h" +#include "semphr.h" +#include "event_groups.h" +MISRAC_ENABLE + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define USB_OSA_SR_ALLOC() uint8_t usbOsaCurrentSr; +#define USB_OSA_ENTER_CRITICAL() USB_OsaEnterCritical(&usbOsaCurrentSr) +#define USB_OSA_EXIT_CRITICAL() USB_OsaExitCritical(usbOsaCurrentSr) + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +extern void USB_OsaEnterCritical(uint8_t *sr); +extern void USB_OsaExitCritical(uint8_t sr); + +#if defined(__cplusplus) +} +#endif + +#endif /* __USB_OSA_FREERTOS_H__ */ -- cgit v1.2.3