Coding standards
This commit is contained in:
parent
19af90face
commit
3a1b6fe8c1
43 changed files with 2033 additions and 2344 deletions
|
@ -231,7 +231,7 @@ void HardFault_HandlerC(unsigned long *sp, unsigned long lr, unsigned long cause
|
||||||
|
|
||||||
// Reset controller
|
// Reset controller
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
while(1) { WDT_Restart(WDT); }
|
for (;;) WDT_Restart(WDT);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((naked)) void NMI_Handler(void) {
|
__attribute__((naked)) void NMI_Handler(void) {
|
||||||
|
|
|
@ -95,7 +95,7 @@ void u8g_SetPILevel_DUE_hw_spi(u8g_t *u8g, uint8_t pin_index, uint8_t level) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8g_com_HAL_DUE_shared_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
|
uint8_t u8g_com_HAL_DUE_shared_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_COM_MSG_STOP:
|
case U8G_COM_MSG_STOP:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,7 @@ void HardFault_HandlerC(unsigned long *sp, unsigned long lr, unsigned long cause
|
||||||
// Reset controller
|
// Reset controller
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
|
|
||||||
while(1) { watchdog_init(); }
|
for (;;) watchdog_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -45,12 +45,11 @@
|
||||||
#define OUTPUT 1
|
#define OUTPUT 1
|
||||||
#define INPUT_PULLUP 2
|
#define INPUT_PULLUP 2
|
||||||
|
|
||||||
|
|
||||||
uint8_t LPC1768_PIN_PORT(const uint8_t pin);
|
uint8_t LPC1768_PIN_PORT(const uint8_t pin);
|
||||||
uint8_t LPC1768_PIN_PIN(const uint8_t pin);
|
uint8_t LPC1768_PIN_PIN(const uint8_t pin);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// I/O functions
|
// I/O functions
|
||||||
|
@ -63,22 +62,21 @@ void pinMode_LCD(uint8_t pin, uint8_t mode) {
|
||||||
PINSEL_FUNC_0,
|
PINSEL_FUNC_0,
|
||||||
PINSEL_PINMODE_TRISTATE,
|
PINSEL_PINMODE_TRISTATE,
|
||||||
PINSEL_PINMODE_NORMAL };
|
PINSEL_PINMODE_NORMAL };
|
||||||
switch(mode) {
|
switch (mode) {
|
||||||
case INPUT:
|
case INPUT:
|
||||||
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR &= ~LPC_PIN(LPC1768_PIN_PIN(pin));
|
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR &= ~LPC_PIN(LPC1768_PIN_PIN(pin));
|
||||||
PINSEL_ConfigPin(&config);
|
PINSEL_ConfigPin(&config);
|
||||||
break;
|
break;
|
||||||
case OUTPUT:
|
case OUTPUT:
|
||||||
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR |= LPC_PIN(LPC1768_PIN_PIN(pin));
|
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR |= LPC_PIN(LPC1768_PIN_PIN(pin));
|
||||||
PINSEL_ConfigPin(&config);
|
PINSEL_ConfigPin(&config);
|
||||||
break;
|
break;
|
||||||
case INPUT_PULLUP:
|
case INPUT_PULLUP:
|
||||||
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR &= ~LPC_PIN(LPC1768_PIN_PIN(pin));
|
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR &= ~LPC_PIN(LPC1768_PIN_PIN(pin));
|
||||||
config.Pinmode = PINSEL_PINMODE_PULLUP;
|
config.Pinmode = PINSEL_PINMODE_PULLUP;
|
||||||
PINSEL_ConfigPin(&config);
|
PINSEL_ConfigPin(&config);
|
||||||
break;
|
break;
|
||||||
default:
|
default: break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +103,6 @@ uint8_t u8g_GetPinLevel(uint8_t pin) {
|
||||||
return (uint32_t)LPC_GPIO(LPC1768_PIN_PORT(pin))->FIOPIN & LPC_PIN(LPC1768_PIN_PIN(pin)) ? 1 : 0;
|
return (uint32_t)LPC_GPIO(LPC1768_PIN_PORT(pin))->FIOPIN & LPC_PIN(LPC1768_PIN_PIN(pin)) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -95,9 +95,8 @@ uint8_t u8g_com_ssd_I2C_start_sequence(u8g_t *u8g) {
|
||||||
if (u8g->pin_list[U8G_PI_SET_A0] == 0) return 1;
|
if (u8g->pin_list[U8G_PI_SET_A0] == 0) return 1;
|
||||||
|
|
||||||
/* setup bus, might be a repeated start */
|
/* setup bus, might be a repeated start */
|
||||||
if (u8g_i2c_start(I2C_SLA) == 0)
|
if (u8g_i2c_start(I2C_SLA) == 0) return 0;
|
||||||
return 0;
|
if (u8g->pin_list[U8G_PI_A0_STATE] == 0) {
|
||||||
if (u8g->pin_list[U8G_PI_A0_STATE] == 0 ) {
|
|
||||||
if (u8g_i2c_send_byte(I2C_CMD_MODE) == 0) return 0;
|
if (u8g_i2c_send_byte(I2C_CMD_MODE) == 0) return 0;
|
||||||
}
|
}
|
||||||
else if (u8g_i2c_send_byte(I2C_DATA_MODE) == 0)
|
else if (u8g_i2c_send_byte(I2C_DATA_MODE) == 0)
|
||||||
|
@ -108,7 +107,7 @@ uint8_t u8g_com_ssd_I2C_start_sequence(u8g_t *u8g) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8g_com_HAL_LPC1768_ssd_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
|
uint8_t u8g_com_HAL_LPC1768_ssd_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_COM_MSG_INIT:
|
case U8G_COM_MSG_INIT:
|
||||||
//u8g_com_arduino_digital_write(u8g, U8G_PI_SCL, HIGH);
|
//u8g_com_arduino_digital_write(u8g, U8G_PI_SCL, HIGH);
|
||||||
//u8g_com_arduino_digital_write(u8g, U8G_PI_SDA, HIGH);
|
//u8g_com_arduino_digital_write(u8g, U8G_PI_SDA, HIGH);
|
||||||
|
|
|
@ -91,7 +91,7 @@ static void u8g_com_LPC1768_st7920_write_byte_hw_spi(uint8_t rs, uint8_t val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8g_com_HAL_LPC1768_ST7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
|
uint8_t u8g_com_HAL_LPC1768_ST7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_COM_MSG_INIT:
|
case U8G_COM_MSG_INIT:
|
||||||
u8g_SetPILevel(u8g, U8G_PI_CS, 0);
|
u8g_SetPILevel(u8g, U8G_PI_CS, 0);
|
||||||
u8g_SetPIOutput(u8g, U8G_PI_CS);
|
u8g_SetPIOutput(u8g, U8G_PI_CS);
|
||||||
|
|
|
@ -89,10 +89,8 @@ static void u8g_com_LPC1768_st7920_write_byte_sw_spi(uint8_t rs, uint8_t val) {
|
||||||
swSpiTransfer(val << 4, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL);
|
swSpiTransfer(val << 4, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8g_com_HAL_LPC1768_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
|
uint8_t u8g_com_HAL_LPC1768_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
|
||||||
{
|
switch (msg) {
|
||||||
switch(msg)
|
|
||||||
{
|
|
||||||
case U8G_COM_MSG_INIT:
|
case U8G_COM_MSG_INIT:
|
||||||
SCK_pin_ST7920_HAL = u8g->pin_list[U8G_PI_SCK];
|
SCK_pin_ST7920_HAL = u8g->pin_list[U8G_PI_SCK];
|
||||||
MOSI_pin_ST7920_HAL_HAL = u8g->pin_list[U8G_PI_MOSI];
|
MOSI_pin_ST7920_HAL_HAL = u8g->pin_list[U8G_PI_MOSI];
|
||||||
|
|
|
@ -72,7 +72,7 @@ static void u8g_sw_spi_HAL_LPC1768_shift_out(uint8_t dataPin, uint8_t clockPin,
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
|
uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_COM_MSG_INIT:
|
case U8G_COM_MSG_INIT:
|
||||||
u8g_SetPIOutput(u8g, U8G_PI_SCK);
|
u8g_SetPIOutput(u8g, U8G_PI_SCK);
|
||||||
u8g_SetPIOutput(u8g, U8G_PI_MOSI);
|
u8g_SetPIOutput(u8g, U8G_PI_MOSI);
|
||||||
|
|
|
@ -58,7 +58,7 @@ uint8_t u8g_com_stm32duino_fsmc_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, voi
|
||||||
|
|
||||||
static uint8_t isCommand;
|
static uint8_t isCommand;
|
||||||
|
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_COM_MSG_STOP:
|
case U8G_COM_MSG_STOP:
|
||||||
break;
|
break;
|
||||||
case U8G_COM_MSG_INIT:
|
case U8G_COM_MSG_INIT:
|
||||||
|
@ -154,7 +154,7 @@ void LCD_IO_Init(uint8_t cs, uint8_t rs) {
|
||||||
if (fsmcInit) return;
|
if (fsmcInit) return;
|
||||||
fsmcInit = 1;
|
fsmcInit = 1;
|
||||||
|
|
||||||
switch(cs) {
|
switch (cs) {
|
||||||
case FSMC_CS_NE1: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION1; break;
|
case FSMC_CS_NE1: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION1; break;
|
||||||
case FSMC_CS_NE2: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION2; break;
|
case FSMC_CS_NE2: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION2; break;
|
||||||
case FSMC_CS_NE3: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION3; break;
|
case FSMC_CS_NE3: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION3; break;
|
||||||
|
@ -164,7 +164,7 @@ void LCD_IO_Init(uint8_t cs, uint8_t rs) {
|
||||||
|
|
||||||
#define _ORADDR(N) controllerAddress |= (_BV32(N) - 2)
|
#define _ORADDR(N) controllerAddress |= (_BV32(N) - 2)
|
||||||
|
|
||||||
switch(rs) {
|
switch (rs) {
|
||||||
case FSMC_RS_A0: _ORADDR( 1); break;
|
case FSMC_RS_A0: _ORADDR( 1); break;
|
||||||
case FSMC_RS_A1: _ORADDR( 2); break;
|
case FSMC_RS_A1: _ORADDR( 2); break;
|
||||||
case FSMC_RS_A2: _ORADDR( 3); break;
|
case FSMC_RS_A2: _ORADDR( 3); break;
|
||||||
|
|
|
@ -71,7 +71,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_timer_enable_interrupt(const uint8_t timer_num) {
|
void HAL_timer_enable_interrupt(const uint8_t timer_num) {
|
||||||
switch(timer_num) {
|
switch (timer_num) {
|
||||||
case 0: NVIC_ENABLE_IRQ(IRQ_FTM0); break;
|
case 0: NVIC_ENABLE_IRQ(IRQ_FTM0); break;
|
||||||
case 1: NVIC_ENABLE_IRQ(IRQ_FTM1); break;
|
case 1: NVIC_ENABLE_IRQ(IRQ_FTM1); break;
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_timer_isr_prologue(const uint8_t timer_num) {
|
void HAL_timer_isr_prologue(const uint8_t timer_num) {
|
||||||
switch(timer_num) {
|
switch (timer_num) {
|
||||||
case 0:
|
case 0:
|
||||||
FTM0_CNT = 0x0000;
|
FTM0_CNT = 0x0000;
|
||||||
FTM0_SC &= ~FTM_SC_TOF; // Clear FTM Overflow flag
|
FTM0_SC &= ~FTM_SC_TOF; // Clear FTM Overflow flag
|
||||||
|
|
|
@ -72,7 +72,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_timer_enable_interrupt(const uint8_t timer_num) {
|
void HAL_timer_enable_interrupt(const uint8_t timer_num) {
|
||||||
switch(timer_num) {
|
switch (timer_num) {
|
||||||
case 0: NVIC_ENABLE_IRQ(IRQ_FTM0); break;
|
case 0: NVIC_ENABLE_IRQ(IRQ_FTM0); break;
|
||||||
case 1: NVIC_ENABLE_IRQ(IRQ_FTM1); break;
|
case 1: NVIC_ENABLE_IRQ(IRQ_FTM1); break;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_timer_isr_prologue(const uint8_t timer_num) {
|
void HAL_timer_isr_prologue(const uint8_t timer_num) {
|
||||||
switch(timer_num) {
|
switch (timer_num) {
|
||||||
case 0:
|
case 0:
|
||||||
FTM0_CNT = 0x0000;
|
FTM0_CNT = 0x0000;
|
||||||
FTM0_SC &= ~FTM_SC_TOF; // Clear FTM Overflow flag
|
FTM0_SC &= ~FTM_SC_TOF; // Clear FTM Overflow flag
|
||||||
|
|
|
@ -76,7 +76,7 @@ void HAL_analog_pin_state(char buffer[], int8_t pin) {
|
||||||
*/
|
*/
|
||||||
bool HAL_pwm_status(int8_t pin) {
|
bool HAL_pwm_status(int8_t pin) {
|
||||||
char buffer[20]; // for the sprintf statements
|
char buffer[20]; // for the sprintf statements
|
||||||
switch(pin) {
|
switch (pin) {
|
||||||
FTM_CASE(0,0);
|
FTM_CASE(0,0);
|
||||||
FTM_CASE(0,1);
|
FTM_CASE(0,1);
|
||||||
FTM_CASE(0,2);
|
FTM_CASE(0,2);
|
||||||
|
|
|
@ -103,7 +103,7 @@ typedef struct {
|
||||||
* Macros
|
* Macros
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#define M_IsOriginValid(v) (((v) & 0x7F) ? true : false)
|
#define M_IsOriginValid(v) !!((v) & 0x7F)
|
||||||
#define M_Origin2Str(v) ((v) ? "VALID" : "INVALID")
|
#define M_Origin2Str(v) ((v) ? "VALID" : "INVALID")
|
||||||
|
|
||||||
#ifdef UNW_DEBUG
|
#ifdef UNW_DEBUG
|
||||||
|
|
|
@ -32,23 +32,17 @@
|
||||||
* \retval false This is not a data-processing instruction,
|
* \retval false This is not a data-processing instruction,
|
||||||
*/
|
*/
|
||||||
static bool isDataProc(uint32_t instr) {
|
static bool isDataProc(uint32_t instr) {
|
||||||
|
|
||||||
uint8_t opcode = (instr & 0x01E00000) >> 21;
|
uint8_t opcode = (instr & 0x01E00000) >> 21;
|
||||||
bool S = (instr & 0x00100000) ? true : false;
|
if ((instr & 0xFC000000) != 0xE0000000) return false;
|
||||||
|
|
||||||
if ((instr & 0xFC000000) != 0xE0000000) {
|
/* TST, TEQ, CMP and CMN all require S to be set */
|
||||||
return false;
|
bool S = !!(instr & 0x00100000);
|
||||||
}
|
if (!S && opcode >= 8 && opcode <= 11) return false;
|
||||||
else if (!S && opcode >= 8 && opcode <= 11) {
|
|
||||||
/* TST, TEQ, CMP and CMN all require S to be set */
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwResult UnwStartArm(UnwState * const state) {
|
UnwResult UnwStartArm(UnwState * const state) {
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
uint16_t t = UNW_MAX_INSTR_COUNT;
|
uint16_t t = UNW_MAX_INSTR_COUNT;
|
||||||
|
|
||||||
|
@ -56,9 +50,8 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
uint32_t instr;
|
uint32_t instr;
|
||||||
|
|
||||||
/* Attempt to read the instruction */
|
/* Attempt to read the instruction */
|
||||||
if (!state->cb->readW(state->regData[15].v, &instr)) {
|
if (!state->cb->readW(state->regData[15].v, &instr))
|
||||||
return UNWIND_IREAD_W_FAIL;
|
return UNWIND_IREAD_W_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
UnwPrintd4("A %x %x %08x:", state->regData[13].v, state->regData[15].v, instr);
|
UnwPrintd4("A %x %x %08x:", state->regData[13].v, state->regData[15].v, instr);
|
||||||
|
|
||||||
|
@ -103,31 +96,20 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the return mode */
|
/* Determine the return mode */
|
||||||
if (state->regData[rn].v & 0x1) {
|
if (state->regData[rn].v & 0x1) /* Branching to THUMB */
|
||||||
|
|
||||||
/* Branching to THUMB */
|
|
||||||
return UnwStartThumb(state);
|
return UnwStartThumb(state);
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
/* Branch to ARM */
|
/* Branch to ARM */
|
||||||
|
/* Account for the auto-increment which isn't needed */
|
||||||
/* Account for the auto-increment which isn't needed */
|
state->regData[15].v -= 4;
|
||||||
state->regData[15].v -= 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* Branch */
|
/* Branch */
|
||||||
else if ((instr & 0xFF000000) == 0xEA000000) {
|
else if ((instr & 0xFF000000) == 0xEA000000) {
|
||||||
|
|
||||||
int32_t offset = (instr & 0x00FFFFFF);
|
int32_t offset = (instr & 0x00FFFFFF) << 2;
|
||||||
|
|
||||||
/* Shift value */
|
|
||||||
offset = offset << 2;
|
|
||||||
|
|
||||||
/* Sign extend if needed */
|
/* Sign extend if needed */
|
||||||
if (offset & 0x02000000) {
|
if (offset & 0x02000000) offset |= 0xFC000000;
|
||||||
offset |= 0xFC000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnwPrintd2("B %d\n", offset);
|
UnwPrintd2("B %d\n", offset);
|
||||||
|
|
||||||
|
@ -142,11 +124,12 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
|
|
||||||
/* MRS */
|
/* MRS */
|
||||||
else if ((instr & 0xFFBF0FFF) == 0xE10F0000) {
|
else if ((instr & 0xFFBF0FFF) == 0xE10F0000) {
|
||||||
#ifdef UNW_DEBUG
|
#ifdef UNW_DEBUG
|
||||||
bool R = (instr & 0x00400000) ? true : false;
|
const bool R = !!(instr & 0x00400000);
|
||||||
#endif
|
#else
|
||||||
|
constexpr bool R = false;
|
||||||
|
#endif
|
||||||
uint8_t rd = (instr & 0x0000F000) >> 12;
|
uint8_t rd = (instr & 0x0000F000) >> 12;
|
||||||
|
|
||||||
UnwPrintd4("MRS r%d,%s\t; r%d invalidated", rd, R ? "SPSR" : "CPSR", rd);
|
UnwPrintd4("MRS r%d,%s\t; r%d invalidated", rd, R ? "SPSR" : "CPSR", rd);
|
||||||
|
|
||||||
/* Status registers untracked */
|
/* Status registers untracked */
|
||||||
|
@ -154,11 +137,10 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
}
|
}
|
||||||
/* MSR */
|
/* MSR */
|
||||||
else if ((instr & 0xFFB0F000) == 0xE120F000) {
|
else if ((instr & 0xFFB0F000) == 0xE120F000) {
|
||||||
#ifdef UNW_DEBUG
|
#ifdef UNW_DEBUG
|
||||||
bool R = (instr & 0x00400000) ? true : false;
|
UnwPrintd2("MSR %s_?, ???", (instr & 0x00400000) ? "SPSR" : "CPSR");
|
||||||
|
#endif
|
||||||
|
|
||||||
UnwPrintd2("MSR %s_?, ???", R ? "SPSR" : "CPSR");
|
|
||||||
#endif
|
|
||||||
/* Status registers untracked.
|
/* Status registers untracked.
|
||||||
* Potentially this could change processor mode and switch
|
* Potentially this could change processor mode and switch
|
||||||
* banked registers r8-r14. Most likely is that r13 (sp) will
|
* banked registers r8-r14. Most likely is that r13 (sp) will
|
||||||
|
@ -170,18 +152,18 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
}
|
}
|
||||||
/* Data processing */
|
/* Data processing */
|
||||||
else if (isDataProc(instr)) {
|
else if (isDataProc(instr)) {
|
||||||
bool I = (instr & 0x02000000) ? true : false;
|
bool I = !!(instr & 0x02000000);
|
||||||
uint8_t opcode = (instr & 0x01E00000) >> 21;
|
uint8_t opcode = (instr & 0x01E00000) >> 21;
|
||||||
#ifdef UNW_DEBUG
|
#ifdef UNW_DEBUG
|
||||||
bool S = (instr & 0x00100000) ? true : false;
|
bool S = !!(instr & 0x00100000);
|
||||||
#endif
|
#endif
|
||||||
uint8_t rn = (instr & 0x000F0000) >> 16;
|
uint8_t rn = (instr & 0x000F0000) >> 16;
|
||||||
uint8_t rd = (instr & 0x0000F000) >> 12;
|
uint8_t rd = (instr & 0x0000F000) >> 12;
|
||||||
uint16_t operand2 = (instr & 0x00000FFF);
|
uint16_t operand2 = (instr & 0x00000FFF);
|
||||||
uint32_t op2val;
|
uint32_t op2val;
|
||||||
int op2origin;
|
int op2origin;
|
||||||
|
|
||||||
switch(opcode) {
|
switch (opcode) {
|
||||||
case 0: UnwPrintd4("AND%s r%d,r%d,", S ? "S" : "", rd, rn); break;
|
case 0: UnwPrintd4("AND%s r%d,r%d,", S ? "S" : "", rd, rn); break;
|
||||||
case 1: UnwPrintd4("EOR%s r%d,r%d,", S ? "S" : "", rd, rn); break;
|
case 1: UnwPrintd4("EOR%s r%d,r%d,", S ? "S" : "", rd, rn); break;
|
||||||
case 2: UnwPrintd4("SUB%s r%d,r%d,", S ? "S" : "", rd, rn); break;
|
case 2: UnwPrintd4("SUB%s r%d,r%d,", S ? "S" : "", rd, rn); break;
|
||||||
|
@ -217,26 +199,23 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
|
|
||||||
/* Register and shift */
|
/* Register and shift */
|
||||||
uint8_t rm = (operand2 & 0x000F);
|
uint8_t rm = (operand2 & 0x000F);
|
||||||
uint8_t regShift = (operand2 & 0x0010) ? true : false;
|
uint8_t regShift = !!(operand2 & 0x0010);
|
||||||
uint8_t shiftType = (operand2 & 0x0060) >> 5;
|
uint8_t shiftType = (operand2 & 0x0060) >> 5;
|
||||||
uint32_t shiftDist;
|
uint32_t shiftDist;
|
||||||
#ifdef UNW_DEBUG
|
#ifdef UNW_DEBUG
|
||||||
const char * const shiftMnu[4] = { "LSL", "LSR", "ASR", "ROR" };
|
const char * const shiftMnu[4] = { "LSL", "LSR", "ASR", "ROR" };
|
||||||
#endif
|
#endif
|
||||||
UnwPrintd2("r%d ", rm);
|
UnwPrintd2("r%d ", rm);
|
||||||
|
|
||||||
/* Get the shift distance */
|
/* Get the shift distance */
|
||||||
if (regShift) {
|
if (regShift) {
|
||||||
|
|
||||||
uint8_t rs = (operand2 & 0x0F00) >> 8;
|
uint8_t rs = (operand2 & 0x0F00) >> 8;
|
||||||
|
|
||||||
if (operand2 & 0x00800) {
|
if (operand2 & 0x00800) {
|
||||||
|
|
||||||
UnwPrintd1("\nError: Bit should be zero\n");
|
UnwPrintd1("\nError: Bit should be zero\n");
|
||||||
return UNWIND_ILLEGAL_INSTR;
|
return UNWIND_ILLEGAL_INSTR;
|
||||||
}
|
}
|
||||||
else if (rs == 15) {
|
else if (rs == 15) {
|
||||||
|
|
||||||
UnwPrintd1("\nError: Cannot use R15 with register shift\n");
|
UnwPrintd1("\nError: Cannot use R15 with register shift\n");
|
||||||
return UNWIND_ILLEGAL_INSTR;
|
return UNWIND_ILLEGAL_INSTR;
|
||||||
}
|
}
|
||||||
|
@ -250,46 +229,33 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
else {
|
else {
|
||||||
shiftDist = (operand2 & 0x0F80) >> 7;
|
shiftDist = (operand2 & 0x0F80) >> 7;
|
||||||
op2origin = REG_VAL_FROM_CONST;
|
op2origin = REG_VAL_FROM_CONST;
|
||||||
|
if (shiftDist) UnwPrintd3("%s #%d", shiftMnu[shiftType], shiftDist);
|
||||||
if (shiftDist) {
|
|
||||||
UnwPrintd3("%s #%d", shiftMnu[shiftType], shiftDist);
|
|
||||||
}
|
|
||||||
UnwPrintd3("\t; r%d %s", rm, M_Origin2Str(state->regData[rm].o));
|
UnwPrintd3("\t; r%d %s", rm, M_Origin2Str(state->regData[rm].o));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply the shift type to the source register */
|
/* Apply the shift type to the source register */
|
||||||
switch(shiftType) {
|
switch (shiftType) {
|
||||||
case 0: /* logical left */
|
case 0: /* logical left */
|
||||||
op2val = state->regData[rm].v << shiftDist;
|
op2val = state->regData[rm].v << shiftDist;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: /* logical right */
|
case 1: /* logical right */
|
||||||
if (!regShift && shiftDist == 0) {
|
if (!regShift && shiftDist == 0) shiftDist = 32;
|
||||||
shiftDist = 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
op2val = state->regData[rm].v >> shiftDist;
|
op2val = state->regData[rm].v >> shiftDist;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: /* arithmetic right */
|
case 2: /* arithmetic right */
|
||||||
if (!regShift && shiftDist == 0) {
|
if (!regShift && shiftDist == 0) shiftDist = 32;
|
||||||
shiftDist = 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->regData[rm].v & 0x80000000) {
|
if (state->regData[rm].v & 0x80000000) {
|
||||||
|
|
||||||
/* Register shifts maybe greater than 32 */
|
/* Register shifts maybe greater than 32 */
|
||||||
if (shiftDist >= 32) {
|
if (shiftDist >= 32)
|
||||||
op2val = 0xFFFFFFFF;
|
op2val = 0xFFFFFFFF;
|
||||||
}
|
else
|
||||||
else {
|
op2val = (state->regData[rm].v >> shiftDist) | (0xFFFFFFFF << (32 - shiftDist));
|
||||||
op2val = state->regData[rm].v >> shiftDist;
|
|
||||||
op2val |= 0xFFFFFFFF << (32 - shiftDist);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
op2val = state->regData[rm].v >> shiftDist;
|
op2val = state->regData[rm].v >> shiftDist;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: /* rotate right */
|
case 3: /* rotate right */
|
||||||
|
@ -317,19 +283,14 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decide the data origin */
|
/* Decide the data origin */
|
||||||
if (M_IsOriginValid(op2origin) &&
|
if (M_IsOriginValid(op2origin) && M_IsOriginValid(state->regData[rm].o))
|
||||||
M_IsOriginValid(state->regData[rm].o)) {
|
op2origin = REG_VAL_ARITHMETIC | state->regData[rm].o;
|
||||||
|
else
|
||||||
op2origin = state->regData[rm].o;
|
|
||||||
op2origin |= REG_VAL_ARITHMETIC;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
op2origin = REG_VAL_INVALID;
|
op2origin = REG_VAL_INVALID;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Propagate register validity */
|
/* Propagate register validity */
|
||||||
switch(opcode) {
|
switch (opcode) {
|
||||||
case 0: /* AND: Rd := Op1 AND Op2 */
|
case 0: /* AND: Rd := Op1 AND Op2 */
|
||||||
case 1: /* EOR: Rd := Op1 EOR Op2 */
|
case 1: /* EOR: Rd := Op1 EOR Op2 */
|
||||||
case 2: /* SUB: Rd:= Op1 - Op2 */
|
case 2: /* SUB: Rd:= Op1 - Op2 */
|
||||||
|
@ -374,14 +335,11 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
* to specify the shift amount the PC will be 12 bytes
|
* to specify the shift amount the PC will be 12 bytes
|
||||||
* ahead.
|
* ahead.
|
||||||
*/
|
*/
|
||||||
if (!I && (operand2 & 0x0010))
|
state->regData[rn].v += ((!I && (operand2 & 0x0010)) ? 12 : 8);
|
||||||
state->regData[rn].v += 12;
|
|
||||||
else
|
|
||||||
state->regData[rn].v += 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute values */
|
/* Compute values */
|
||||||
switch(opcode) {
|
switch (opcode) {
|
||||||
case 0: /* AND: Rd := Op1 AND Op2 */
|
case 0: /* AND: Rd := Op1 AND Op2 */
|
||||||
state->regData[rd].v = state->regData[rn].v & op2val;
|
state->regData[rd].v = state->regData[rn].v & op2val;
|
||||||
break;
|
break;
|
||||||
|
@ -429,12 +387,8 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove the prefetch offset from the PC */
|
/* Remove the prefetch offset from the PC */
|
||||||
if (rd != 15 && rn == 15) {
|
if (rd != 15 && rn == 15)
|
||||||
if (!I && (operand2 & 0x0010))
|
state->regData[rn].v -= ((!I && (operand2 & 0x0010)) ? 12 : 8);
|
||||||
state->regData[rn].v -= 12;
|
|
||||||
else
|
|
||||||
state->regData[rn].v -= 8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Block Data Transfer
|
/* Block Data Transfer
|
||||||
|
@ -442,26 +396,25 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
*/
|
*/
|
||||||
else if ((instr & 0xFE000000) == 0xE8000000) {
|
else if ((instr & 0xFE000000) == 0xE8000000) {
|
||||||
|
|
||||||
bool P = (instr & 0x01000000) ? true : false;
|
bool P = !!(instr & 0x01000000),
|
||||||
bool U = (instr & 0x00800000) ? true : false;
|
U = !!(instr & 0x00800000),
|
||||||
bool S = (instr & 0x00400000) ? true : false;
|
S = !!(instr & 0x00400000),
|
||||||
bool W = (instr & 0x00200000) ? true : false;
|
W = !!(instr & 0x00200000),
|
||||||
bool L = (instr & 0x00100000) ? true : false;
|
L = !!(instr & 0x00100000);
|
||||||
uint16_t baseReg = (instr & 0x000F0000) >> 16;
|
uint16_t baseReg = (instr & 0x000F0000) >> 16;
|
||||||
uint16_t regList = (instr & 0x0000FFFF);
|
uint16_t regList = (instr & 0x0000FFFF);
|
||||||
uint32_t addr = state->regData[baseReg].v;
|
uint32_t addr = state->regData[baseReg].v;
|
||||||
bool addrValid = M_IsOriginValid(state->regData[baseReg].o);
|
bool addrValid = M_IsOriginValid(state->regData[baseReg].o);
|
||||||
int8_t r;
|
int8_t r;
|
||||||
|
|
||||||
#ifdef UNW_DEBUG
|
#ifdef UNW_DEBUG
|
||||||
/* Display the instruction */
|
/* Display the instruction */
|
||||||
if (L) {
|
if (L)
|
||||||
UnwPrintd6("LDM%c%c r%d%s, {reglist}%s\n", P ? 'E' : 'F', U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
|
UnwPrintd6("LDM%c%c r%d%s, {reglist}%s\n", P ? 'E' : 'F', U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
|
||||||
}
|
else
|
||||||
else {
|
UnwPrintd6("STM%c%c r%d%s, {reglist}%s\n", !P ? 'E' : 'F', !U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
|
||||||
UnwPrintd6("STM%c%c r%d%s, {reglist}%s\n", !P ? 'E' : 'F', !U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
|
#endif
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* S indicates that banked registers (untracked) are used, unless
|
/* S indicates that banked registers (untracked) are used, unless
|
||||||
* this is a load including the PC when the S-bit indicates that
|
* this is a load including the PC when the S-bit indicates that
|
||||||
* that CPSR is loaded from SPSR (also untracked, but ignored).
|
* that CPSR is loaded from SPSR (also untracked, but ignored).
|
||||||
|
@ -489,44 +442,35 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
/* Check if the register is to be transferred */
|
/* Check if the register is to be transferred */
|
||||||
if (regList & (0x01 << r)) {
|
if (regList & (0x01 << r)) {
|
||||||
|
|
||||||
if (P)
|
if (P) addr += U ? 4 : -4;
|
||||||
addr += U ? 4 : -4;
|
|
||||||
|
|
||||||
if (L) {
|
if (L) {
|
||||||
|
|
||||||
if (addrValid) {
|
if (addrValid) {
|
||||||
|
|
||||||
if (!UnwMemReadRegister(state, addr, &state->regData[r])) {
|
if (!UnwMemReadRegister(state, addr, &state->regData[r]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the origin if read via the stack pointer */
|
/* Update the origin if read via the stack pointer */
|
||||||
if (M_IsOriginValid(state->regData[r].o) && baseReg == 13) {
|
if (M_IsOriginValid(state->regData[r].o) && baseReg == 13)
|
||||||
state->regData[r].o = REG_VAL_FROM_STACK;
|
state->regData[r].o = REG_VAL_FROM_STACK;
|
||||||
}
|
|
||||||
|
|
||||||
UnwPrintd5(" R%d = 0x%08x\t; r%d %s\n",r,state->regData[r].v,r, M_Origin2Str(state->regData[r].o));
|
UnwPrintd5(" R%d = 0x%08x\t; r%d %s\n",r,state->regData[r].v,r, M_Origin2Str(state->regData[r].o));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
/* Invalidate the register as the base reg was invalid */
|
/* Invalidate the register as the base reg was invalid */
|
||||||
state->regData[r].o = REG_VAL_INVALID;
|
state->regData[r].o = REG_VAL_INVALID;
|
||||||
|
|
||||||
UnwPrintd2(" R%d = ???\n", r);
|
UnwPrintd2(" R%d = ???\n", r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (addrValid) {
|
if (addrValid && !UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r]))
|
||||||
if (!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
|
return UNWIND_DWRITE_W_FAIL;
|
||||||
return UNWIND_DWRITE_W_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UnwPrintd2(" R%d = 0x%08x\n", r);
|
UnwPrintd2(" R%d = 0x%08x\n", r);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!P)
|
if (!P) addr += U ? 4 : -4;
|
||||||
addr += U ? 4 : -4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the next register */
|
/* Check the next register */
|
||||||
|
@ -535,8 +479,7 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
} while (r >= 0 && r <= 15);
|
} while (r >= 0 && r <= 15);
|
||||||
|
|
||||||
/* Check the writeback bit */
|
/* Check the writeback bit */
|
||||||
if (W)
|
if (W) state->regData[baseReg].v = addr;
|
||||||
state->regData[baseReg].v = addr;
|
|
||||||
|
|
||||||
/* Check if the PC was loaded */
|
/* Check if the PC was loaded */
|
||||||
if (L && (regList & (0x01 << 15))) {
|
if (L && (regList & (0x01 << 15))) {
|
||||||
|
@ -547,9 +490,8 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Store the return address */
|
/* Store the return address */
|
||||||
if (!UnwReportRetAddr(state, state->regData[15].v)) {
|
if (!UnwReportRetAddr(state, state->regData[15].v))
|
||||||
return UNWIND_TRUNCATED;
|
return UNWIND_TRUNCATED;
|
||||||
}
|
|
||||||
|
|
||||||
UnwPrintd2(" Return PC=0x%x", state->regData[15].v);
|
UnwPrintd2(" Return PC=0x%x", state->regData[15].v);
|
||||||
|
|
||||||
|
@ -585,9 +527,7 @@ UnwResult UnwStartArm(UnwState * const state) {
|
||||||
/* Garbage collect the memory hash (used only for the stack) */
|
/* Garbage collect the memory hash (used only for the stack) */
|
||||||
UnwMemHashGC(state);
|
UnwMemHashGC(state);
|
||||||
|
|
||||||
t--;
|
if (--t == 0) return UNWIND_EXHAUSTED;
|
||||||
if (t == 0)
|
|
||||||
return UNWIND_EXHAUSTED;
|
|
||||||
|
|
||||||
} while (!found);
|
} while (!found);
|
||||||
|
|
||||||
|
|
|
@ -25,17 +25,11 @@
|
||||||
* \param value The value to sign extend.
|
* \param value The value to sign extend.
|
||||||
* \return The signed-11 bit value stored in a 16bit data type.
|
* \return The signed-11 bit value stored in a 16bit data type.
|
||||||
*/
|
*/
|
||||||
static int32_t signExtend11(uint16_t value) {
|
static int32_t signExtend11(const uint16_t value) {
|
||||||
|
return (value & 0x400) ? value | 0xFFFFF800 : value;
|
||||||
if(value & 0x400) {
|
|
||||||
value |= 0xFFFFF800;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwResult UnwStartThumb(UnwState * const state) {
|
UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
uint16_t t = UNW_MAX_INSTR_COUNT;
|
uint16_t t = UNW_MAX_INSTR_COUNT;
|
||||||
uint32_t lastJumpAddr = 0; // Last JUMP address, to try to detect infinite loops
|
uint32_t lastJumpAddr = 0; // Last JUMP address, to try to detect infinite loops
|
||||||
|
@ -45,20 +39,19 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
uint16_t instr;
|
uint16_t instr;
|
||||||
|
|
||||||
/* Attempt to read the instruction */
|
/* Attempt to read the instruction */
|
||||||
if(!state->cb->readH(state->regData[15].v & (~0x1), &instr)) {
|
if (!state->cb->readH(state->regData[15].v & (~0x1), &instr))
|
||||||
return UNWIND_IREAD_H_FAIL;
|
return UNWIND_IREAD_H_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
UnwPrintd4("T %x %x %04x:", state->regData[13].v, state->regData[15].v, instr);
|
UnwPrintd4("T %x %x %04x:", state->regData[13].v, state->regData[15].v, instr);
|
||||||
|
|
||||||
/* Check that the PC is still on Thumb alignment */
|
/* Check that the PC is still on Thumb alignment */
|
||||||
if(!(state->regData[15].v & 0x1)) {
|
if (!(state->regData[15].v & 0x1)) {
|
||||||
UnwPrintd1("\nError: PC misalignment\n");
|
UnwPrintd1("\nError: PC misalignment\n");
|
||||||
return UNWIND_INCONSISTENT;
|
return UNWIND_INCONSISTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the SP and PC have not been invalidated */
|
/* Check that the SP and PC have not been invalidated */
|
||||||
if(!M_IsOriginValid(state->regData[13].o) || !M_IsOriginValid(state->regData[15].o)) {
|
if (!M_IsOriginValid(state->regData[13].o) || !M_IsOriginValid(state->regData[15].o)) {
|
||||||
UnwPrintd1("\nError: PC or SP invalidated\n");
|
UnwPrintd1("\nError: PC or SP invalidated\n");
|
||||||
return UNWIND_INCONSISTENT;
|
return UNWIND_INCONSISTENT;
|
||||||
}
|
}
|
||||||
|
@ -73,9 +66,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
state->regData[15].v += 2;
|
state->regData[15].v += 2;
|
||||||
|
|
||||||
/* Attempt to read the 2nd part of the instruction */
|
/* Attempt to read the 2nd part of the instruction */
|
||||||
if(!state->cb->readH(state->regData[15].v & (~0x1), &instr2)) {
|
if (!state->cb->readH(state->regData[15].v & (~0x1), &instr2))
|
||||||
return UNWIND_IREAD_H_FAIL;
|
return UNWIND_IREAD_H_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
UnwPrintd3(" %x %04x:", state->regData[15].v, instr2);
|
UnwPrintd3(" %x %04x:", state->regData[15].v, instr2);
|
||||||
|
|
||||||
|
@ -84,26 +76,25 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* PUSH and POP
|
* PUSH and POP
|
||||||
*/
|
*/
|
||||||
if ((instr & 0xFE6F) == 0xE82D) {
|
if ((instr & 0xFE6F) == 0xE82D) {
|
||||||
bool L = (instr & 0x10) ? true : false;
|
bool L = !!(instr & 0x10);
|
||||||
uint16_t rList = instr2;
|
uint16_t rList = instr2;
|
||||||
|
|
||||||
if(L) {
|
if (L) {
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
|
|
||||||
/* Load from memory: POP */
|
/* Load from memory: POP */
|
||||||
UnwPrintd1("POP {Rlist}\n");
|
UnwPrintd1("POP {Rlist}\n");
|
||||||
|
|
||||||
/* Load registers from stack */
|
/* Load registers from stack */
|
||||||
for(r = 0; r < 16; r++) {
|
for (r = 0; r < 16; r++) {
|
||||||
if(rList & (0x1 << r)) {
|
if (rList & (0x1 << r)) {
|
||||||
|
|
||||||
/* Read the word */
|
/* Read the word */
|
||||||
if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r])) {
|
if (!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
/* Alter the origin to be from the stack if it was valid */
|
/* Alter the origin to be from the stack if it was valid */
|
||||||
if(M_IsOriginValid(state->regData[r].o)) {
|
if (M_IsOriginValid(state->regData[r].o)) {
|
||||||
|
|
||||||
state->regData[r].o = REG_VAL_FROM_STACK;
|
state->regData[r].o = REG_VAL_FROM_STACK;
|
||||||
|
|
||||||
|
@ -114,7 +105,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* the caller was from Thumb. This would allow return
|
* the caller was from Thumb. This would allow return
|
||||||
* by BX for interworking APCS.
|
* by BX for interworking APCS.
|
||||||
*/
|
*/
|
||||||
if((state->regData[15].v & 0x1) == 0) {
|
if ((state->regData[15].v & 0x1) == 0) {
|
||||||
UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
|
UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
|
||||||
|
|
||||||
/* Pop into the PC will not switch mode */
|
/* Pop into the PC will not switch mode */
|
||||||
|
@ -122,9 +113,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store the return address */
|
/* Store the return address */
|
||||||
if(!UnwReportRetAddr(state, state->regData[15].v)) {
|
if (!UnwReportRetAddr(state, state->regData[15].v))
|
||||||
return UNWIND_TRUNCATED;
|
return UNWIND_TRUNCATED;
|
||||||
}
|
|
||||||
|
|
||||||
/* Now have the return address */
|
/* Now have the return address */
|
||||||
UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
|
UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
|
||||||
|
@ -155,15 +145,14 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
/* Store to memory: PUSH */
|
/* Store to memory: PUSH */
|
||||||
UnwPrintd1("PUSH {Rlist}");
|
UnwPrintd1("PUSH {Rlist}");
|
||||||
|
|
||||||
for(r = 15; r >= 0; r--) {
|
for (r = 15; r >= 0; r--) {
|
||||||
if(rList & (0x1 << r)) {
|
if (rList & (0x1 << r)) {
|
||||||
UnwPrintd4("\n r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
|
UnwPrintd4("\n r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
|
||||||
|
|
||||||
state->regData[13].v -= 4;
|
state->regData[13].v -= 4;
|
||||||
|
|
||||||
if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
|
if (!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r]))
|
||||||
return UNWIND_DWRITE_W_FAIL;
|
return UNWIND_DWRITE_W_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,9 +169,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
|
|
||||||
state->regData[13].v -= 4;
|
state->regData[13].v -= 4;
|
||||||
|
|
||||||
if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
|
if (!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r]))
|
||||||
return UNWIND_DWRITE_W_FAIL;
|
return UNWIND_DWRITE_W_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* POP register
|
* POP register
|
||||||
|
@ -194,12 +182,11 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
UnwPrintd2("POP {R%d}\n", r);
|
UnwPrintd2("POP {R%d}\n", r);
|
||||||
|
|
||||||
/* Read the word */
|
/* Read the word */
|
||||||
if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r])) {
|
if (!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
/* Alter the origin to be from the stack if it was valid */
|
/* Alter the origin to be from the stack if it was valid */
|
||||||
if(M_IsOriginValid(state->regData[r].o)) {
|
if (M_IsOriginValid(state->regData[r].o)) {
|
||||||
|
|
||||||
state->regData[r].o = REG_VAL_FROM_STACK;
|
state->regData[r].o = REG_VAL_FROM_STACK;
|
||||||
|
|
||||||
|
@ -210,7 +197,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* the caller was from Thumb. This would allow return
|
* the caller was from Thumb. This would allow return
|
||||||
* by BX for interworking APCS.
|
* by BX for interworking APCS.
|
||||||
*/
|
*/
|
||||||
if((state->regData[15].v & 0x1) == 0) {
|
if ((state->regData[15].v & 0x1) == 0) {
|
||||||
UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
|
UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
|
||||||
|
|
||||||
/* Pop into the PC will not switch mode */
|
/* Pop into the PC will not switch mode */
|
||||||
|
@ -218,9 +205,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store the return address */
|
/* Store the return address */
|
||||||
if(!UnwReportRetAddr(state, state->regData[15].v)) {
|
if (!UnwReportRetAddr(state, state->regData[15].v))
|
||||||
return UNWIND_TRUNCATED;
|
return UNWIND_TRUNCATED;
|
||||||
}
|
|
||||||
|
|
||||||
/* Now have the return address */
|
/* Now have the return address */
|
||||||
UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
|
UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
|
||||||
|
@ -255,7 +241,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* the switch clauses
|
* the switch clauses
|
||||||
*/
|
*/
|
||||||
uint8_t rn = instr & 0xF;
|
uint8_t rn = instr & 0xF;
|
||||||
bool H = (instr2 & 0x10) ? true : false;
|
bool H = !!(instr2 & 0x10);
|
||||||
|
|
||||||
UnwPrintd5("TB%c [r%d,r%d%s]\n", H ? 'H' : 'B', rn, (instr2 & 0xF), H ? ",LSL #1" : "");
|
UnwPrintd5("TB%c [r%d,r%d%s]\n", H ? 'H' : 'B', rn, (instr2 & 0xF), H ? ",LSL #1" : "");
|
||||||
|
|
||||||
|
@ -263,15 +249,14 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
if (rn == 15) {
|
if (rn == 15) {
|
||||||
if (H) {
|
if (H) {
|
||||||
uint16_t rv;
|
uint16_t rv;
|
||||||
if(!state->cb->readH((state->regData[15].v & (~1)) + 2, &rv)) {
|
if (!state->cb->readH((state->regData[15].v & (~1)) + 2, &rv))
|
||||||
return UNWIND_DREAD_H_FAIL;
|
return UNWIND_DREAD_H_FAIL;
|
||||||
}
|
|
||||||
state->regData[15].v += rv * 2;
|
state->regData[15].v += rv * 2;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
uint8_t rv;
|
uint8_t rv;
|
||||||
if(!state->cb->readB((state->regData[15].v & (~1)) + 2, &rv)) {
|
if (!state->cb->readB((state->regData[15].v & (~1)) + 2, &rv))
|
||||||
return UNWIND_DREAD_B_FAIL;
|
return UNWIND_DREAD_B_FAIL;
|
||||||
}
|
|
||||||
state->regData[15].v += rv * 2;
|
state->regData[15].v += rv * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,12 +340,11 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
UnwPrintd2(" Return PC=%x", state->regData[15].v);
|
UnwPrintd2(" Return PC=%x", state->regData[15].v);
|
||||||
|
|
||||||
/* Report the return address, including mode bit */
|
/* Report the return address, including mode bit */
|
||||||
if(!UnwReportRetAddr(state, state->regData[15].v)) {
|
if (!UnwReportRetAddr(state, state->regData[15].v))
|
||||||
return UNWIND_TRUNCATED;
|
return UNWIND_TRUNCATED;
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine the new mode */
|
/* Determine the new mode */
|
||||||
if(state->regData[15].v & 0x1) {
|
if (state->regData[15].v & 0x1) {
|
||||||
/* Branching to THUMB */
|
/* Branching to THUMB */
|
||||||
|
|
||||||
/* Account for the auto-increment which isn't needed */
|
/* Account for the auto-increment which isn't needed */
|
||||||
|
@ -411,10 +395,10 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* PC-relative load
|
* PC-relative load
|
||||||
* LDR Rd,[PC, #+/-imm]
|
* LDR Rd,[PC, #+/-imm]
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xFF7F) == 0xF85F) {
|
else if ((instr & 0xFF7F) == 0xF85F) {
|
||||||
uint8_t rt = (instr2 & 0xF000) >> 12;
|
uint8_t rt = (instr2 & 0xF000) >> 12;
|
||||||
uint8_t imm12 = (instr2 & 0x0FFF);
|
uint8_t imm12 = (instr2 & 0x0FFF);
|
||||||
bool A = (instr & 0x80) ? true : false;
|
bool A = !!(instr & 0x80);
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
|
|
||||||
/* Compute load address, adding a word to account for prefetch */
|
/* Compute load address, adding a word to account for prefetch */
|
||||||
|
@ -424,9 +408,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
|
|
||||||
UnwPrintd4("LDR r%d,[PC #%c0x%08x]", rt, A?'+':'-', address);
|
UnwPrintd4("LDR r%d,[PC #%c0x%08x]", rt, A?'+':'-', address);
|
||||||
|
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
if (!UnwMemReadRegister(state, address, &state->regData[rt]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* LDR immediate.
|
* LDR immediate.
|
||||||
|
@ -441,11 +424,11 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
/* If destination is PC and we don't know the source value, then fail */
|
/* If destination is PC and we don't know the source value, then fail */
|
||||||
if (!M_IsOriginValid(state->regData[rn].o)) {
|
if (!M_IsOriginValid(state->regData[rn].o)) {
|
||||||
state->regData[rt].o = state->regData[rn].o;
|
state->regData[rt].o = state->regData[rn].o;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
uint32_t address = state->regData[rn].v + imm12;
|
uint32_t address = state->regData[rn].v + imm12;
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
if (!UnwMemReadRegister(state, address, &state->regData[rt]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -459,31 +442,20 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
uint8_t rn = (instr & 0xF);
|
uint8_t rn = (instr & 0xF);
|
||||||
uint8_t rt = (instr2 & 0xF000) >> 12;
|
uint8_t rt = (instr2 & 0xF000) >> 12;
|
||||||
uint16_t imm8 = (instr2 & 0xFF);
|
uint16_t imm8 = (instr2 & 0xFF);
|
||||||
bool P = (instr2 & 0x400) ? true : false;
|
bool P = !!(instr2 & 0x400);
|
||||||
bool U = (instr2 & 0x200) ? true : false;
|
bool U = !!(instr2 & 0x200);
|
||||||
bool W = (instr2 & 0x100) ? true : false;
|
bool W = !!(instr2 & 0x100);
|
||||||
|
|
||||||
if (!M_IsOriginValid(state->regData[rn].o)) {
|
if (!M_IsOriginValid(state->regData[rn].o))
|
||||||
state->regData[rt].o = state->regData[rn].o;
|
state->regData[rt].o = state->regData[rn].o;
|
||||||
} else {
|
else {
|
||||||
uint32_t offaddress = state->regData[rn].v + imm8;
|
uint32_t offaddress = state->regData[rn].v + (U ? imm8 + imm8 : 0),
|
||||||
if (U) offaddress += imm8;
|
address = P ? offaddress : state->regData[rn].v;
|
||||||
else offaddress -= imm8;
|
|
||||||
|
|
||||||
uint32_t address;
|
if (!UnwMemReadRegister(state, address, &state->regData[rt]))
|
||||||
if (P) {
|
|
||||||
address = offaddress;
|
|
||||||
} else {
|
|
||||||
address = state->regData[rn].v;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
if (W) {
|
if (W) state->regData[rn].v = offaddress;
|
||||||
state->regData[rn].v = offaddress;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -493,30 +465,28 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* Where Rt is PC, Rn value is known, Rm is not known or unknown
|
* Where Rt is PC, Rn value is known, Rm is not known or unknown
|
||||||
*/
|
*/
|
||||||
else if ((instr & 0xFFF0) == 0xF850 && (instr2 & 0x0FC0) == 0x0000) {
|
else if ((instr & 0xFFF0) == 0xF850 && (instr2 & 0x0FC0) == 0x0000) {
|
||||||
uint8_t rn = (instr & 0xF);
|
const uint8_t rn = (instr & 0xF),
|
||||||
uint8_t rt = (instr2 & 0xF000) >> 12;
|
rt = (instr2 & 0xF000) >> 12,
|
||||||
uint8_t rm = (instr2 & 0xF);
|
rm = (instr2 & 0xF),
|
||||||
uint8_t imm2 = (instr2 & 0x30) >> 4;
|
imm2 = (instr2 & 0x30) >> 4;
|
||||||
|
|
||||||
if (!M_IsOriginValid(state->regData[rn].o) ||
|
if (!M_IsOriginValid(state->regData[rn].o) || !M_IsOriginValid(state->regData[rm].o)) {
|
||||||
!M_IsOriginValid(state->regData[rm].o)) {
|
|
||||||
|
|
||||||
/* If Rt is PC, and Rn is known, then do an exception and assume
|
/* If Rt is PC, and Rn is known, then do an exception and assume
|
||||||
Rm equals 0 => This takes the first case in a switch() */
|
Rm equals 0 => This takes the first case in a switch() */
|
||||||
if (rt == 15 && M_IsOriginValid(state->regData[rn].o)) {
|
if (rt == 15 && M_IsOriginValid(state->regData[rn].o)) {
|
||||||
uint32_t address = state->regData[rn].v;
|
uint32_t address = state->regData[rn].v;
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
if (!UnwMemReadRegister(state, address, &state->regData[rt]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
else /* Propagate unknown value */
|
||||||
/* Propagate unknown value */
|
|
||||||
state->regData[rt].o = state->regData[rn].o;
|
state->regData[rt].o = state->regData[rn].o;
|
||||||
}
|
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
uint32_t address = state->regData[rn].v + (state->regData[rm].v << imm2);
|
uint32_t address = state->regData[rn].v + (state->regData[rm].v << imm2);
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
if (!UnwMemReadRegister(state, address, &state->regData[rt]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -533,14 +503,14 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* LSR Rd, Rs, #Offset5
|
* LSR Rd, Rs, #Offset5
|
||||||
* ASR Rd, Rs, #Offset5
|
* ASR Rd, Rs, #Offset5
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xE000) == 0x0000 && (instr & 0x1800) != 0x1800) {
|
else if ((instr & 0xE000) == 0x0000 && (instr & 0x1800) != 0x1800) {
|
||||||
bool signExtend;
|
bool signExtend;
|
||||||
uint8_t op = (instr & 0x1800) >> 11;
|
const uint8_t op = (instr & 0x1800) >> 11,
|
||||||
uint8_t offset5 = (instr & 0x07C0) >> 6;
|
offset5 = (instr & 0x07C0) >> 6,
|
||||||
uint8_t rs = (instr & 0x0038) >> 3;
|
rs = (instr & 0x0038) >> 3,
|
||||||
uint8_t rd = (instr & 0x0007);
|
rd = (instr & 0x0007);
|
||||||
|
|
||||||
switch(op) {
|
switch (op) {
|
||||||
case 0: /* LSL */
|
case 0: /* LSL */
|
||||||
UnwPrintd6("LSL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
|
UnwPrintd6("LSL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
|
||||||
state->regData[rd].v = state->regData[rs].v << offset5;
|
state->regData[rd].v = state->regData[rs].v << offset5;
|
||||||
|
@ -558,11 +528,9 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
case 2: /* ASR */
|
case 2: /* ASR */
|
||||||
UnwPrintd6("ASL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
|
UnwPrintd6("ASL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
|
||||||
|
|
||||||
signExtend = (state->regData[rs].v & 0x8000) ? true : false;
|
signExtend = !!(state->regData[rs].v & 0x8000);
|
||||||
state->regData[rd].v = state->regData[rs].v >> offset5;
|
state->regData[rd].v = state->regData[rs].v >> offset5;
|
||||||
if(signExtend) {
|
if (signExtend) state->regData[rd].v |= 0xFFFFFFFF << (32 - offset5);
|
||||||
state->regData[rd].v |= 0xFFFFFFFF << (32 - offset5);
|
|
||||||
}
|
|
||||||
state->regData[rd].o = state->regData[rs].o;
|
state->regData[rd].o = state->regData[rs].o;
|
||||||
state->regData[rd].o |= REG_VAL_ARITHMETIC;
|
state->regData[rd].o |= REG_VAL_ARITHMETIC;
|
||||||
break;
|
break;
|
||||||
|
@ -574,9 +542,9 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* SUB Rd, Rs, Rn
|
* SUB Rd, Rs, Rn
|
||||||
* SUB Rd, Rs, #Offset3
|
* SUB Rd, Rs, #Offset3
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xF800) == 0x1800) {
|
else if ((instr & 0xF800) == 0x1800) {
|
||||||
bool I = (instr & 0x0400) ? true : false;
|
bool I = !!(instr & 0x0400);
|
||||||
bool op = (instr & 0x0200) ? true : false;
|
bool op = !!(instr & 0x0200);
|
||||||
uint8_t rn = (instr & 0x01C0) >> 6;
|
uint8_t rn = (instr & 0x01C0) >> 6;
|
||||||
uint8_t rs = (instr & 0x0038) >> 3;
|
uint8_t rs = (instr & 0x0038) >> 3;
|
||||||
uint8_t rd = (instr & 0x0007);
|
uint8_t rd = (instr & 0x0007);
|
||||||
|
@ -584,36 +552,24 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
/* Print decoding */
|
/* Print decoding */
|
||||||
UnwPrintd6("%s r%d, r%d, %c%d\t;",op ? "SUB" : "ADD",rd, rs,I ? '#' : 'r',rn);
|
UnwPrintd6("%s r%d, r%d, %c%d\t;",op ? "SUB" : "ADD",rd, rs,I ? '#' : 'r',rn);
|
||||||
UnwPrintd5("r%d %s, r%d %s",rd, M_Origin2Str(state->regData[rd].o),rs, M_Origin2Str(state->regData[rs].o));
|
UnwPrintd5("r%d %s, r%d %s",rd, M_Origin2Str(state->regData[rd].o),rs, M_Origin2Str(state->regData[rs].o));
|
||||||
if(!I) {
|
if (!I) {
|
||||||
|
|
||||||
UnwPrintd3(", r%d %s", rn, M_Origin2Str(state->regData[rn].o));
|
UnwPrintd3(", r%d %s", rn, M_Origin2Str(state->regData[rn].o));
|
||||||
|
|
||||||
/* Perform calculation */
|
/* Perform calculation */
|
||||||
if(op) {
|
state->regData[rd].v = state->regData[rs].v + (op ? -state->regData[rn].v : state->regData[rn].v);
|
||||||
state->regData[rd].v = state->regData[rs].v - state->regData[rn].v;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
state->regData[rd].v = state->regData[rs].v + state->regData[rn].v;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Propagate the origin */
|
/* Propagate the origin */
|
||||||
if(M_IsOriginValid(state->regData[rs].o) &&
|
if (M_IsOriginValid(state->regData[rs].o) && M_IsOriginValid(state->regData[rn].o)) {
|
||||||
M_IsOriginValid(state->regData[rn].o)) {
|
|
||||||
state->regData[rd].o = state->regData[rs].o;
|
state->regData[rd].o = state->regData[rs].o;
|
||||||
state->regData[rd].o |= REG_VAL_ARITHMETIC;
|
state->regData[rd].o |= REG_VAL_ARITHMETIC;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
state->regData[rd].o = REG_VAL_INVALID;
|
state->regData[rd].o = REG_VAL_INVALID;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Perform calculation */
|
/* Perform calculation */
|
||||||
if(op) {
|
state->regData[rd].v = state->regData[rs].v + (op ? -rn : rn);
|
||||||
state->regData[rd].v = state->regData[rs].v - rn;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
state->regData[rd].v = state->regData[rs].v + rn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Propagate the origin */
|
/* Propagate the origin */
|
||||||
state->regData[rd].o = state->regData[rs].o;
|
state->regData[rd].o = state->regData[rs].o;
|
||||||
|
@ -626,13 +582,13 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* ADD Rd, #Offset8
|
* ADD Rd, #Offset8
|
||||||
* SUB Rd, #Offset8
|
* SUB Rd, #Offset8
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xE000) == 0x2000) {
|
else if ((instr & 0xE000) == 0x2000) {
|
||||||
|
|
||||||
uint8_t op = (instr & 0x1800) >> 11;
|
uint8_t op = (instr & 0x1800) >> 11;
|
||||||
uint8_t rd = (instr & 0x0700) >> 8;
|
uint8_t rd = (instr & 0x0700) >> 8;
|
||||||
uint8_t offset8 = (instr & 0x00FF);
|
uint8_t offset8 = (instr & 0x00FF);
|
||||||
|
|
||||||
switch(op) {
|
switch (op) {
|
||||||
case 0: /* MOV */
|
case 0: /* MOV */
|
||||||
UnwPrintd3("MOV r%d, #0x%x", rd, offset8);
|
UnwPrintd3("MOV r%d, #0x%x", rd, offset8);
|
||||||
state->regData[rd].v = offset8;
|
state->regData[rd].v = offset8;
|
||||||
|
@ -675,7 +631,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* BIC Rd, Rs
|
* BIC Rd, Rs
|
||||||
* MVN Rd, Rs
|
* MVN Rd, Rs
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xFC00) == 0x4000) {
|
else if ((instr & 0xFC00) == 0x4000) {
|
||||||
uint8_t op = (instr & 0x03C0) >> 6;
|
uint8_t op = (instr & 0x03C0) >> 6;
|
||||||
uint8_t rs = (instr & 0x0038) >> 3;
|
uint8_t rs = (instr & 0x0038) >> 3;
|
||||||
uint8_t rd = (instr & 0x0007);
|
uint8_t rd = (instr & 0x0007);
|
||||||
|
@ -688,7 +644,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
"ORR", "MUL", "BIC", "MVN" };
|
"ORR", "MUL", "BIC", "MVN" };
|
||||||
#endif
|
#endif
|
||||||
/* Print the mnemonic and registers */
|
/* Print the mnemonic and registers */
|
||||||
switch(op) {
|
switch (op) {
|
||||||
case 0: /* AND */
|
case 0: /* AND */
|
||||||
case 1: /* EOR */
|
case 1: /* EOR */
|
||||||
case 2: /* LSL */
|
case 2: /* LSL */
|
||||||
|
@ -720,7 +676,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform operation */
|
/* Perform operation */
|
||||||
switch(op) {
|
switch (op) {
|
||||||
case 0: /* AND */
|
case 0: /* AND */
|
||||||
state->regData[rd].v &= state->regData[rs].v;
|
state->regData[rd].v &= state->regData[rs].v;
|
||||||
break;
|
break;
|
||||||
|
@ -738,7 +694,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: /* ASR */
|
case 4: /* ASR */
|
||||||
if(state->regData[rd].v & 0x80000000) {
|
if (state->regData[rd].v & 0x80000000) {
|
||||||
state->regData[rd].v >>= state->regData[rs].v;
|
state->regData[rd].v >>= state->regData[rs].v;
|
||||||
state->regData[rd].v |= 0xFFFFFFFF << (32 - state->regData[rs].v);
|
state->regData[rd].v |= 0xFFFFFFFF << (32 - state->regData[rs].v);
|
||||||
}
|
}
|
||||||
|
@ -782,7 +738,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Propagate data origins */
|
/* Propagate data origins */
|
||||||
switch(op) {
|
switch (op) {
|
||||||
case 0: /* AND */
|
case 0: /* AND */
|
||||||
case 1: /* EOR */
|
case 1: /* EOR */
|
||||||
case 2: /* LSL */
|
case 2: /* LSL */
|
||||||
|
@ -792,13 +748,12 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
case 12: /* ORR */
|
case 12: /* ORR */
|
||||||
case 13: /* MUL */
|
case 13: /* MUL */
|
||||||
case 14: /* BIC */
|
case 14: /* BIC */
|
||||||
if(M_IsOriginValid(state->regData[rd].o) && M_IsOriginValid(state->regData[rs].o)) {
|
if (M_IsOriginValid(state->regData[rd].o) && M_IsOriginValid(state->regData[rs].o)) {
|
||||||
state->regData[rd].o = state->regData[rs].o;
|
state->regData[rd].o = state->regData[rs].o;
|
||||||
state->regData[rd].o |= REG_VAL_ARITHMETIC;
|
state->regData[rd].o |= REG_VAL_ARITHMETIC;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
state->regData[rd].o = REG_VAL_INVALID;
|
state->regData[rd].o = REG_VAL_INVALID;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5: /* ADC */
|
case 5: /* ADC */
|
||||||
|
@ -825,7 +780,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* CMP Hd, Rs
|
* CMP Hd, Rs
|
||||||
* MOV Hd, Hs
|
* MOV Hd, Hs
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xFC00) == 0x4400) {
|
else if ((instr & 0xFC00) == 0x4400) {
|
||||||
uint8_t op = (instr & 0x0300) >> 8;
|
uint8_t op = (instr & 0x0300) >> 8;
|
||||||
bool h1 = (instr & 0x0080) ? true: false;
|
bool h1 = (instr & 0x0080) ? true: false;
|
||||||
bool h2 = (instr & 0x0040) ? true: false;
|
bool h2 = (instr & 0x0040) ? true: false;
|
||||||
|
@ -833,12 +788,10 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
uint8_t rhd = (instr & 0x0007);
|
uint8_t rhd = (instr & 0x0007);
|
||||||
|
|
||||||
/* Adjust the register numbers */
|
/* Adjust the register numbers */
|
||||||
if(h2)
|
if (h2) rhs += 8;
|
||||||
rhs += 8;
|
if (h1) rhd += 8;
|
||||||
if(h1)
|
|
||||||
rhd += 8;
|
|
||||||
|
|
||||||
switch(op) {
|
switch (op) {
|
||||||
case 0: /* ADD */
|
case 0: /* ADD */
|
||||||
UnwPrintd5("ADD r%d, r%d\t; r%d %s", rhd, rhs, rhs, M_Origin2Str(state->regData[rhs].o));
|
UnwPrintd5("ADD r%d, r%d\t; r%d %s", rhd, rhs, rhs, M_Origin2Str(state->regData[rhs].o));
|
||||||
state->regData[rhd].v += state->regData[rhs].v;
|
state->regData[rhd].v += state->regData[rhs].v;
|
||||||
|
@ -861,28 +814,25 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
UnwPrintd4("BX r%d\t; r%d %s\n", rhs, rhs, M_Origin2Str(state->regData[rhs].o));
|
UnwPrintd4("BX r%d\t; r%d %s\n", rhs, rhs, M_Origin2Str(state->regData[rhs].o));
|
||||||
|
|
||||||
/* Only follow BX if the data was from the stack or BX LR */
|
/* Only follow BX if the data was from the stack or BX LR */
|
||||||
if(rhs == 14 || state->regData[rhs].o == REG_VAL_FROM_STACK) {
|
if (rhs == 14 || state->regData[rhs].o == REG_VAL_FROM_STACK) {
|
||||||
UnwPrintd2(" Return PC=0x%x\n", state->regData[rhs].v & (~0x1));
|
UnwPrintd2(" Return PC=0x%x\n", state->regData[rhs].v & (~0x1));
|
||||||
|
|
||||||
/* Report the return address, including mode bit */
|
/* Report the return address, including mode bit */
|
||||||
if(!UnwReportRetAddr(state, state->regData[rhs].v)) {
|
if (!UnwReportRetAddr(state, state->regData[rhs].v))
|
||||||
return UNWIND_TRUNCATED;
|
return UNWIND_TRUNCATED;
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the PC */
|
/* Update the PC */
|
||||||
state->regData[15].v = state->regData[rhs].v;
|
state->regData[15].v = state->regData[rhs].v;
|
||||||
|
|
||||||
/* Determine the new mode */
|
/* Determine the new mode */
|
||||||
if(state->regData[rhs].v & 0x1) {
|
if (state->regData[rhs].v & 0x1) {
|
||||||
/* Branching to THUMB */
|
/* Branching to THUMB */
|
||||||
|
|
||||||
/* Account for the auto-increment which isn't needed */
|
/* Account for the auto-increment which isn't needed */
|
||||||
state->regData[15].v -= 2;
|
state->regData[15].v -= 2;
|
||||||
}
|
}
|
||||||
else {
|
else /* Branch to ARM */
|
||||||
/* Branch to ARM */
|
|
||||||
return UnwStartArm(state);
|
return UnwStartArm(state);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
UnwPrintd4("\nError: BX to invalid register: r%d = 0x%x (%s)\n", rhs, state->regData[rhs].o, M_Origin2Str(state->regData[rhs].o));
|
UnwPrintd4("\nError: BX to invalid register: r%d = 0x%x (%s)\n", rhs, state->regData[rhs].o, M_Origin2Str(state->regData[rhs].o));
|
||||||
|
@ -893,7 +843,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
/* Format 9: PC-relative load
|
/* Format 9: PC-relative load
|
||||||
* LDR Rd,[PC, #imm]
|
* LDR Rd,[PC, #imm]
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xF800) == 0x4800) {
|
else if ((instr & 0xF800) == 0x4800) {
|
||||||
uint8_t rd = (instr & 0x0700) >> 8;
|
uint8_t rd = (instr & 0x0700) >> 8;
|
||||||
uint8_t word8 = (instr & 0x00FF);
|
uint8_t word8 = (instr & 0x00FF);
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
|
@ -903,19 +853,18 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
|
|
||||||
UnwPrintd3("LDR r%d, 0x%08x", rd, address);
|
UnwPrintd3("LDR r%d, 0x%08x", rd, address);
|
||||||
|
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rd])) {
|
if (!UnwMemReadRegister(state, address, &state->regData[rd]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* Format 13: add offset to Stack Pointer
|
/* Format 13: add offset to Stack Pointer
|
||||||
* ADD sp,#+imm
|
* ADD sp,#+imm
|
||||||
* ADD sp,#-imm
|
* ADD sp,#-imm
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xFF00) == 0xB000) {
|
else if ((instr & 0xFF00) == 0xB000) {
|
||||||
uint8_t value = (instr & 0x7F) * 4;
|
uint8_t value = (instr & 0x7F) * 4;
|
||||||
|
|
||||||
/* Check the negative bit */
|
/* Check the negative bit */
|
||||||
if((instr & 0x80) != 0) {
|
if ((instr & 0x80) != 0) {
|
||||||
UnwPrintd2("SUB sp,#0x%x", value);
|
UnwPrintd2("SUB sp,#0x%x", value);
|
||||||
state->regData[13].v -= value;
|
state->regData[13].v -= value;
|
||||||
}
|
}
|
||||||
|
@ -930,29 +879,27 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* POP {Rlist}
|
* POP {Rlist}
|
||||||
* POP {Rlist, PC}
|
* POP {Rlist, PC}
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xF600) == 0xB400) {
|
else if ((instr & 0xF600) == 0xB400) {
|
||||||
bool L = (instr & 0x0800) ? true : false;
|
bool L = !!(instr & 0x0800);
|
||||||
bool R = (instr & 0x0100) ? true : false;
|
bool R = !!(instr & 0x0100);
|
||||||
uint8_t rList = (instr & 0x00FF);
|
uint8_t rList = (instr & 0x00FF);
|
||||||
|
|
||||||
if(L) {
|
if (L) {
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
|
|
||||||
/* Load from memory: POP */
|
/* Load from memory: POP */
|
||||||
UnwPrintd2("POP {Rlist%s}\n", R ? ", PC" : "");
|
UnwPrintd2("POP {Rlist%s}\n", R ? ", PC" : "");
|
||||||
|
|
||||||
for(r = 0; r < 8; r++) {
|
for (r = 0; r < 8; r++) {
|
||||||
if(rList & (0x1 << r)) {
|
if (rList & (0x1 << r)) {
|
||||||
|
|
||||||
/* Read the word */
|
/* Read the word */
|
||||||
if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r])) {
|
if (!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
/* Alter the origin to be from the stack if it was valid */
|
/* Alter the origin to be from the stack if it was valid */
|
||||||
if(M_IsOriginValid(state->regData[r].o)) {
|
if (M_IsOriginValid(state->regData[r].o))
|
||||||
state->regData[r].o = REG_VAL_FROM_STACK;
|
state->regData[r].o = REG_VAL_FROM_STACK;
|
||||||
}
|
|
||||||
|
|
||||||
state->regData[13].v += 4;
|
state->regData[13].v += 4;
|
||||||
|
|
||||||
|
@ -961,14 +908,13 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the PC is to be popped */
|
/* Check if the PC is to be popped */
|
||||||
if(R) {
|
if (R) {
|
||||||
/* Get the return address */
|
/* Get the return address */
|
||||||
if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[15])) {
|
if (!UnwMemReadRegister(state, state->regData[13].v, &state->regData[15]))
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
/* Alter the origin to be from the stack if it was valid */
|
/* Alter the origin to be from the stack if it was valid */
|
||||||
if(!M_IsOriginValid(state->regData[15].o)) {
|
if (!M_IsOriginValid(state->regData[15].o)) {
|
||||||
/* Return address is not valid */
|
/* Return address is not valid */
|
||||||
UnwPrintd1("PC popped with invalid address\n");
|
UnwPrintd1("PC popped with invalid address\n");
|
||||||
return UNWIND_FAILURE;
|
return UNWIND_FAILURE;
|
||||||
|
@ -978,7 +924,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* the caller was from Thumb. This would allow return
|
* the caller was from Thumb. This would allow return
|
||||||
* by BX for interworking APCS.
|
* by BX for interworking APCS.
|
||||||
*/
|
*/
|
||||||
if((state->regData[15].v & 0x1) == 0) {
|
if ((state->regData[15].v & 0x1) == 0) {
|
||||||
UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
|
UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
|
||||||
|
|
||||||
/* Pop into the PC will not switch mode */
|
/* Pop into the PC will not switch mode */
|
||||||
|
@ -986,9 +932,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store the return address */
|
/* Store the return address */
|
||||||
if(!UnwReportRetAddr(state, state->regData[15].v)) {
|
if (!UnwReportRetAddr(state, state->regData[15].v))
|
||||||
return UNWIND_TRUNCATED;
|
return UNWIND_TRUNCATED;
|
||||||
}
|
|
||||||
|
|
||||||
/* Now have the return address */
|
/* Now have the return address */
|
||||||
UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
|
UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
|
||||||
|
@ -1008,26 +953,24 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
UnwPrintd2("PUSH {Rlist%s}", R ? ", LR" : "");
|
UnwPrintd2("PUSH {Rlist%s}", R ? ", LR" : "");
|
||||||
|
|
||||||
/* Check if the LR is to be pushed */
|
/* Check if the LR is to be pushed */
|
||||||
if(R) {
|
if (R) {
|
||||||
UnwPrintd3("\n lr = 0x%08x\t; %s", state->regData[14].v, M_Origin2Str(state->regData[14].o));
|
UnwPrintd3("\n lr = 0x%08x\t; %s", state->regData[14].v, M_Origin2Str(state->regData[14].o));
|
||||||
|
|
||||||
state->regData[13].v -= 4;
|
state->regData[13].v -= 4;
|
||||||
|
|
||||||
/* Write the register value to memory */
|
/* Write the register value to memory */
|
||||||
if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[14])) {
|
if (!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[14]))
|
||||||
return UNWIND_DWRITE_W_FAIL;
|
return UNWIND_DWRITE_W_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(r = 7; r >= 0; r--) {
|
for (r = 7; r >= 0; r--) {
|
||||||
if(rList & (0x1 << r)) {
|
if (rList & (0x1 << r)) {
|
||||||
UnwPrintd4("\n r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
|
UnwPrintd4("\n r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
|
||||||
|
|
||||||
state->regData[13].v -= 4;
|
state->regData[13].v -= 4;
|
||||||
|
|
||||||
if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
|
if (!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r]))
|
||||||
return UNWIND_DWRITE_W_FAIL;
|
return UNWIND_DWRITE_W_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1037,7 +980,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
* Conditional branches
|
* Conditional branches
|
||||||
* Bcond
|
* Bcond
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xF000) == 0xD000) {
|
else if ((instr & 0xF000) == 0xD000) {
|
||||||
int32_t branchValue = (instr & 0xFF);
|
int32_t branchValue = (instr & 0xFF);
|
||||||
if (branchValue & 0x80) branchValue |= 0xFFFFFF00;
|
if (branchValue & 0x80) branchValue |= 0xFFFFFF00;
|
||||||
|
|
||||||
|
@ -1066,7 +1009,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
/* Format 18: unconditional branch
|
/* Format 18: unconditional branch
|
||||||
* B label
|
* B label
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xF800) == 0xE000) {
|
else if ((instr & 0xF800) == 0xE000) {
|
||||||
uint32_t v;
|
uint32_t v;
|
||||||
int32_t branchValue = signExtend11(instr & 0x07FF);
|
int32_t branchValue = signExtend11(instr & 0x07FF);
|
||||||
|
|
||||||
|
@ -1106,8 +1049,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
UnwPrintd1("\n");
|
UnwPrintd1("\n");
|
||||||
|
|
||||||
/* Should never hit the reset vector */
|
/* Should never hit the reset vector */
|
||||||
if(state->regData[15].v == 0)
|
if (state->regData[15].v == 0) return UNWIND_RESET;
|
||||||
return UNWIND_RESET;
|
|
||||||
|
|
||||||
/* Check next address */
|
/* Check next address */
|
||||||
state->regData[15].v += 2;
|
state->regData[15].v += 2;
|
||||||
|
@ -1115,11 +1057,9 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
/* Garbage collect the memory hash (used only for the stack) */
|
/* Garbage collect the memory hash (used only for the stack) */
|
||||||
UnwMemHashGC(state);
|
UnwMemHashGC(state);
|
||||||
|
|
||||||
t--;
|
if (--t == 0) return UNWIND_EXHAUSTED;
|
||||||
if(t == 0)
|
|
||||||
return UNWIND_EXHAUSTED;
|
|
||||||
|
|
||||||
} while(!found);
|
} while (!found);
|
||||||
|
|
||||||
return UNWIND_SUCCESS;
|
return UNWIND_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "unwarmmem.h"
|
#include "unwarmmem.h"
|
||||||
#include "unwarm.h"
|
#include "unwarm.h"
|
||||||
|
|
||||||
#define M_IsIdxUsed(a, v) (((a)[v >> 3] & (1 << (v & 0x7))) ? true : false)
|
#define M_IsIdxUsed(a, v) !!((a)[v >> 3] & (1 << (v & 0x7)))
|
||||||
#define M_SetIdxUsed(a, v) ((a)[v >> 3] |= (1 << (v & 0x7)))
|
#define M_SetIdxUsed(a, v) ((a)[v >> 3] |= (1 << (v & 0x7)))
|
||||||
#define M_ClrIdxUsed(a, v) ((a)[v >> 3] &= ~(1 << (v & 0x7)))
|
#define M_ClrIdxUsed(a, v) ((a)[v >> 3] &= ~(1 << (v & 0x7)))
|
||||||
|
|
||||||
|
@ -34,11 +34,9 @@ static int16_t memHashIndex(MemData * const memData, const uint32_t addr) {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* Check if the element is occupied */
|
/* Check if the element is occupied */
|
||||||
if(M_IsIdxUsed(memData->used, s)) {
|
if (M_IsIdxUsed(memData->used, s)) {
|
||||||
/* Check if it is occupied with the sought data */
|
/* Check if it is occupied with the sought data */
|
||||||
if(memData->a[s] == addr) {
|
if (memData->a[s] == addr) return s;
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Item is free, this is where the item should be stored */
|
/* Item is free, this is where the item should be stored */
|
||||||
|
@ -47,10 +45,8 @@ static int16_t memHashIndex(MemData * const memData, const uint32_t addr) {
|
||||||
|
|
||||||
/* Search the next entry */
|
/* Search the next entry */
|
||||||
s++;
|
s++;
|
||||||
if(s > MEM_HASH_SIZE) {
|
if (s > MEM_HASH_SIZE) s = 0;
|
||||||
s = 0;
|
} while (s != v);
|
||||||
}
|
|
||||||
} while(s != v);
|
|
||||||
|
|
||||||
/* Search failed, hash is full and the address not stored */
|
/* Search failed, hash is full and the address not stored */
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -58,9 +54,9 @@ static int16_t memHashIndex(MemData * const memData, const uint32_t addr) {
|
||||||
|
|
||||||
bool UnwMemHashRead(MemData * const memData, uint32_t addr,uint32_t * const data, bool * const tracked) {
|
bool UnwMemHashRead(MemData * const memData, uint32_t addr,uint32_t * const data, bool * const tracked) {
|
||||||
|
|
||||||
int16_t i = memHashIndex(memData, addr);
|
const int16_t i = memHashIndex(memData, addr);
|
||||||
|
|
||||||
if(i >= 0 && M_IsIdxUsed(memData->used, i) && memData->a[i] == addr) {
|
if (i >= 0 && M_IsIdxUsed(memData->used, i) && memData->a[i] == addr) {
|
||||||
*data = memData->v[i];
|
*data = memData->v[i];
|
||||||
*tracked = M_IsIdxUsed(memData->tracked, i);
|
*tracked = M_IsIdxUsed(memData->tracked, i);
|
||||||
return true;
|
return true;
|
||||||
|
@ -72,44 +68,36 @@ bool UnwMemHashRead(MemData * const memData, uint32_t addr,uint32_t * const data
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnwMemHashWrite(MemData * const memData, uint32_t addr, uint32_t val, bool valValid) {
|
bool UnwMemHashWrite(MemData * const memData, uint32_t addr, uint32_t val, bool valValid) {
|
||||||
|
const int16_t i = memHashIndex(memData, addr);
|
||||||
|
if (i < 0) return false; /* Hash full */
|
||||||
|
|
||||||
int16_t i = memHashIndex(memData, addr);
|
/* Store the item */
|
||||||
|
memData->a[i] = addr;
|
||||||
|
M_SetIdxUsed(memData->used, i);
|
||||||
|
|
||||||
if(i < 0){
|
if (valValid) {
|
||||||
/* Hash full */
|
memData->v[i] = val;
|
||||||
return false;
|
M_SetIdxUsed(memData->tracked, i);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Store the item */
|
#ifdef UNW_DEBUG
|
||||||
memData->a[i] = addr;
|
memData->v[i] = 0xDEADBEEF;
|
||||||
M_SetIdxUsed(memData->used, i);
|
#endif
|
||||||
|
M_ClrIdxUsed(memData->tracked, i);
|
||||||
if(valValid)
|
|
||||||
{
|
|
||||||
memData->v[i] = val;
|
|
||||||
M_SetIdxUsed(memData->tracked, i);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#ifdef UNW_DEBUG
|
|
||||||
memData->v[i] = 0xDEADBEEF;
|
|
||||||
#endif
|
|
||||||
M_ClrIdxUsed(memData->tracked, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnwMemHashGC(UnwState * const state) {
|
void UnwMemHashGC(UnwState * const state) {
|
||||||
|
|
||||||
const uint32_t minValidAddr = state->regData[13].v;
|
const uint32_t minValidAddr = state->regData[13].v;
|
||||||
MemData * const memData = &state->memData;
|
MemData * const memData = &state->memData;
|
||||||
uint16_t t;
|
uint16_t t;
|
||||||
|
|
||||||
for(t = 0; t < MEM_HASH_SIZE; t++) {
|
for (t = 0; t < MEM_HASH_SIZE; t++) {
|
||||||
if(M_IsIdxUsed(memData->used, t) && (memData->a[t] < minValidAddr)) {
|
if (M_IsIdxUsed(memData->used, t) && (memData->a[t] < minValidAddr)) {
|
||||||
UnwPrintd3("MemHashGC: Free elem %d, addr 0x%08x\n", t, memData->a[t]);
|
UnwPrintd3("MemHashGC: Free elem %d, addr 0x%08x\n", t, memData->a[t]);
|
||||||
|
|
||||||
M_ClrIdxUsed(memData->used, t);
|
M_ClrIdxUsed(memData->used, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,11 @@ static int HasUnwindTableInfo(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data) {
|
UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data) {
|
||||||
|
|
||||||
if (HasUnwindTableInfo()) {
|
if (HasUnwindTableInfo()) {
|
||||||
|
|
||||||
/* We have unwind information tables */
|
/* We have unwind information tables */
|
||||||
return UnwindByTableStart(frame, cb, data);
|
return UnwindByTableStart(frame, cb, data);
|
||||||
|
}
|
||||||
} else {
|
else {
|
||||||
|
|
||||||
/* We don't have unwind information tables */
|
/* We don't have unwind information tables */
|
||||||
UnwState state;
|
UnwState state;
|
||||||
|
@ -48,12 +46,7 @@ UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data)
|
||||||
UnwInitState(&state, cb, data, frame->pc, frame->sp);
|
UnwInitState(&state, cb, data, frame->pc, frame->sp);
|
||||||
|
|
||||||
/* Check the Thumb bit */
|
/* Check the Thumb bit */
|
||||||
if(frame->pc & 0x1) {
|
return (frame->pc & 0x1) ? UnwStartThumb(&state) : UnwStartArm(&state);
|
||||||
return UnwStartThumb(&state);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return UnwStartArm(&state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -143,7 +143,7 @@ public:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EP_M876:
|
case EP_M876:
|
||||||
switch(c) {
|
switch (c) {
|
||||||
case ' ': break;
|
case ' ': break;
|
||||||
case 'S': state = EP_M876S; break;
|
case 'S': state = EP_M876S; break;
|
||||||
default: state = EP_IGNORE; break;
|
default: state = EP_IGNORE; break;
|
||||||
|
|
|
@ -557,7 +557,7 @@ void MMU2::toolChange(const char* special) {
|
||||||
set_runout_valid(false);
|
set_runout_valid(false);
|
||||||
KEEPALIVE_STATE(IN_HANDLER);
|
KEEPALIVE_STATE(IN_HANDLER);
|
||||||
|
|
||||||
switch(*special) {
|
switch (*special) {
|
||||||
case '?': {
|
case '?': {
|
||||||
uint8_t index = mmu2_chooseFilament();
|
uint8_t index = mmu2_chooseFilament();
|
||||||
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
|
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
|
||||||
|
|
|
@ -248,7 +248,7 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t
|
||||||
|
|
||||||
park_above_object(m, uncertainty);
|
park_above_object(m, uncertainty);
|
||||||
|
|
||||||
switch(side) {
|
switch (side) {
|
||||||
case TOP: {
|
case TOP: {
|
||||||
const float measurement = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty);
|
const float measurement = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty);
|
||||||
m.obj_center[Z_AXIS] = measurement - dimensions[Z_AXIS] / 2;
|
m.obj_center[Z_AXIS] = measurement - dimensions[Z_AXIS] / 2;
|
||||||
|
|
|
@ -112,7 +112,7 @@ static const uint8_t u8g_dev_sh1106_128x64_init_seq_2_wire[] PROGMEM = {
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t u8g_dev_sh1106_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
uint8_t u8g_dev_sh1106_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_DEV_MSG_INIT:
|
case U8G_DEV_MSG_INIT:
|
||||||
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
|
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
|
||||||
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_init_seq_2_wire);
|
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_init_seq_2_wire);
|
||||||
|
@ -180,7 +180,7 @@ static const uint8_t u8g_dev_ssd1306_128x64_init_seq_2_wire[] PROGMEM = {
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t u8g_dev_ssd1306_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
uint8_t u8g_dev_ssd1306_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_DEV_MSG_INIT:
|
case U8G_DEV_MSG_INIT:
|
||||||
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
|
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
|
||||||
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_init_seq_2_wire);
|
u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_init_seq_2_wire);
|
||||||
|
@ -227,7 +227,7 @@ u8g_dev_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire = { u8g_dev_ssd1306_128x64_2x_2_w
|
||||||
uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_seq) {
|
uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_seq) {
|
||||||
uint8_t is_escape = 0;
|
uint8_t is_escape = 0;
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
for(;;) {
|
for (;;) {
|
||||||
value = u8g_pgm_read(esc_seq);
|
value = u8g_pgm_read(esc_seq);
|
||||||
if (is_escape == 0) {
|
if (is_escape == 0) {
|
||||||
if (value != 255) {
|
if (value != 255) {
|
||||||
|
|
|
@ -149,7 +149,7 @@ static const uint8_t u8g_dev_st7565_64128n_HAL_sleep_off[] PROGMEM = {
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t u8g_dev_st7565_64128n_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, const uint8_t msg, void *arg) {
|
uint8_t u8g_dev_st7565_64128n_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, const uint8_t msg, void *arg) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_DEV_MSG_INIT:
|
case U8G_DEV_MSG_INIT:
|
||||||
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
|
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
|
||||||
u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7565_64128n_HAL_init_seq);
|
u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7565_64128n_HAL_init_seq);
|
||||||
|
@ -183,7 +183,7 @@ uint8_t u8g_dev_st7565_64128n_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, const uint8_t m
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8g_dev_st7565_64128n_HAL_2x_fn(u8g_t *u8g, u8g_dev_t *dev, const uint8_t msg, void *arg) {
|
uint8_t u8g_dev_st7565_64128n_HAL_2x_fn(u8g_t *u8g, u8g_dev_t *dev, const uint8_t msg, void *arg) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_DEV_MSG_INIT:
|
case U8G_DEV_MSG_INIT:
|
||||||
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
|
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
|
||||||
u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7565_64128n_HAL_init_seq);
|
u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7565_64128n_HAL_init_seq);
|
||||||
|
|
|
@ -106,7 +106,7 @@ void clear_graphics_DRAM(u8g_t *u8g, u8g_dev_t *dev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8g_dev_st7920_128x64_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
uint8_t u8g_dev_st7920_128x64_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_DEV_MSG_INIT:
|
case U8G_DEV_MSG_INIT:
|
||||||
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
|
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
|
||||||
u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7920_128x64_HAL_init_seq);
|
u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7920_128x64_HAL_init_seq);
|
||||||
|
@ -149,7 +149,7 @@ uint8_t u8g_dev_st7920_128x64_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, vo
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8g_dev_st7920_128x64_HAL_4x_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
uint8_t u8g_dev_st7920_128x64_HAL_4x_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_DEV_MSG_INIT:
|
case U8G_DEV_MSG_INIT:
|
||||||
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
|
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
|
||||||
u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7920_128x64_HAL_init_seq);
|
u8g_WriteEscSeqP(u8g, dev, u8g_dev_st7920_128x64_HAL_init_seq);
|
||||||
|
|
|
@ -125,7 +125,7 @@ uint8_t u8g_dev_tft_320x240_upscale_from_128x64_fn(u8g_t *u8g, u8g_dev_t *dev, u
|
||||||
uint16_t buffer[256];
|
uint16_t buffer[256];
|
||||||
uint32_t i, j, k;
|
uint32_t i, j, k;
|
||||||
|
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_DEV_MSG_INIT:
|
case U8G_DEV_MSG_INIT:
|
||||||
dev->com_fn(u8g, U8G_COM_MSG_INIT, U8G_SPI_CLK_CYCLE_NONE, &lcd_id);
|
dev->com_fn(u8g, U8G_COM_MSG_INIT, U8G_SPI_CLK_CYCLE_NONE, &lcd_id);
|
||||||
if (lcd_id == 0x040404) return 0; // No connected display on FSMC
|
if (lcd_id == 0x040404) return 0; // No connected display on FSMC
|
||||||
|
|
|
@ -109,7 +109,7 @@ static const uint8_t u8g_dev_uc1701_mini12864_HAL_data_start[] PROGMEM = {
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t u8g_dev_uc1701_mini12864_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
uint8_t u8g_dev_uc1701_mini12864_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_DEV_MSG_INIT:
|
case U8G_DEV_MSG_INIT:
|
||||||
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
|
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
|
||||||
u8g_WriteEscSeqP(u8g, dev, u8g_dev_uc1701_mini12864_HAL_init_seq);
|
u8g_WriteEscSeqP(u8g, dev, u8g_dev_uc1701_mini12864_HAL_init_seq);
|
||||||
|
@ -138,7 +138,7 @@ uint8_t u8g_dev_uc1701_mini12864_HAL_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg,
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8g_dev_uc1701_mini12864_HAL_2x_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
uint8_t u8g_dev_uc1701_mini12864_HAL_2x_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case U8G_DEV_MSG_INIT:
|
case U8G_DEV_MSG_INIT:
|
||||||
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
|
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
|
||||||
u8g_WriteEscSeqP(u8g, dev, u8g_dev_uc1701_mini12864_HAL_init_seq);
|
u8g_WriteEscSeqP(u8g, dev, u8g_dev_uc1701_mini12864_HAL_init_seq);
|
||||||
|
|
|
@ -339,7 +339,7 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
|
||||||
|
|
||||||
#if ENABLED(SD_CHECK_AND_RETRY)
|
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||||
uint8_t retryCnt = 3;
|
uint8_t retryCnt = 3;
|
||||||
for(;;) {
|
for (;;) {
|
||||||
if (cardCommand(CMD17, blockNumber))
|
if (cardCommand(CMD17, blockNumber))
|
||||||
error(SD_CARD_ERROR_CMD17);
|
error(SD_CARD_ERROR_CMD17);
|
||||||
else if (readData(dst, 512))
|
else if (readData(dst, 512))
|
||||||
|
|
|
@ -35,98 +35,98 @@ static uint8_t usb_task_state;
|
||||||
|
|
||||||
/* constructor */
|
/* constructor */
|
||||||
USB::USB() : bmHubPre(0) {
|
USB::USB() : bmHubPre(0) {
|
||||||
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
|
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize data structures */
|
/* Initialize data structures */
|
||||||
void USB::init() {
|
void USB::init() {
|
||||||
//devConfigIndex = 0;
|
//devConfigIndex = 0;
|
||||||
bmHubPre = 0;
|
bmHubPre = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t USB::getUsbTaskState(void) {
|
uint8_t USB::getUsbTaskState(void) {
|
||||||
return ( usb_task_state);
|
return ( usb_task_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void USB::setUsbTaskState(uint8_t state) {
|
void USB::setUsbTaskState(uint8_t state) {
|
||||||
usb_task_state = state;
|
usb_task_state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) {
|
EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) {
|
||||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||||
|
|
||||||
if(!p || !p->epinfo)
|
if (!p || !p->epinfo)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
EpInfo *pep = p->epinfo;
|
EpInfo *pep = p->epinfo;
|
||||||
|
|
||||||
for(uint8_t i = 0; i < p->epcount; i++) {
|
for (uint8_t i = 0; i < p->epcount; i++) {
|
||||||
if((pep)->epAddr == ep)
|
if ((pep)->epAddr == ep)
|
||||||
return pep;
|
return pep;
|
||||||
|
|
||||||
pep++;
|
pep++;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set device table entry */
|
/* set device table entry */
|
||||||
|
|
||||||
/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
|
/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
|
||||||
uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) {
|
uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) {
|
||||||
if(!eprecord_ptr)
|
if (!eprecord_ptr)
|
||||||
return USB_ERROR_INVALID_ARGUMENT;
|
return USB_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||||
|
|
||||||
if(!p)
|
if (!p)
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
p->address.devAddress = addr;
|
p->address.devAddress = addr;
|
||||||
p->epinfo = eprecord_ptr;
|
p->epinfo = eprecord_ptr;
|
||||||
p->epcount = epcount;
|
p->epcount = epcount;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit) {
|
uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit) {
|
||||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||||
|
|
||||||
if(!p)
|
if (!p)
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
if(!p->epinfo)
|
if (!p->epinfo)
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
return USB_ERROR_EPINFO_IS_NULL;
|
||||||
|
|
||||||
*ppep = getEpInfoEntry(addr, ep);
|
*ppep = getEpInfoEntry(addr, ep);
|
||||||
|
|
||||||
if(!*ppep)
|
if (!*ppep)
|
||||||
return USB_ERROR_EP_NOT_FOUND_IN_TBL;
|
return USB_ERROR_EP_NOT_FOUND_IN_TBL;
|
||||||
|
|
||||||
*nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
|
*nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
|
||||||
(*nak_limit)--;
|
(*nak_limit)--;
|
||||||
/*
|
/*
|
||||||
USBTRACE2("\r\nAddress: ", addr);
|
USBTRACE2("\r\nAddress: ", addr);
|
||||||
USBTRACE2(" EP: ", ep);
|
USBTRACE2(" EP: ", ep);
|
||||||
USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
|
USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
|
||||||
USBTRACE2(" NAK Limit: ", nak_limit);
|
USBTRACE2(" NAK Limit: ", nak_limit);
|
||||||
USBTRACE("\r\n");
|
USBTRACE("\r\n");
|
||||||
*/
|
*/
|
||||||
regWr(rPERADDR, addr); //set peripheral address
|
regWr(rPERADDR, addr); //set peripheral address
|
||||||
|
|
||||||
uint8_t mode = regRd(rMODE);
|
uint8_t mode = regRd(rMODE);
|
||||||
|
|
||||||
//Serial.print("\r\nMode: ");
|
//Serial.print("\r\nMode: ");
|
||||||
//Serial.println( mode, HEX);
|
//Serial.println( mode, HEX);
|
||||||
//Serial.print("\r\nLS: ");
|
//Serial.print("\r\nLS: ");
|
||||||
//Serial.println(p->lowspeed, HEX);
|
//Serial.println(p->lowspeed, HEX);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
|
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
|
||||||
regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
|
regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
|
/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
|
||||||
|
@ -136,166 +136,152 @@ uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_l
|
||||||
|
|
||||||
/* 01-0f = non-zero HRSLT */
|
/* 01-0f = non-zero HRSLT */
|
||||||
uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
||||||
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) {
|
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) {
|
||||||
bool direction = false; //request direction, IN or OUT
|
bool direction = false; //request direction, IN or OUT
|
||||||
uint8_t rcode;
|
uint8_t rcode;
|
||||||
SETUP_PKT setup_pkt;
|
SETUP_PKT setup_pkt;
|
||||||
|
|
||||||
EpInfo *pep = NULL;
|
EpInfo *pep = NULL;
|
||||||
uint16_t nak_limit = 0;
|
uint16_t nak_limit = 0;
|
||||||
|
|
||||||
rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
||||||
|
if (rcode) return rcode;
|
||||||
|
|
||||||
if(rcode)
|
direction = ((bmReqType & 0x80) > 0);
|
||||||
return rcode;
|
|
||||||
|
|
||||||
direction = ((bmReqType & 0x80) > 0);
|
/* fill in setup packet */
|
||||||
|
setup_pkt.ReqType_u.bmRequestType = bmReqType;
|
||||||
|
setup_pkt.bRequest = bRequest;
|
||||||
|
setup_pkt.wVal_u.wValueLo = wValLo;
|
||||||
|
setup_pkt.wVal_u.wValueHi = wValHi;
|
||||||
|
setup_pkt.wIndex = wInd;
|
||||||
|
setup_pkt.wLength = total;
|
||||||
|
|
||||||
/* fill in setup packet */
|
bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO
|
||||||
setup_pkt.ReqType_u.bmRequestType = bmReqType;
|
|
||||||
setup_pkt.bRequest = bRequest;
|
|
||||||
setup_pkt.wVal_u.wValueLo = wValLo;
|
|
||||||
setup_pkt.wVal_u.wValueHi = wValHi;
|
|
||||||
setup_pkt.wIndex = wInd;
|
|
||||||
setup_pkt.wLength = total;
|
|
||||||
|
|
||||||
bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO
|
rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet
|
||||||
|
if (rcode) return rcode; // Return HRSLT if not zero
|
||||||
|
|
||||||
rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet
|
if (dataptr != NULL) { //data stage, if present
|
||||||
|
if (direction) { //IN transfer
|
||||||
|
uint16_t left = total;
|
||||||
|
pep->bmRcvToggle = 1; //bmRCVTOG1;
|
||||||
|
|
||||||
if(rcode) //return HRSLT if not zero
|
while (left) {
|
||||||
return ( rcode);
|
// Bytes read into buffer
|
||||||
|
uint16_t read = nbytes;
|
||||||
|
//uint16_t read = (left<nbytes) ? left : nbytes;
|
||||||
|
|
||||||
if(dataptr != NULL) //data stage, if present
|
rcode = InTransfer(pep, nak_limit, &read, dataptr);
|
||||||
{
|
if (rcode == hrTOGERR) {
|
||||||
if(direction) //IN transfer
|
// yes, we flip it wrong here so that next time it is actually correct!
|
||||||
{
|
pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
||||||
uint16_t left = total;
|
continue;
|
||||||
|
|
||||||
pep->bmRcvToggle = 1; //bmRCVTOG1;
|
|
||||||
|
|
||||||
while(left) {
|
|
||||||
// Bytes read into buffer
|
|
||||||
uint16_t read = nbytes;
|
|
||||||
//uint16_t read = (left<nbytes) ? left : nbytes;
|
|
||||||
|
|
||||||
rcode = InTransfer(pep, nak_limit, &read, dataptr);
|
|
||||||
if(rcode == hrTOGERR) {
|
|
||||||
// yes, we flip it wrong here so that next time it is actually correct!
|
|
||||||
pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rcode)
|
|
||||||
return rcode;
|
|
||||||
|
|
||||||
// Invoke callback function if inTransfer completed successfully and callback function pointer is specified
|
|
||||||
if(!rcode && p)
|
|
||||||
((USBReadParser*)p)->Parse(read, dataptr, total - left);
|
|
||||||
|
|
||||||
left -= read;
|
|
||||||
|
|
||||||
if(read < nbytes)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else //OUT transfer
|
|
||||||
{
|
|
||||||
pep->bmSndToggle = 1; //bmSNDTOG1;
|
|
||||||
rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
|
|
||||||
}
|
|
||||||
if(rcode) //return error
|
|
||||||
return ( rcode);
|
|
||||||
}
|
}
|
||||||
// Status stage
|
|
||||||
return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction
|
if (rcode) return rcode;
|
||||||
|
|
||||||
|
// Invoke callback function if inTransfer completed successfully and callback function pointer is specified
|
||||||
|
if (!rcode && p) ((USBReadParser*)p)->Parse(read, dataptr, total - left);
|
||||||
|
|
||||||
|
left -= read;
|
||||||
|
|
||||||
|
if (read < nbytes) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { //OUT transfer
|
||||||
|
pep->bmSndToggle = 1; //bmSNDTOG1;
|
||||||
|
rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
|
||||||
|
}
|
||||||
|
if (rcode) return rcode; // return error
|
||||||
|
}
|
||||||
|
// Status stage
|
||||||
|
return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
|
/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
|
||||||
/* Keep sending INs and writes data to memory area pointed by 'data' */
|
/* Keep sending INs and writes data to memory area pointed by 'data' */
|
||||||
|
|
||||||
/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
|
/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
|
||||||
fe USB xfer timeout */
|
fe USB xfer timeout */
|
||||||
uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/) {
|
uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/) {
|
||||||
EpInfo *pep = NULL;
|
EpInfo *pep = NULL;
|
||||||
uint16_t nak_limit = 0;
|
uint16_t nak_limit = 0;
|
||||||
|
|
||||||
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
||||||
|
if (rcode) {
|
||||||
if(rcode) {
|
USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81);
|
||||||
USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81);
|
USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81);
|
||||||
USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81);
|
USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81);
|
||||||
USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81);
|
return rcode;
|
||||||
return rcode;
|
}
|
||||||
}
|
return InTransfer(pep, nak_limit, nbytesptr, data, bInterval);
|
||||||
return InTransfer(pep, nak_limit, nbytesptr, data, bInterval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/) {
|
uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/) {
|
||||||
uint8_t rcode = 0;
|
uint8_t rcode = 0;
|
||||||
uint8_t pktsize;
|
uint8_t pktsize;
|
||||||
|
|
||||||
uint16_t nbytes = *nbytesptr;
|
uint16_t nbytes = *nbytesptr;
|
||||||
//printf("Requesting %i bytes ", nbytes);
|
//printf("Requesting %i bytes ", nbytes);
|
||||||
uint8_t maxpktsize = pep->maxPktSize;
|
uint8_t maxpktsize = pep->maxPktSize;
|
||||||
|
|
||||||
*nbytesptr = 0;
|
*nbytesptr = 0;
|
||||||
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
|
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
|
||||||
|
|
||||||
// use a 'break' to exit this loop
|
// use a 'break' to exit this loop
|
||||||
while(1) {
|
for (;;) {
|
||||||
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
|
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
|
||||||
if(rcode == hrTOGERR) {
|
if (rcode == hrTOGERR) {
|
||||||
// yes, we flip it wrong here so that next time it is actually correct!
|
// yes, we flip it wrong here so that next time it is actually correct!
|
||||||
pep->bmRcvToggle = (regRd(rHRSL) & bmRCVTOGRD) ? 0 : 1;
|
pep->bmRcvToggle = (regRd(rHRSL) & bmRCVTOGRD) ? 0 : 1;
|
||||||
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
|
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(rcode) {
|
if (rcode) {
|
||||||
//printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
|
//printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
|
||||||
break; //should be 0, indicating ACK. Else return error code.
|
break; //should be 0, indicating ACK. Else return error code.
|
||||||
}
|
}
|
||||||
/* check for RCVDAVIRQ and generate error if not present */
|
/* check for RCVDAVIRQ and generate error if not present */
|
||||||
/* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
|
/* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
|
||||||
if((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
|
if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
|
||||||
//printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
|
//printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
|
||||||
rcode = 0xf0; //receive error
|
rcode = 0xF0; //receive error
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pktsize = regRd(rRCVBC); //number of received bytes
|
pktsize = regRd(rRCVBC); //number of received bytes
|
||||||
//printf("Got %i bytes \r\n", pktsize);
|
//printf("Got %i bytes \r\n", pktsize);
|
||||||
// This would be OK, but...
|
// This would be OK, but...
|
||||||
//assert(pktsize <= nbytes);
|
//assert(pktsize <= nbytes);
|
||||||
if(pktsize > nbytes) {
|
if (pktsize > nbytes) {
|
||||||
// This can happen. Use of assert on Arduino locks up the Arduino.
|
// This can happen. Use of assert on Arduino locks up the Arduino.
|
||||||
// So I will trim the value, and hope for the best.
|
// So I will trim the value, and hope for the best.
|
||||||
//printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
|
//printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
|
||||||
pktsize = nbytes;
|
pktsize = nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
|
int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
|
||||||
|
if (mem_left < 0) mem_left = 0;
|
||||||
|
|
||||||
if(mem_left < 0)
|
data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
|
||||||
mem_left = 0;
|
|
||||||
|
|
||||||
data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
|
regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer
|
||||||
|
*nbytesptr += pktsize; // add this packet's byte count to total transfer length
|
||||||
|
|
||||||
regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer
|
/* The transfer is complete under two conditions: */
|
||||||
*nbytesptr += pktsize; // add this packet's byte count to total transfer length
|
/* 1. The device sent a short packet (L.T. maxPacketSize) */
|
||||||
|
/* 2. 'nbytes' have been transferred. */
|
||||||
/* The transfer is complete under two conditions: */
|
if (pktsize < maxpktsize || *nbytesptr >= nbytes) { // Transferred 'nbytes' bytes?
|
||||||
/* 1. The device sent a short packet (L.T. maxPacketSize) */
|
// Save toggle value
|
||||||
/* 2. 'nbytes' have been transferred. */
|
pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
|
||||||
if((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes?
|
//printf("\r\n");
|
||||||
{
|
rcode = 0;
|
||||||
// Save toggle value
|
break;
|
||||||
pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
|
}
|
||||||
//printf("\r\n");
|
else if (bInterval > 0)
|
||||||
rcode = 0;
|
delay(bInterval); // Delay according to polling interval
|
||||||
break;
|
}
|
||||||
} else if(bInterval > 0)
|
return rcode;
|
||||||
delay(bInterval); // Delay according to polling interval
|
|
||||||
} //while( 1 )
|
|
||||||
return ( rcode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
|
/* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
|
||||||
|
@ -303,336 +289,324 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
|
||||||
|
|
||||||
/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
|
/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
|
||||||
uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
|
uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
|
||||||
EpInfo *pep = NULL;
|
EpInfo *pep = NULL;
|
||||||
uint16_t nak_limit = 0;
|
uint16_t nak_limit = 0;
|
||||||
|
|
||||||
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
||||||
|
if (rcode) return rcode;
|
||||||
|
|
||||||
if(rcode)
|
return OutTransfer(pep, nak_limit, nbytes, data);
|
||||||
return rcode;
|
|
||||||
|
|
||||||
return OutTransfer(pep, nak_limit, nbytes, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
|
uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
|
||||||
uint8_t rcode = hrSUCCESS, retry_count;
|
uint8_t rcode = hrSUCCESS, retry_count;
|
||||||
uint8_t *data_p = data; //local copy of the data pointer
|
uint8_t *data_p = data; //local copy of the data pointer
|
||||||
uint16_t bytes_tosend, nak_count;
|
uint16_t bytes_tosend, nak_count;
|
||||||
uint16_t bytes_left = nbytes;
|
uint16_t bytes_left = nbytes;
|
||||||
|
|
||||||
uint8_t maxpktsize = pep->maxPktSize;
|
uint8_t maxpktsize = pep->maxPktSize;
|
||||||
|
|
||||||
if(maxpktsize < 1 || maxpktsize > 64)
|
if (maxpktsize < 1 || maxpktsize > 64)
|
||||||
return USB_ERROR_INVALID_MAX_PKT_SIZE;
|
return USB_ERROR_INVALID_MAX_PKT_SIZE;
|
||||||
|
|
||||||
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
|
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
|
||||||
|
|
||||||
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
|
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
|
||||||
|
|
||||||
while(bytes_left) {
|
while (bytes_left) {
|
||||||
retry_count = 0;
|
retry_count = 0;
|
||||||
nak_count = 0;
|
nak_count = 0;
|
||||||
bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
|
bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
|
||||||
bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
|
bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
|
||||||
regWr(rSNDBC, bytes_tosend); //set number of bytes
|
regWr(rSNDBC, bytes_tosend); //set number of bytes
|
||||||
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
|
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
|
||||||
while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
|
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
|
||||||
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
|
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
|
||||||
rcode = (regRd(rHRSL) & 0x0f);
|
rcode = (regRd(rHRSL) & 0x0F);
|
||||||
|
|
||||||
while(rcode && ((int32_t)((uint32_t)millis() - timeout) < 0L)) {
|
while (rcode && ((int32_t)((uint32_t)millis() - timeout) < 0L)) {
|
||||||
switch(rcode) {
|
switch (rcode) {
|
||||||
case hrNAK:
|
case hrNAK:
|
||||||
nak_count++;
|
nak_count++;
|
||||||
if(nak_limit && (nak_count == nak_limit))
|
if (nak_limit && (nak_count == nak_limit))
|
||||||
goto breakout;
|
goto breakout;
|
||||||
//return ( rcode);
|
//return ( rcode);
|
||||||
break;
|
break;
|
||||||
case hrTIMEOUT:
|
case hrTIMEOUT:
|
||||||
retry_count++;
|
retry_count++;
|
||||||
if(retry_count == USB_RETRY_LIMIT)
|
if (retry_count == USB_RETRY_LIMIT)
|
||||||
goto breakout;
|
goto breakout;
|
||||||
//return ( rcode);
|
//return ( rcode);
|
||||||
break;
|
break;
|
||||||
case hrTOGERR:
|
case hrTOGERR:
|
||||||
// yes, we flip it wrong here so that next time it is actually correct!
|
// yes, we flip it wrong here so that next time it is actually correct!
|
||||||
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
||||||
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
|
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto breakout;
|
goto breakout;
|
||||||
}//switch( rcode
|
}
|
||||||
|
|
||||||
/* process NAK according to Host out NAK bug */
|
/* process NAK according to Host out NAK bug */
|
||||||
regWr(rSNDBC, 0);
|
regWr(rSNDBC, 0);
|
||||||
regWr(rSNDFIFO, *data_p);
|
regWr(rSNDFIFO, *data_p);
|
||||||
regWr(rSNDBC, bytes_tosend);
|
regWr(rSNDBC, bytes_tosend);
|
||||||
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
|
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
|
||||||
while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
|
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
|
||||||
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
|
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
|
||||||
rcode = (regRd(rHRSL) & 0x0f);
|
rcode = (regRd(rHRSL) & 0x0F);
|
||||||
}//while( rcode && ....
|
} // while rcode && ....
|
||||||
bytes_left -= bytes_tosend;
|
bytes_left -= bytes_tosend;
|
||||||
data_p += bytes_tosend;
|
data_p += bytes_tosend;
|
||||||
}//while( bytes_left...
|
} // while bytes_left...
|
||||||
breakout:
|
breakout:
|
||||||
|
|
||||||
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
|
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
|
||||||
return ( rcode); //should be 0 in all cases
|
return ( rcode); //should be 0 in all cases
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
|
/* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
|
||||||
/* If NAK, tries to re-send up to nak_limit times */
|
/* If NAK, tries to re-send up to nak_limit times */
|
||||||
/* If nak_limit == 0, do not count NAKs, exit after timeout */
|
/* If nak_limit == 0, do not count NAKs, exit after timeout */
|
||||||
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
|
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
|
||||||
|
|
||||||
/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */
|
/* return codes 0x00-0x0F are HRSLT( 0x00 being success ), 0xFF means timeout */
|
||||||
uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
|
uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
|
||||||
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
|
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
|
||||||
uint8_t tmpdata;
|
uint8_t tmpdata;
|
||||||
uint8_t rcode = hrSUCCESS;
|
uint8_t rcode = hrSUCCESS;
|
||||||
uint8_t retry_count = 0;
|
uint8_t retry_count = 0;
|
||||||
uint16_t nak_count = 0;
|
uint16_t nak_count = 0;
|
||||||
|
|
||||||
while((int32_t)((uint32_t)millis() - timeout) < 0L) {
|
while ((int32_t)((uint32_t)millis() - timeout) < 0L) {
|
||||||
#if defined(ESP8266) || defined(ESP32)
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
yield(); // needed in order to reset the watchdog timer on the ESP8266
|
yield(); // needed in order to reset the watchdog timer on the ESP8266
|
||||||
#endif
|
#endif
|
||||||
regWr(rHXFR, (token | ep)); //launch the transfer
|
regWr(rHXFR, (token | ep)); //launch the transfer
|
||||||
rcode = USB_ERROR_TRANSFER_TIMEOUT;
|
rcode = USB_ERROR_TRANSFER_TIMEOUT;
|
||||||
|
|
||||||
while((int32_t)((uint32_t)millis() - timeout) < 0L) //wait for transfer completion
|
while ((int32_t)((uint32_t)millis() - timeout) < 0L) { //wait for transfer completion
|
||||||
{
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
#if defined(ESP8266) || defined(ESP32)
|
yield(); // needed to reset the watchdog timer on the ESP8266
|
||||||
yield(); // needed in order to reset the watchdog timer on the ESP8266
|
#endif
|
||||||
#endif
|
tmpdata = regRd(rHIRQ);
|
||||||
tmpdata = regRd(rHIRQ);
|
|
||||||
|
|
||||||
if(tmpdata & bmHXFRDNIRQ) {
|
if (tmpdata & bmHXFRDNIRQ) {
|
||||||
regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
|
regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
|
||||||
rcode = 0x00;
|
rcode = 0x00;
|
||||||
break;
|
break;
|
||||||
}//if( tmpdata & bmHXFRDNIRQ
|
}
|
||||||
|
|
||||||
}//while ( millis() < timeout
|
} // while millis() < timeout
|
||||||
|
|
||||||
//if (rcode != 0x00) //exit if timeout
|
//if (rcode != 0x00) //exit if timeout
|
||||||
// return ( rcode);
|
// return ( rcode);
|
||||||
|
|
||||||
rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
|
rcode = (regRd(rHRSL) & 0x0F); //analyze transfer result
|
||||||
|
|
||||||
switch(rcode) {
|
switch (rcode) {
|
||||||
case hrNAK:
|
case hrNAK:
|
||||||
nak_count++;
|
nak_count++;
|
||||||
if(nak_limit && (nak_count == nak_limit))
|
if (nak_limit && (nak_count == nak_limit))
|
||||||
return (rcode);
|
return (rcode);
|
||||||
break;
|
break;
|
||||||
case hrTIMEOUT:
|
case hrTIMEOUT:
|
||||||
retry_count++;
|
retry_count++;
|
||||||
if(retry_count == USB_RETRY_LIMIT)
|
if (retry_count == USB_RETRY_LIMIT)
|
||||||
return (rcode);
|
return (rcode);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return (rcode);
|
return (rcode);
|
||||||
}//switch( rcode
|
}
|
||||||
|
|
||||||
}//while( timeout > millis()
|
} // while timeout > millis()
|
||||||
return ( rcode);
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USB main task. Performs enumeration/cleanup */
|
/* USB main task. Performs enumeration/cleanup */
|
||||||
void USB::Task(void) //USB state machine
|
void USB::Task(void) { //USB state machine
|
||||||
{
|
uint8_t rcode;
|
||||||
uint8_t rcode;
|
uint8_t tmpdata;
|
||||||
uint8_t tmpdata;
|
static uint32_t delay = 0;
|
||||||
static uint32_t delay = 0;
|
//USB_DEVICE_DESCRIPTOR buf;
|
||||||
//USB_DEVICE_DESCRIPTOR buf;
|
bool lowspeed = false;
|
||||||
bool lowspeed = false;
|
|
||||||
|
|
||||||
MAX3421E::Task();
|
MAX3421E::Task();
|
||||||
|
|
||||||
tmpdata = getVbusState();
|
tmpdata = getVbusState();
|
||||||
|
|
||||||
/* modify USB task state if Vbus changed */
|
/* modify USB task state if Vbus changed */
|
||||||
switch(tmpdata) {
|
switch (tmpdata) {
|
||||||
case SE1: //illegal state
|
case SE1: //illegal state
|
||||||
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
|
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
|
||||||
lowspeed = false;
|
lowspeed = false;
|
||||||
break;
|
break;
|
||||||
case SE0: //disconnected
|
case SE0: //disconnected
|
||||||
if((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
|
if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
|
||||||
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
||||||
lowspeed = false;
|
lowspeed = false;
|
||||||
break;
|
break;
|
||||||
case LSHOST:
|
case LSHOST:
|
||||||
|
lowspeed = true;
|
||||||
|
//intentional fallthrough
|
||||||
|
case FSHOST: //attached
|
||||||
|
if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
|
||||||
|
delay = (uint32_t)millis() + USB_SETTLE_DELAY;
|
||||||
|
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
lowspeed = true;
|
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
|
||||||
//intentional fallthrough
|
if (devConfig[i]) rcode = devConfig[i]->Poll();
|
||||||
case FSHOST: //attached
|
|
||||||
if((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
|
|
||||||
delay = (uint32_t)millis() + USB_SETTLE_DELAY;
|
|
||||||
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}// switch( tmpdata
|
|
||||||
|
|
||||||
for(uint8_t i = 0; i < USB_NUMDEVICES; i++)
|
switch (usb_task_state) {
|
||||||
if(devConfig[i])
|
case USB_DETACHED_SUBSTATE_INITIALIZE:
|
||||||
rcode = devConfig[i]->Poll();
|
init();
|
||||||
|
|
||||||
switch(usb_task_state) {
|
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
|
||||||
case USB_DETACHED_SUBSTATE_INITIALIZE:
|
if (devConfig[i])
|
||||||
init();
|
rcode = devConfig[i]->Release();
|
||||||
|
|
||||||
for(uint8_t i = 0; i < USB_NUMDEVICES; i++)
|
usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
|
||||||
if(devConfig[i])
|
break;
|
||||||
rcode = devConfig[i]->Release();
|
case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
|
||||||
|
break;
|
||||||
|
case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
|
||||||
|
break;
|
||||||
|
case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
|
||||||
|
if ((int32_t)((uint32_t)millis() - delay) >= 0L)
|
||||||
|
usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
|
||||||
|
else break; // don't fall through
|
||||||
|
case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
|
||||||
|
regWr(rHCTL, bmBUSRST); //issue bus reset
|
||||||
|
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
|
||||||
|
break;
|
||||||
|
case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
|
||||||
|
if ((regRd(rHCTL) & bmBUSRST) == 0) {
|
||||||
|
tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
|
||||||
|
regWr(rMODE, tmpdata);
|
||||||
|
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
|
||||||
|
//delay = (uint32_t)millis() + 20; //20ms wait after reset per USB spec
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
|
||||||
|
if (regRd(rHIRQ) & bmFRAMEIRQ) {
|
||||||
|
//when first SOF received _and_ 20ms has passed we can continue
|
||||||
|
/*
|
||||||
|
if (delay < (uint32_t)millis()) //20ms passed
|
||||||
|
usb_task_state = USB_STATE_CONFIGURING;
|
||||||
|
*/
|
||||||
|
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
|
||||||
|
delay = (uint32_t)millis() + 20;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USB_ATTACHED_SUBSTATE_WAIT_RESET:
|
||||||
|
if ((int32_t)((uint32_t)millis() - delay) >= 0L) usb_task_state = USB_STATE_CONFIGURING;
|
||||||
|
else break; // don't fall through
|
||||||
|
case USB_STATE_CONFIGURING:
|
||||||
|
|
||||||
usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
|
//Serial.print("\r\nConf.LS: ");
|
||||||
break;
|
//Serial.println(lowspeed, HEX);
|
||||||
case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
|
|
||||||
break;
|
|
||||||
case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
|
|
||||||
break;
|
|
||||||
case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
|
|
||||||
if((int32_t)((uint32_t)millis() - delay) >= 0L)
|
|
||||||
usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
|
|
||||||
else break; // don't fall through
|
|
||||||
case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
|
|
||||||
regWr(rHCTL, bmBUSRST); //issue bus reset
|
|
||||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
|
|
||||||
break;
|
|
||||||
case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
|
|
||||||
if((regRd(rHCTL) & bmBUSRST) == 0) {
|
|
||||||
tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
|
|
||||||
regWr(rMODE, tmpdata);
|
|
||||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
|
|
||||||
//delay = (uint32_t)millis() + 20; //20ms wait after reset per USB spec
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
|
|
||||||
if(regRd(rHIRQ) & bmFRAMEIRQ) {
|
|
||||||
//when first SOF received _and_ 20ms has passed we can continue
|
|
||||||
/*
|
|
||||||
if (delay < (uint32_t)millis()) //20ms passed
|
|
||||||
usb_task_state = USB_STATE_CONFIGURING;
|
|
||||||
*/
|
|
||||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
|
|
||||||
delay = (uint32_t)millis() + 20;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case USB_ATTACHED_SUBSTATE_WAIT_RESET:
|
|
||||||
if((int32_t)((uint32_t)millis() - delay) >= 0L) usb_task_state = USB_STATE_CONFIGURING;
|
|
||||||
else break; // don't fall through
|
|
||||||
case USB_STATE_CONFIGURING:
|
|
||||||
|
|
||||||
//Serial.print("\r\nConf.LS: ");
|
rcode = Configuring(0, 0, lowspeed);
|
||||||
//Serial.println(lowspeed, HEX);
|
|
||||||
|
|
||||||
rcode = Configuring(0, 0, lowspeed);
|
if (!rcode)
|
||||||
|
usb_task_state = USB_STATE_RUNNING;
|
||||||
if(rcode) {
|
else if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
|
||||||
if(rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
|
usb_error = rcode;
|
||||||
usb_error = rcode;
|
usb_task_state = USB_STATE_ERROR;
|
||||||
usb_task_state = USB_STATE_ERROR;
|
}
|
||||||
}
|
break;
|
||||||
} else
|
case USB_STATE_RUNNING:
|
||||||
usb_task_state = USB_STATE_RUNNING;
|
break;
|
||||||
break;
|
case USB_STATE_ERROR:
|
||||||
case USB_STATE_RUNNING:
|
//MAX3421E::Init();
|
||||||
break;
|
break;
|
||||||
case USB_STATE_ERROR:
|
}
|
||||||
//MAX3421E::Init();
|
|
||||||
break;
|
|
||||||
} // switch( usb_task_state )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
|
uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
//uint8_t buf[12];
|
//uint8_t buf[12];
|
||||||
uint8_t rcode;
|
uint8_t rcode;
|
||||||
UsbDevice *p0 = NULL, *p = NULL;
|
UsbDevice *p0 = NULL, *p = NULL;
|
||||||
|
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
p0 = addrPool.GetUsbDevicePtr(0);
|
p0 = addrPool.GetUsbDevicePtr(0);
|
||||||
|
if (!p0) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
if (!p0->epinfo) return USB_ERROR_EPINFO_IS_NULL;
|
||||||
|
|
||||||
if(!p0)
|
p0->lowspeed = lowspeed;
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
|
||||||
|
|
||||||
if(!p0->epinfo)
|
// Allocate new address according to device class
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
|
||||||
|
if (!bAddress) return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||||
|
|
||||||
p0->lowspeed = (lowspeed) ? true : false;
|
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
|
if (!p) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
// Allocate new address according to device class
|
p->lowspeed = lowspeed;
|
||||||
uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
|
|
||||||
|
|
||||||
if(!bAddress)
|
// Assign new address to the device
|
||||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
rcode = setAddr(0, 0, bAddress);
|
||||||
|
if (rcode) {
|
||||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
addrPool.FreeAddress(bAddress);
|
||||||
|
bAddress = 0;
|
||||||
if(!p)
|
}
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
return rcode;
|
||||||
|
|
||||||
p->lowspeed = lowspeed;
|
|
||||||
|
|
||||||
// Assign new address to the device
|
|
||||||
rcode = setAddr(0, 0, bAddress);
|
|
||||||
|
|
||||||
if(rcode) {
|
|
||||||
addrPool.FreeAddress(bAddress);
|
|
||||||
bAddress = 0;
|
|
||||||
return rcode;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) {
|
|
||||||
//printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
|
|
||||||
uint8_t retries = 0;
|
|
||||||
|
|
||||||
again:
|
|
||||||
uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
|
|
||||||
if(rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
|
|
||||||
if(parent == 0) {
|
|
||||||
// Send a bus reset on the root interface.
|
|
||||||
regWr(rHCTL, bmBUSRST); //issue bus reset
|
|
||||||
delay(102); // delay 102ms, compensate for clock inaccuracy.
|
|
||||||
} else {
|
|
||||||
// reset parent port
|
|
||||||
devConfig[parent]->ResetHubPort(port);
|
|
||||||
}
|
|
||||||
} else if(rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
|
|
||||||
delay(100);
|
|
||||||
retries++;
|
|
||||||
goto again;
|
|
||||||
} else if(rcode)
|
|
||||||
return rcode;
|
|
||||||
|
|
||||||
rcode = devConfig[driver]->Init(parent, port, lowspeed);
|
|
||||||
if(rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
|
|
||||||
delay(100);
|
|
||||||
retries++;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
if(rcode) {
|
|
||||||
// Issue a bus reset, because the device may be in a limbo state
|
|
||||||
if(parent == 0) {
|
|
||||||
// Send a bus reset on the root interface.
|
|
||||||
regWr(rHCTL, bmBUSRST); //issue bus reset
|
|
||||||
delay(102); // delay 102ms, compensate for clock inaccuracy.
|
|
||||||
} else {
|
|
||||||
// reset parent port
|
|
||||||
devConfig[parent]->ResetHubPort(port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rcode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
* This is broken. We need to enumerate differently.
|
//printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
|
||||||
|
uint8_t retries = 0;
|
||||||
|
|
||||||
|
again:
|
||||||
|
uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
|
||||||
|
if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
|
||||||
|
if (parent == 0) {
|
||||||
|
// Send a bus reset on the root interface.
|
||||||
|
regWr(rHCTL, bmBUSRST); //issue bus reset
|
||||||
|
delay(102); // delay 102ms, compensate for clock inaccuracy.
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// reset parent port
|
||||||
|
devConfig[parent]->ResetHubPort(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
|
||||||
|
delay(100);
|
||||||
|
retries++;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
else if (rcode)
|
||||||
|
return rcode;
|
||||||
|
|
||||||
|
rcode = devConfig[driver]->Init(parent, port, lowspeed);
|
||||||
|
if (rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
|
||||||
|
delay(100);
|
||||||
|
retries++;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rcode) {
|
||||||
|
// Issue a bus reset, because the device may be in a limbo state
|
||||||
|
if (parent == 0) {
|
||||||
|
// Send a bus reset on the root interface.
|
||||||
|
regWr(rHCTL, bmBUSRST); //issue bus reset
|
||||||
|
delay(102); // delay 102ms, compensate for clock inaccuracy.
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// reset parent port
|
||||||
|
devConfig[parent]->ResetHubPort(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is broken. It needs to enumerate differently.
|
||||||
* It causes major problems with several devices if detected in an unexpected order.
|
* It causes major problems with several devices if detected in an unexpected order.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* Oleg - I wouldn't do anything before the newly connected device is considered sane.
|
* Oleg - I wouldn't do anything before the newly connected device is considered sane.
|
||||||
* i.e.(delays are not indicated for brevity):
|
* i.e.(delays are not indicated for brevity):
|
||||||
* 1. reset
|
* 1. reset
|
||||||
|
@ -649,7 +623,7 @@ again:
|
||||||
* 4: set address
|
* 4: set address
|
||||||
* 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
|
* 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
|
||||||
* 6: while (configurations) {
|
* 6: while (configurations) {
|
||||||
* for(each configuration) {
|
* for (each configuration) {
|
||||||
* for (each driver) {
|
* for (each driver) {
|
||||||
* 6a: Ask device if it likes configuration. Returns 0 on OK.
|
* 6a: Ask device if it likes configuration. Returns 0 on OK.
|
||||||
* If successful, the driver configured device.
|
* If successful, the driver configured device.
|
||||||
|
@ -663,170 +637,161 @@ again:
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* 7: for(each driver) {
|
* 7: for (each driver) {
|
||||||
* 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID
|
* 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID
|
||||||
* 8: if we get here, no driver likes the device plugged in, so exit failure.
|
* 8: if we get here, no driver likes the device plugged in, so exit failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
|
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
//uint8_t bAddress = 0;
|
//uint8_t bAddress = 0;
|
||||||
//printf("Configuring: parent = %i, port = %i\r\n", parent, port);
|
//printf("Configuring: parent = %i, port = %i\r\n", parent, port);
|
||||||
uint8_t devConfigIndex;
|
uint8_t devConfigIndex;
|
||||||
uint8_t rcode = 0;
|
uint8_t rcode = 0;
|
||||||
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
|
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
|
||||||
USB_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR *>(buf);
|
USB_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR *>(buf);
|
||||||
UsbDevice *p = NULL;
|
UsbDevice *p = NULL;
|
||||||
EpInfo *oldep_ptr = NULL;
|
EpInfo *oldep_ptr = NULL;
|
||||||
EpInfo epInfo;
|
EpInfo epInfo;
|
||||||
|
|
||||||
epInfo.epAddr = 0;
|
epInfo.epAddr = 0;
|
||||||
epInfo.maxPktSize = 8;
|
epInfo.maxPktSize = 8;
|
||||||
epInfo.bmSndToggle = 0;
|
epInfo.bmSndToggle = 0;
|
||||||
epInfo.bmRcvToggle = 0;
|
epInfo.bmRcvToggle = 0;
|
||||||
epInfo.bmNakPower = USB_NAK_MAX_POWER;
|
epInfo.bmNakPower = USB_NAK_MAX_POWER;
|
||||||
|
|
||||||
//delay(2000);
|
//delay(2000);
|
||||||
AddressPool &addrPool = GetAddressPool();
|
AddressPool &addrPool = GetAddressPool();
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
p = addrPool.GetUsbDevicePtr(0);
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
if(!p) {
|
if (!p) {
|
||||||
//printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
|
//printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save old pointer to EP_RECORD of address 0
|
// Save old pointer to EP_RECORD of address 0
|
||||||
oldep_ptr = p->epinfo;
|
oldep_ptr = p->epinfo;
|
||||||
|
|
||||||
// Temporary assign new pointer to epInfo to p->epinfo in order to
|
// Temporary assign new pointer to epInfo to p->epinfo in order to
|
||||||
// avoid toggle inconsistence
|
// avoid toggle inconsistence
|
||||||
|
|
||||||
p->epinfo = &epInfo;
|
p->epinfo = &epInfo;
|
||||||
|
|
||||||
p->lowspeed = lowspeed;
|
p->lowspeed = lowspeed;
|
||||||
// Get device descriptor
|
// Get device descriptor
|
||||||
rcode = getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
|
rcode = getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
|
||||||
|
|
||||||
// Restore p->epinfo
|
// Restore p->epinfo
|
||||||
p->epinfo = oldep_ptr;
|
p->epinfo = oldep_ptr;
|
||||||
|
|
||||||
if(rcode) {
|
if (rcode) {
|
||||||
//printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n");
|
//printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n");
|
||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// to-do?
|
// to-do?
|
||||||
// Allocate new address according to device class
|
// Allocate new address according to device class
|
||||||
//bAddress = addrPool.AllocAddress(parent, false, port);
|
//bAddress = addrPool.AllocAddress(parent, false, port);
|
||||||
|
|
||||||
uint16_t vid = udd->idVendor;
|
uint16_t vid = udd->idVendor, pid = udd->idProduct;
|
||||||
uint16_t pid = udd->idProduct;
|
uint8_t klass = udd->bDeviceClass, subklass = udd->bDeviceSubClass;
|
||||||
uint8_t klass = udd->bDeviceClass;
|
|
||||||
uint8_t subklass = udd->bDeviceSubClass;
|
|
||||||
// Attempt to configure if VID/PID or device class matches with a driver
|
|
||||||
// Qualify with subclass too.
|
|
||||||
//
|
|
||||||
// VID/PID & class tests default to false for drivers not yet ported
|
|
||||||
// subclass defaults to true, so you don't have to define it if you don't have to.
|
|
||||||
//
|
|
||||||
for(devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
|
|
||||||
if(!devConfig[devConfigIndex]) continue; // no driver
|
|
||||||
if(devConfig[devConfigIndex]->GetAddress()) continue; // consumed
|
|
||||||
if(devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) {
|
|
||||||
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
|
|
||||||
if(rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(devConfigIndex < USB_NUMDEVICES) {
|
// Attempt to configure if VID/PID or device class matches with a driver
|
||||||
return rcode;
|
// Qualify with subclass too.
|
||||||
}
|
//
|
||||||
|
// VID/PID & class tests default to false for drivers not yet ported
|
||||||
|
// subclass defaults to true, so you don't have to define it if you don't have to.
|
||||||
|
//
|
||||||
|
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
|
||||||
|
if (!devConfig[devConfigIndex]) continue; // no driver
|
||||||
|
if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed
|
||||||
|
if (devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) {
|
||||||
|
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
|
||||||
|
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devConfigIndex < USB_NUMDEVICES) return rcode;
|
||||||
|
|
||||||
// blindly attempt to configure
|
// blindly attempt to configure
|
||||||
for(devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
|
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
|
||||||
if(!devConfig[devConfigIndex]) continue;
|
if (!devConfig[devConfigIndex]) continue;
|
||||||
if(devConfig[devConfigIndex]->GetAddress()) continue; // consumed
|
if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed
|
||||||
if(devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above
|
if (devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above
|
||||||
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
|
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
|
||||||
|
|
||||||
//printf("ERROR ENUMERATING %2.2x\r\n", rcode);
|
//printf("ERROR ENUMERATING %2.2x\r\n", rcode);
|
||||||
if(!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) {
|
if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) {
|
||||||
// in case of an error dev_index should be reset to 0
|
// in case of an error dev_index should be reset to 0
|
||||||
// in order to start from the very beginning the
|
// in order to start from the very beginning the
|
||||||
// next time the program gets here
|
// next time the program gets here
|
||||||
//if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
|
//if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
|
||||||
// devConfigIndex = 0;
|
// devConfigIndex = 0;
|
||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if we get here that means that the device class is not supported by any of registered classes
|
// Arriving here means the device class is unsupported by registered classes
|
||||||
rcode = DefaultAddressing(parent, port, lowspeed);
|
return DefaultAddressing(parent, port, lowspeed);
|
||||||
|
|
||||||
return rcode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t USB::ReleaseDevice(uint8_t addr) {
|
uint8_t USB::ReleaseDevice(uint8_t addr) {
|
||||||
if(!addr)
|
if (addr) {
|
||||||
return 0;
|
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
||||||
|
if (!devConfig[i]) continue;
|
||||||
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
if (devConfig[i]->GetAddress() == addr)
|
||||||
if(!devConfig[i]) continue;
|
return devConfig[i]->Release();
|
||||||
if(devConfig[i]->GetAddress() == addr)
|
}
|
||||||
return devConfig[i]->Release();
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1 //!defined(USB_METHODS_INLINE)
|
#if 1 //!defined(USB_METHODS_INLINE)
|
||||||
//get device descriptor
|
//get device descriptor
|
||||||
|
|
||||||
uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
|
uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
|
||||||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, NULL));
|
return ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, NULL);
|
||||||
}
|
}
|
||||||
//get configuration descriptor
|
//get configuration descriptor
|
||||||
|
|
||||||
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
|
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
|
||||||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL));
|
return ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this
|
/* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this
|
||||||
total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */
|
total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */
|
||||||
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
|
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
|
||||||
const uint8_t bufSize = 64;
|
const uint8_t bufSize = 64;
|
||||||
uint8_t buf[bufSize];
|
uint8_t buf[bufSize];
|
||||||
USB_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR *>(buf);
|
USB_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR *>(buf);
|
||||||
|
|
||||||
uint8_t ret = getConfDescr(addr, ep, 9, conf, buf);
|
uint8_t ret = getConfDescr(addr, ep, 9, conf, buf);
|
||||||
|
if (ret) return ret;
|
||||||
|
|
||||||
if(ret)
|
uint16_t total = ucd->wTotalLength;
|
||||||
return ret;
|
|
||||||
|
|
||||||
uint16_t total = ucd->wTotalLength;
|
//USBTRACE2("\r\ntotal conf.size:", total);
|
||||||
|
|
||||||
//USBTRACE2("\r\ntotal conf.size:", total);
|
return ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p);
|
||||||
|
|
||||||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//get string descriptor
|
//get string descriptor
|
||||||
|
|
||||||
uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) {
|
uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) {
|
||||||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL));
|
return ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL);
|
||||||
}
|
}
|
||||||
//set address
|
//set address
|
||||||
|
|
||||||
uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
|
uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
|
||||||
uint8_t rcode = ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL);
|
uint8_t rcode = ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL);
|
||||||
//delay(2); //per USB 2.0 sect.9.2.6.3
|
//delay(2); //per USB 2.0 sect.9.2.6.3
|
||||||
delay(300); // Older spec says you should wait at least 200ms
|
delay(300); // Older spec says you should wait at least 200ms
|
||||||
return rcode;
|
return rcode;
|
||||||
//return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
|
//return ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL);
|
||||||
}
|
}
|
||||||
//set configuration
|
//set configuration
|
||||||
|
|
||||||
uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
|
uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
|
||||||
return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
|
return ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // defined(USB_METHODS_INLINE)
|
#endif // defined(USB_METHODS_INLINE)
|
||||||
|
|
|
@ -22,8 +22,9 @@
|
||||||
* Web : http://www.circuitsathome.com
|
* Web : http://www.circuitsathome.com
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
/* USB functions */
|
/* USB functions */
|
||||||
#ifndef _usb_h_
|
|
||||||
#define _usb_h_
|
#define _usb_h_
|
||||||
|
|
||||||
#include "../../../inc/MarlinConfigPre.h"
|
#include "../../../inc/MarlinConfigPre.h"
|
||||||
|
@ -50,4 +51,4 @@
|
||||||
#include "parsetools.h"
|
#include "parsetools.h"
|
||||||
#include "confdescparser.h"
|
#include "confdescparser.h"
|
||||||
|
|
||||||
#endif //_usb_h_
|
#undef _usb_h_
|
||||||
|
|
|
@ -231,8 +231,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
|
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
|
||||||
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
||||||
if(!devConfig[i]) {
|
if (!devConfig[i]) {
|
||||||
devConfig[i] = pdev;
|
devConfig[i] = pdev;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,11 @@
|
||||||
* Web : http://www.circuitsathome.com
|
* Web : http://www.circuitsathome.com
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#if !defined(_usb_h_) || defined(__ADDRESS_H__)
|
#ifndef _usb_h_
|
||||||
#error "Never include address.h directly; include Usb.h instead"
|
#error "Never include address.h directly; include Usb.h instead"
|
||||||
#else
|
#endif
|
||||||
#define __ADDRESS_H__
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
|
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
|
||||||
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
|
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
|
||||||
|
@ -38,18 +36,18 @@
|
||||||
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
|
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
|
||||||
|
|
||||||
struct EpInfo {
|
struct EpInfo {
|
||||||
uint8_t epAddr; // Endpoint address
|
uint8_t epAddr; // Endpoint address
|
||||||
uint8_t maxPktSize; // Maximum packet size
|
uint8_t maxPktSize; // Maximum packet size
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint8_t epAttribs;
|
uint8_t epAttribs;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
|
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
|
||||||
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
|
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
|
||||||
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
|
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
};
|
};
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
// 7 6 5 4 3 2 1 0
|
// 7 6 5 4 3 2 1 0
|
||||||
|
@ -63,17 +61,15 @@ struct EpInfo {
|
||||||
//
|
//
|
||||||
|
|
||||||
struct UsbDeviceAddress {
|
struct UsbDeviceAddress {
|
||||||
|
union {
|
||||||
union {
|
struct {
|
||||||
|
uint8_t bmAddress : 3; // device address/port number
|
||||||
struct {
|
uint8_t bmParent : 3; // parent hub address
|
||||||
uint8_t bmAddress : 3; // device address/port number
|
uint8_t bmHub : 1; // hub flag
|
||||||
uint8_t bmParent : 3; // parent hub address
|
uint8_t bmReserved : 1; // reserved, must be zero
|
||||||
uint8_t bmHub : 1; // hub flag
|
} __attribute__((packed));
|
||||||
uint8_t bmReserved : 1; // reserved, must be zero
|
uint8_t devAddress;
|
||||||
} __attribute__((packed));
|
};
|
||||||
uint8_t devAddress;
|
|
||||||
};
|
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
#define bmUSB_DEV_ADDR_ADDRESS 0x07
|
#define bmUSB_DEV_ADDR_ADDRESS 0x07
|
||||||
|
@ -81,18 +77,18 @@ struct UsbDeviceAddress {
|
||||||
#define bmUSB_DEV_ADDR_HUB 0x40
|
#define bmUSB_DEV_ADDR_HUB 0x40
|
||||||
|
|
||||||
struct UsbDevice {
|
struct UsbDevice {
|
||||||
EpInfo *epinfo; // endpoint info pointer
|
EpInfo *epinfo; // endpoint info pointer
|
||||||
UsbDeviceAddress address;
|
UsbDeviceAddress address;
|
||||||
uint8_t epcount; // number of endpoints
|
uint8_t epcount; // number of endpoints
|
||||||
bool lowspeed; // indicates if a device is the low speed one
|
bool lowspeed; // indicates if a device is the low speed one
|
||||||
// uint8_t devclass; // device class
|
// uint8_t devclass; // device class
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
class AddressPool {
|
class AddressPool {
|
||||||
public:
|
public:
|
||||||
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
|
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
|
||||||
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
|
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
|
||||||
virtual void FreeAddress(uint8_t addr) = 0;
|
virtual void FreeAddress(uint8_t addr) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
|
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
|
||||||
|
@ -102,190 +98,174 @@ typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
|
||||||
|
|
||||||
template <const uint8_t MAX_DEVICES_ALLOWED>
|
template <const uint8_t MAX_DEVICES_ALLOWED>
|
||||||
class AddressPoolImpl : public AddressPool {
|
class AddressPoolImpl : public AddressPool {
|
||||||
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
|
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
|
||||||
|
|
||||||
uint8_t hubCounter; // hub counter is kept
|
uint8_t hubCounter; // hub counter is kept
|
||||||
// in order to avoid hub address duplication
|
// in order to avoid hub address duplication
|
||||||
|
|
||||||
UsbDevice thePool[MAX_DEVICES_ALLOWED];
|
UsbDevice thePool[MAX_DEVICES_ALLOWED];
|
||||||
|
|
||||||
// Initializes address pool entry
|
// Initialize address pool entry
|
||||||
|
|
||||||
void InitEntry(uint8_t index) {
|
void InitEntry(uint8_t index) {
|
||||||
thePool[index].address.devAddress = 0;
|
thePool[index].address.devAddress = 0;
|
||||||
thePool[index].epcount = 1;
|
thePool[index].epcount = 1;
|
||||||
thePool[index].lowspeed = 0;
|
thePool[index].lowspeed = 0;
|
||||||
thePool[index].epinfo = &dev0ep;
|
thePool[index].epinfo = &dev0ep;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Returns thePool index for a given address
|
// Return thePool index for a given address
|
||||||
|
|
||||||
uint8_t FindAddressIndex(uint8_t address = 0) {
|
uint8_t FindAddressIndex(uint8_t address = 0) {
|
||||||
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
|
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||||
if(thePool[i].address.devAddress == address)
|
if (thePool[i].address.devAddress == address)
|
||||||
return i;
|
return i;
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns thePool child index for a given parent
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
|
// Return thePool child index for a given parent
|
||||||
for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
|
|
||||||
if(thePool[i].address.bmParent == addr.bmAddress)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Frees address entry specified by index parameter
|
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
|
||||||
|
for (uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
|
||||||
|
if (thePool[i].address.bmParent == addr.bmAddress)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void FreeAddressByIndex(uint8_t index) {
|
// Frees address entry specified by index parameter
|
||||||
// Zero field is reserved and should not be affected
|
|
||||||
if(index == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
UsbDeviceAddress uda = thePool[index].address;
|
void FreeAddressByIndex(uint8_t index) {
|
||||||
// If a hub was switched off all port addresses should be freed
|
// Zero field is reserved and should not be affected
|
||||||
if(uda.bmHub == 1) {
|
if (index == 0) return;
|
||||||
for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
|
|
||||||
FreeAddressByIndex(i);
|
|
||||||
|
|
||||||
// If the hub had the last allocated address, hubCounter should be decremented
|
UsbDeviceAddress uda = thePool[index].address;
|
||||||
if(hubCounter == uda.bmAddress)
|
// If a hub was switched off all port addresses should be freed
|
||||||
hubCounter--;
|
if (uda.bmHub == 1) {
|
||||||
}
|
for (uint8_t i = 1; (i = FindChildIndex(uda, i));)
|
||||||
InitEntry(index);
|
FreeAddressByIndex(i);
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes the whole address pool at once
|
// If the hub had the last allocated address, hubCounter should be decremented
|
||||||
|
if (hubCounter == uda.bmAddress) hubCounter--;
|
||||||
|
}
|
||||||
|
InitEntry(index);
|
||||||
|
}
|
||||||
|
|
||||||
void InitAllAddresses() {
|
// Initialize the whole address pool at once
|
||||||
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
|
||||||
InitEntry(i);
|
|
||||||
|
|
||||||
hubCounter = 0;
|
void InitAllAddresses() {
|
||||||
};
|
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||||
|
InitEntry(i);
|
||||||
|
|
||||||
|
hubCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AddressPoolImpl() : hubCounter(0) {
|
AddressPoolImpl() : hubCounter(0) {
|
||||||
// Zero address is reserved
|
// Zero address is reserved
|
||||||
InitEntry(0);
|
InitEntry(0);
|
||||||
|
|
||||||
thePool[0].address.devAddress = 0;
|
thePool[0].address.devAddress = 0;
|
||||||
thePool[0].epinfo = &dev0ep;
|
thePool[0].epinfo = &dev0ep;
|
||||||
dev0ep.epAddr = 0;
|
dev0ep.epAddr = 0;
|
||||||
dev0ep.maxPktSize = 8;
|
dev0ep.maxPktSize = 8;
|
||||||
dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
|
dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
|
||||||
dev0ep.bmRcvToggle = 0;
|
dev0ep.bmRcvToggle = 0;
|
||||||
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
|
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
|
||||||
|
|
||||||
InitAllAddresses();
|
InitAllAddresses();
|
||||||
};
|
}
|
||||||
|
|
||||||
// Returns a pointer to a specified address entry
|
// Return a pointer to a specified address entry
|
||||||
|
|
||||||
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
|
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
|
||||||
if(!addr)
|
if (!addr) return thePool;
|
||||||
return thePool;
|
uint8_t index = FindAddressIndex(addr);
|
||||||
|
return index ? thePool + index : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t index = FindAddressIndex(addr);
|
// Perform an operation specified by pfunc for each addressed device
|
||||||
|
|
||||||
return (!index) ? NULL : thePool + index;
|
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
||||||
};
|
if (pfunc) {
|
||||||
|
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||||
|
if (thePool[i].address.devAddress)
|
||||||
|
pfunc(thePool + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Performs an operation specified by pfunc for each addressed device
|
// Allocate new address
|
||||||
|
|
||||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
|
||||||
if(!pfunc)
|
/* if (parent != 0 && port == 0)
|
||||||
return;
|
USB_HOST_SERIAL.println("PRT:0"); */
|
||||||
|
UsbDeviceAddress _parent;
|
||||||
|
_parent.devAddress = parent;
|
||||||
|
if (_parent.bmReserved || port > 7)
|
||||||
|
//if(parent > 127 || port > 7)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
if (is_hub && hubCounter == 7) return 0;
|
||||||
if(thePool[i].address.devAddress)
|
|
||||||
pfunc(thePool + i);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allocates new address
|
// finds first empty address entry starting from one
|
||||||
|
uint8_t index = FindAddressIndex(0);
|
||||||
|
|
||||||
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
|
if (!index) return 0; // if empty entry is not found
|
||||||
/* if (parent != 0 && port == 0)
|
|
||||||
USB_HOST_SERIAL.println("PRT:0"); */
|
|
||||||
UsbDeviceAddress _parent;
|
|
||||||
_parent.devAddress = parent;
|
|
||||||
if(_parent.bmReserved || port > 7)
|
|
||||||
//if(parent > 127 || port > 7)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if(is_hub && hubCounter == 7)
|
if (_parent.devAddress == 0) {
|
||||||
return 0;
|
if (is_hub) {
|
||||||
|
thePool[index].address.devAddress = 0x41;
|
||||||
|
hubCounter++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
thePool[index].address.devAddress = 1;
|
||||||
|
|
||||||
// finds first empty address entry starting from one
|
return thePool[index].address.devAddress;
|
||||||
uint8_t index = FindAddressIndex(0);
|
}
|
||||||
|
|
||||||
if(!index) // if empty entry is not found
|
UsbDeviceAddress addr;
|
||||||
return 0;
|
addr.devAddress = 0; // Ensure all bits are zero
|
||||||
|
addr.bmParent = _parent.bmAddress;
|
||||||
|
if (is_hub) {
|
||||||
|
addr.bmHub = 1;
|
||||||
|
addr.bmAddress = ++hubCounter;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addr.bmHub = 0;
|
||||||
|
addr.bmAddress = port;
|
||||||
|
}
|
||||||
|
thePool[index].address = addr;
|
||||||
|
/*
|
||||||
|
USB_HOST_SERIAL.print("Addr:");
|
||||||
|
USB_HOST_SERIAL.print(addr.bmHub, HEX);
|
||||||
|
USB_HOST_SERIAL.print(".");
|
||||||
|
USB_HOST_SERIAL.print(addr.bmParent, HEX);
|
||||||
|
USB_HOST_SERIAL.print(".");
|
||||||
|
USB_HOST_SERIAL.println(addr.bmAddress, HEX);
|
||||||
|
*/
|
||||||
|
return thePool[index].address.devAddress;
|
||||||
|
}
|
||||||
|
|
||||||
if(_parent.devAddress == 0) {
|
// Empty the pool entry
|
||||||
if(is_hub) {
|
|
||||||
thePool[index].address.devAddress = 0x41;
|
|
||||||
hubCounter++;
|
|
||||||
} else
|
|
||||||
thePool[index].address.devAddress = 1;
|
|
||||||
|
|
||||||
return thePool[index].address.devAddress;
|
virtual void FreeAddress(uint8_t addr) {
|
||||||
}
|
// if the root hub is disconnected all the addresses should be initialized
|
||||||
|
if (addr == 0x41) {
|
||||||
|
InitAllAddresses();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FreeAddressByIndex(FindAddressIndex(addr));
|
||||||
|
}
|
||||||
|
|
||||||
UsbDeviceAddress addr;
|
// Return number of hubs attached
|
||||||
addr.devAddress = 0; // Ensure all bits are zero
|
// It can be helpful to find out if hubs are attached when getting the exact number of hubs.
|
||||||
addr.bmParent = _parent.bmAddress;
|
//uint8_t GetNumHubs() { return hubCounter; }
|
||||||
if(is_hub) {
|
//uint8_t GetNumDevices() {
|
||||||
addr.bmHub = 1;
|
// uint8_t counter = 0;
|
||||||
addr.bmAddress = ++hubCounter;
|
// for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||||
} else {
|
// if (thePool[i].address != 0); counter++;
|
||||||
addr.bmHub = 0;
|
// return counter;
|
||||||
addr.bmAddress = port;
|
//}
|
||||||
}
|
|
||||||
thePool[index].address = addr;
|
|
||||||
/*
|
|
||||||
USB_HOST_SERIAL.print("Addr:");
|
|
||||||
USB_HOST_SERIAL.print(addr.bmHub, HEX);
|
|
||||||
USB_HOST_SERIAL.print(".");
|
|
||||||
USB_HOST_SERIAL.print(addr.bmParent, HEX);
|
|
||||||
USB_HOST_SERIAL.print(".");
|
|
||||||
USB_HOST_SERIAL.println(addr.bmAddress, HEX);
|
|
||||||
*/
|
|
||||||
return thePool[index].address.devAddress;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Empties pool entry
|
|
||||||
|
|
||||||
virtual void FreeAddress(uint8_t addr) {
|
|
||||||
// if the root hub is disconnected all the addresses should be initialized
|
|
||||||
if(addr == 0x41) {
|
|
||||||
InitAllAddresses();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint8_t index = FindAddressIndex(addr);
|
|
||||||
FreeAddressByIndex(index);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns number of hubs attached
|
|
||||||
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
|
|
||||||
//uint8_t GetNumHubs()
|
|
||||||
//{
|
|
||||||
// return hubCounter;
|
|
||||||
//};
|
|
||||||
//uint8_t GetNumDevices()
|
|
||||||
//{
|
|
||||||
// uint8_t counter = 0;
|
|
||||||
|
|
||||||
// for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
|
|
||||||
// if (thePool[i].address != 0);
|
|
||||||
// counter ++;
|
|
||||||
|
|
||||||
// return counter;
|
|
||||||
//};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __ADDRESS_H__
|
|
||||||
|
|
|
@ -22,197 +22,180 @@
|
||||||
* Web : http://www.circuitsathome.com
|
* Web : http://www.circuitsathome.com
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
#if !defined(_usb_h_) || defined(__CONFDESCPARSER_H__)
|
#pragma once
|
||||||
#error "Never include confdescparser.h directly; include Usb.h instead"
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define __CONFDESCPARSER_H__
|
#ifndef _usb_h_
|
||||||
|
#error "Never include confdescparser.h directly; include Usb.h instead"
|
||||||
|
#endif
|
||||||
|
|
||||||
class UsbConfigXtracter {
|
class UsbConfigXtracter {
|
||||||
public:
|
public:
|
||||||
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
|
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
|
||||||
//virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
|
//virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
|
||||||
|
|
||||||
virtual void EndpointXtract(uint8_t conf __attribute__((unused)), uint8_t iface __attribute__((unused)), uint8_t alt __attribute__((unused)), uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *ep __attribute__((unused))) {
|
virtual void EndpointXtract(uint8_t conf __attribute__((unused)), uint8_t iface __attribute__((unused)), uint8_t alt __attribute__((unused)), uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *ep __attribute__((unused))) {
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CP_MASK_COMPARE_CLASS 1
|
#define CP_MASK_COMPARE_CLASS 1
|
||||||
#define CP_MASK_COMPARE_SUBCLASS 2
|
#define CP_MASK_COMPARE_SUBCLASS 2
|
||||||
#define CP_MASK_COMPARE_PROTOCOL 4
|
#define CP_MASK_COMPARE_PROTOCOL 4
|
||||||
#define CP_MASK_COMPARE_ALL 7
|
#define CP_MASK_COMPARE_ALL 7
|
||||||
|
|
||||||
// Configuration Descriptor Parser Class Template
|
// Configuration Descriptor Parser Class Template
|
||||||
|
|
||||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
class ConfigDescParser : public USBReadParser {
|
class ConfigDescParser : public USBReadParser {
|
||||||
UsbConfigXtracter *theXtractor;
|
UsbConfigXtracter *theXtractor;
|
||||||
MultiValueBuffer theBuffer;
|
MultiValueBuffer theBuffer;
|
||||||
MultiByteValueParser valParser;
|
MultiByteValueParser valParser;
|
||||||
ByteSkipper theSkipper;
|
ByteSkipper theSkipper;
|
||||||
uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
|
uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
|
||||||
|
|
||||||
uint8_t stateParseDescr; // ParseDescriptor state
|
uint8_t stateParseDescr; // ParseDescriptor state
|
||||||
|
|
||||||
uint8_t dscrLen; // Descriptor length
|
uint8_t dscrLen; // Descriptor length
|
||||||
uint8_t dscrType; // Descriptor type
|
uint8_t dscrType; // Descriptor type
|
||||||
|
|
||||||
bool isGoodInterface; // Apropriate interface flag
|
bool isGoodInterface; // Apropriate interface flag
|
||||||
uint8_t confValue; // Configuration value
|
uint8_t confValue; // Configuration value
|
||||||
uint8_t protoValue; // Protocol value
|
uint8_t protoValue; // Protocol value
|
||||||
uint8_t ifaceNumber; // Interface number
|
uint8_t ifaceNumber; // Interface number
|
||||||
uint8_t ifaceAltSet; // Interface alternate settings
|
uint8_t ifaceAltSet; // Interface alternate settings
|
||||||
|
|
||||||
bool UseOr;
|
bool UseOr;
|
||||||
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
|
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
|
||||||
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void SetOR(void) {
|
void SetOR(void) { UseOr = true; }
|
||||||
UseOr = true;
|
ConfigDescParser(UsbConfigXtracter *xtractor);
|
||||||
}
|
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
|
||||||
ConfigDescParser(UsbConfigXtracter *xtractor);
|
|
||||||
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
|
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
|
||||||
theXtractor(xtractor),
|
theXtractor(xtractor),
|
||||||
stateParseDescr(0),
|
stateParseDescr(0),
|
||||||
dscrLen(0),
|
dscrLen(0),
|
||||||
dscrType(0),
|
dscrType(0),
|
||||||
UseOr(false) {
|
UseOr(false) {
|
||||||
theBuffer.pValue = varBuffer;
|
theBuffer.pValue = varBuffer;
|
||||||
valParser.Initialize(&theBuffer);
|
valParser.Initialize(&theBuffer);
|
||||||
theSkipper.Initialize(&theBuffer);
|
theSkipper.Initialize(&theBuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset __attribute__((unused))) {
|
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset __attribute__((unused))) {
|
||||||
uint16_t cntdn = (uint16_t)len;
|
uint16_t cntdn = (uint16_t)len;
|
||||||
uint8_t *p = (uint8_t*)pbuf;
|
uint8_t *p = (uint8_t*)pbuf;
|
||||||
|
while (cntdn) if (!ParseDescriptor(&p, &cntdn)) return;
|
||||||
while(cntdn)
|
|
||||||
if(!ParseDescriptor(&p, &cntdn))
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
|
/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
|
||||||
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
|
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
|
||||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
|
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
|
||||||
USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
|
USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
|
||||||
USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
|
USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
|
||||||
switch(stateParseDescr) {
|
switch (stateParseDescr) {
|
||||||
case 0:
|
case 0:
|
||||||
theBuffer.valueSize = 2;
|
theBuffer.valueSize = 2;
|
||||||
valParser.Initialize(&theBuffer);
|
valParser.Initialize(&theBuffer);
|
||||||
stateParseDescr = 1;
|
stateParseDescr = 1;
|
||||||
case 1:
|
case 1:
|
||||||
if(!valParser.Parse(pp, pcntdn))
|
if (!valParser.Parse(pp, pcntdn)) return false;
|
||||||
return false;
|
dscrLen = *((uint8_t*)theBuffer.pValue);
|
||||||
dscrLen = *((uint8_t*)theBuffer.pValue);
|
dscrType = *((uint8_t*)theBuffer.pValue + 1);
|
||||||
dscrType = *((uint8_t*)theBuffer.pValue + 1);
|
stateParseDescr = 2;
|
||||||
stateParseDescr = 2;
|
case 2:
|
||||||
case 2:
|
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
|
||||||
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
|
// the pointer is positioned two bytes ahead in order for the rest of descriptor
|
||||||
// the pointer is positioned two bytes ahead in order for the rest of descriptor
|
// to be read right after the size and the type fields.
|
||||||
// to be read right after the size and the type fields.
|
// This should be used carefully. varBuffer should be used directly to handle data
|
||||||
// This should be used carefully. varBuffer should be used directly to handle data
|
// in the buffer.
|
||||||
// in the buffer.
|
theBuffer.pValue = varBuffer + 2;
|
||||||
theBuffer.pValue = varBuffer + 2;
|
stateParseDescr = 3;
|
||||||
stateParseDescr = 3;
|
case 3:
|
||||||
case 3:
|
switch (dscrType) {
|
||||||
switch(dscrType) {
|
case USB_DESCRIPTOR_INTERFACE:
|
||||||
case USB_DESCRIPTOR_INTERFACE:
|
isGoodInterface = false;
|
||||||
isGoodInterface = false;
|
break;
|
||||||
break;
|
case USB_DESCRIPTOR_CONFIGURATION:
|
||||||
case USB_DESCRIPTOR_CONFIGURATION:
|
case USB_DESCRIPTOR_ENDPOINT:
|
||||||
case USB_DESCRIPTOR_ENDPOINT:
|
case HID_DESCRIPTOR_HID:
|
||||||
case HID_DESCRIPTOR_HID:
|
break;
|
||||||
break;
|
}
|
||||||
}
|
theBuffer.valueSize = dscrLen - 2;
|
||||||
theBuffer.valueSize = dscrLen - 2;
|
valParser.Initialize(&theBuffer);
|
||||||
valParser.Initialize(&theBuffer);
|
stateParseDescr = 4;
|
||||||
stateParseDescr = 4;
|
case 4:
|
||||||
case 4:
|
switch (dscrType) {
|
||||||
switch(dscrType) {
|
case USB_DESCRIPTOR_CONFIGURATION:
|
||||||
case USB_DESCRIPTOR_CONFIGURATION:
|
if (!valParser.Parse(pp, pcntdn)) return false;
|
||||||
if(!valParser.Parse(pp, pcntdn))
|
confValue = ucd->bConfigurationValue;
|
||||||
return false;
|
break;
|
||||||
confValue = ucd->bConfigurationValue;
|
case USB_DESCRIPTOR_INTERFACE:
|
||||||
break;
|
if (!valParser.Parse(pp, pcntdn)) return false;
|
||||||
case USB_DESCRIPTOR_INTERFACE:
|
if ((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
|
||||||
if(!valParser.Parse(pp, pcntdn))
|
break;
|
||||||
return false;
|
if ((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
|
||||||
if((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
|
break;
|
||||||
break;
|
if (UseOr) {
|
||||||
if((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
|
if ((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol))) break;
|
||||||
break;
|
}
|
||||||
if(UseOr) {
|
else if ((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
|
||||||
if((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol)))
|
break;
|
||||||
break;
|
isGoodInterface = true;
|
||||||
} else {
|
ifaceNumber = uid->bInterfaceNumber;
|
||||||
if((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
|
ifaceAltSet = uid->bAlternateSetting;
|
||||||
break;
|
protoValue = uid->bInterfaceProtocol;
|
||||||
}
|
break;
|
||||||
isGoodInterface = true;
|
case USB_DESCRIPTOR_ENDPOINT:
|
||||||
ifaceNumber = uid->bInterfaceNumber;
|
if (!valParser.Parse(pp, pcntdn)) return false;
|
||||||
ifaceAltSet = uid->bAlternateSetting;
|
if (isGoodInterface && theXtractor)
|
||||||
protoValue = uid->bInterfaceProtocol;
|
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
|
||||||
break;
|
break;
|
||||||
case USB_DESCRIPTOR_ENDPOINT:
|
//case HID_DESCRIPTOR_HID:
|
||||||
if(!valParser.Parse(pp, pcntdn))
|
// if (!valParser.Parse(pp, pcntdn)) return false;
|
||||||
return false;
|
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
||||||
if(isGoodInterface)
|
// break;
|
||||||
if(theXtractor)
|
default:
|
||||||
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
|
if (!theSkipper.Skip(pp, pcntdn, dscrLen - 2)) return false;
|
||||||
break;
|
}
|
||||||
//case HID_DESCRIPTOR_HID:
|
theBuffer.pValue = varBuffer;
|
||||||
// if (!valParser.Parse(pp, pcntdn))
|
stateParseDescr = 0;
|
||||||
// return false;
|
}
|
||||||
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
return true;
|
||||||
// break;
|
|
||||||
default:
|
|
||||||
if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
theBuffer.pValue = varBuffer;
|
|
||||||
stateParseDescr = 0;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
|
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
|
||||||
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
|
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
|
||||||
Notify(PSTR("bDescLength:\t\t"), 0x80);
|
Notify(PSTR("bDescLength:\t\t"), 0x80);
|
||||||
PrintHex<uint8_t > (pDesc->bLength, 0x80);
|
PrintHex<uint8_t > (pDesc->bLength, 0x80);
|
||||||
|
|
||||||
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
|
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
|
||||||
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
|
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
|
||||||
|
|
||||||
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
|
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
|
||||||
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
|
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
|
||||||
|
|
||||||
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
|
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
|
||||||
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
|
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
|
||||||
|
|
||||||
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
|
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
|
||||||
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
|
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
|
||||||
|
|
||||||
for(uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
|
for (uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
|
||||||
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
||||||
|
|
||||||
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
|
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
|
||||||
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
|
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
|
||||||
|
|
||||||
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
|
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
|
||||||
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
|
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
|
||||||
}
|
}
|
||||||
Notify(PSTR("\r\n"), 0x80);
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // __CONFDESCPARSER_H__
|
|
||||||
|
|
|
@ -22,49 +22,47 @@
|
||||||
* Web : http://www.circuitsathome.com
|
* Web : http://www.circuitsathome.com
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#if !defined(_usb_h_) || defined(__HEXDUMP_H__)
|
#ifndef _usb_h_
|
||||||
#error "Never include hexdump.h directly; include Usb.h instead"
|
#error "Never include hexdump.h directly; include Usb.h instead"
|
||||||
#else
|
#endif
|
||||||
#define __HEXDUMP_H__
|
|
||||||
|
|
||||||
extern int UsbDEBUGlvl;
|
extern int UsbDEBUGlvl;
|
||||||
|
|
||||||
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
||||||
class HexDumper : public BASE_CLASS {
|
class HexDumper : public BASE_CLASS {
|
||||||
uint8_t byteCount;
|
uint8_t byteCount;
|
||||||
OFFSET_TYPE byteTotal;
|
OFFSET_TYPE byteTotal;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HexDumper() : byteCount(0), byteTotal(0) {
|
HexDumper() : byteCount(0), byteTotal(0) {
|
||||||
};
|
};
|
||||||
|
|
||||||
void Initialize() {
|
void Initialize() {
|
||||||
byteCount = 0;
|
byteCount = 0;
|
||||||
byteTotal = 0;
|
byteTotal = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
|
void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
||||||
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset __attribute__((unused))) {
|
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset __attribute__((unused))) {
|
||||||
if(UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
|
if (UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
|
||||||
for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
|
for (LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
|
||||||
if(!byteCount) {
|
if (!byteCount) {
|
||||||
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
|
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
|
||||||
E_Notify(PSTR(": "), 0x80);
|
E_Notify(PSTR(": "), 0x80);
|
||||||
}
|
}
|
||||||
PrintHex<uint8_t > (pbuf[j], 0x80);
|
PrintHex<uint8_t > (pbuf[j], 0x80);
|
||||||
E_Notify(PSTR(" "), 0x80);
|
E_Notify(PSTR(" "), 0x80);
|
||||||
|
|
||||||
if(byteCount == 15) {
|
if (byteCount == 15) {
|
||||||
E_Notify(PSTR("\r\n"), 0x80);
|
E_Notify(PSTR("\r\n"), 0x80);
|
||||||
byteCount = 0xFF;
|
byteCount = 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __HEXDUMP_H__
|
|
||||||
|
|
|
@ -22,13 +22,12 @@
|
||||||
* Web : http://www.circuitsathome.com
|
* Web : http://www.circuitsathome.com
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#ifndef _usb_h_
|
#ifndef _usb_h_
|
||||||
#error "Never include macros.h directly; include Usb.h instead"
|
#error "Never include macros.h directly; include Usb.h instead"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// HANDY MACROS
|
// HANDY MACROS
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -36,7 +35,7 @@
|
||||||
#define VALUE_BETWEEN(v,l,h) (((v)>(l)) && ((v)<(h)))
|
#define VALUE_BETWEEN(v,l,h) (((v)>(l)) && ((v)<(h)))
|
||||||
#define VALUE_WITHIN(v,l,h) (((v)>=(l)) && ((v)<=(h)))
|
#define VALUE_WITHIN(v,l,h) (((v)>=(l)) && ((v)<=(h)))
|
||||||
#define output_pgm_message(wa,fp,mp,el) wa = &mp, fp((char *)pgm_read_pointer(wa), el)
|
#define output_pgm_message(wa,fp,mp,el) wa = &mp, fp((char *)pgm_read_pointer(wa), el)
|
||||||
#define output_if_between(v,l,h,wa,fp,mp,el) if(VALUE_BETWEEN(v,l,h)) output_pgm_message(wa,fp,mp[v-(l+1)],el);
|
#define output_if_between(v,l,h,wa,fp,mp,el) if (VALUE_BETWEEN(v,l,h)) output_pgm_message(wa,fp,mp[v-(l+1)],el);
|
||||||
|
|
||||||
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
|
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
|
||||||
#ifndef __BYTE_GRABBING_DEFINED__
|
#ifndef __BYTE_GRABBING_DEFINED__
|
||||||
|
|
|
@ -44,9 +44,7 @@ const uint8_t BulkOnly::epInterruptInIndex = 3;
|
||||||
* @return media capacity
|
* @return media capacity
|
||||||
*/
|
*/
|
||||||
uint32_t BulkOnly::GetCapacity(uint8_t lun) {
|
uint32_t BulkOnly::GetCapacity(uint8_t lun) {
|
||||||
if(LUNOk[lun])
|
return LUNOk[lun] ? CurrentCapacity[lun] : 0UL;
|
||||||
return CurrentCapacity[lun];
|
|
||||||
return 0LU;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,9 +54,7 @@ uint32_t BulkOnly::GetCapacity(uint8_t lun) {
|
||||||
* @return media sector size
|
* @return media sector size
|
||||||
*/
|
*/
|
||||||
uint16_t BulkOnly::GetSectorSize(uint8_t lun) {
|
uint16_t BulkOnly::GetSectorSize(uint8_t lun) {
|
||||||
if(LUNOk[lun])
|
return LUNOk[lun] ? CurrentSectorSize[lun] : 0U;
|
||||||
return CurrentSectorSize[lun];
|
|
||||||
return 0U;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,9 +63,7 @@ uint16_t BulkOnly::GetSectorSize(uint8_t lun) {
|
||||||
* @param lun Logical Unit Number
|
* @param lun Logical Unit Number
|
||||||
* @return true if LUN is ready for use
|
* @return true if LUN is ready for use
|
||||||
*/
|
*/
|
||||||
bool BulkOnly::LUNIsGood(uint8_t lun) {
|
bool BulkOnly::LUNIsGood(uint8_t lun) { return LUNOk[lun]; }
|
||||||
return LUNOk[lun];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if LUN is write protected
|
* Test if LUN is write protected
|
||||||
|
@ -77,9 +71,7 @@ bool BulkOnly::LUNIsGood(uint8_t lun) {
|
||||||
* @param lun Logical Unit Number
|
* @param lun Logical Unit Number
|
||||||
* @return cached status of write protect switch
|
* @return cached status of write protect switch
|
||||||
*/
|
*/
|
||||||
bool BulkOnly::WriteProtected(uint8_t lun) {
|
bool BulkOnly::WriteProtected(uint8_t lun) { return WriteOk[lun]; }
|
||||||
return WriteOk[lun];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap and execute a SCSI CDB with length of 6
|
* Wrap and execute a SCSI CDB with length of 6
|
||||||
|
@ -91,10 +83,10 @@ bool BulkOnly::WriteProtected(uint8_t lun) {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
|
uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
|
||||||
// promote buf_size to 32bits.
|
// promote buf_size to 32bits.
|
||||||
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
|
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
|
||||||
//SetCurLUN(cdb->LUN);
|
//SetCurLUN(cdb->LUN);
|
||||||
return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
|
return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,10 +99,10 @@ uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, ui
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
|
uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
|
||||||
// promote buf_size to 32bits.
|
// promote buf_size to 32bits.
|
||||||
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
|
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
|
||||||
//SetCurLUN(cdb->LUN);
|
//SetCurLUN(cdb->LUN);
|
||||||
return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
|
return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,11 +114,11 @@ uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf,
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) {
|
uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) {
|
||||||
Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
|
Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
|
||||||
Notify(PSTR("---------\r\n"), 0x80);
|
Notify(PSTR("---------\r\n"), 0x80);
|
||||||
|
|
||||||
CDB6_t cdb = CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock);
|
CDB6_t cdb = CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock);
|
||||||
return SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_IN);
|
return SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,17 +130,18 @@ uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) {
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
|
uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
|
||||||
Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
|
Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
|
||||||
Notify(PSTR("-----------------\r\n"), 0x80);
|
Notify(PSTR("-----------------\r\n"), 0x80);
|
||||||
|
|
||||||
uint8_t rcode = MASS_ERR_UNIT_NOT_READY;
|
uint8_t rcode = MASS_ERR_UNIT_NOT_READY;
|
||||||
if(bAddress) {
|
if (bAddress) {
|
||||||
CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0);
|
CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0);
|
||||||
rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT);
|
rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT);
|
||||||
} else {
|
}
|
||||||
SetCurLUN(lun);
|
else
|
||||||
}
|
SetCurLUN(lun);
|
||||||
return rcode;
|
|
||||||
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -162,27 +155,27 @@ uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) {
|
uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) {
|
||||||
if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
|
if (!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
|
||||||
Notify(PSTR("\r\nRead LUN:\t"), 0x80);
|
Notify(PSTR("\r\nRead LUN:\t"), 0x80);
|
||||||
D_PrintHex<uint8_t > (lun, 0x90);
|
D_PrintHex<uint8_t> (lun, 0x90);
|
||||||
Notify(PSTR("\r\nLBA:\t\t"), 0x90);
|
Notify(PSTR("\r\nLBA:\t\t"), 0x90);
|
||||||
D_PrintHex<uint32_t > (addr, 0x90);
|
D_PrintHex<uint32_t> (addr, 0x90);
|
||||||
Notify(PSTR("\r\nblocks:\t\t"), 0x90);
|
Notify(PSTR("\r\nblocks:\t\t"), 0x90);
|
||||||
D_PrintHex<uint8_t > (blocks, 0x90);
|
D_PrintHex<uint8_t> (blocks, 0x90);
|
||||||
Notify(PSTR("\r\nblock size:\t"), 0x90);
|
Notify(PSTR("\r\nblock size:\t"), 0x90);
|
||||||
D_PrintHex<uint16_t > (bsize, 0x90);
|
D_PrintHex<uint16_t> (bsize, 0x90);
|
||||||
Notify(PSTR("\r\n---------\r\n"), 0x80);
|
Notify(PSTR("\r\n---------\r\n"), 0x80);
|
||||||
CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr);
|
CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr);
|
||||||
|
|
||||||
again:
|
again:
|
||||||
uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN);
|
uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN);
|
||||||
|
|
||||||
if(er == MASS_ERR_STALL) {
|
if (er == MASS_ERR_STALL) {
|
||||||
MediaCTL(lun, 1);
|
MediaCTL(lun, 1);
|
||||||
delay(150);
|
delay(150);
|
||||||
if(!TestUnitReady(lun)) goto again;
|
if (!TestUnitReady(lun)) goto again;
|
||||||
}
|
}
|
||||||
return er;
|
return er;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,28 +189,28 @@ again:
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) {
|
uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) {
|
||||||
if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
|
if (!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
|
||||||
if(!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED;
|
if (!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED;
|
||||||
Notify(PSTR("\r\nWrite LUN:\t"), 0x80);
|
Notify(PSTR("\r\nWrite LUN:\t"), 0x80);
|
||||||
D_PrintHex<uint8_t > (lun, 0x90);
|
D_PrintHex<uint8_t> (lun, 0x90);
|
||||||
Notify(PSTR("\r\nLBA:\t\t"), 0x90);
|
Notify(PSTR("\r\nLBA:\t\t"), 0x90);
|
||||||
D_PrintHex<uint32_t > (addr, 0x90);
|
D_PrintHex<uint32_t> (addr, 0x90);
|
||||||
Notify(PSTR("\r\nblocks:\t\t"), 0x90);
|
Notify(PSTR("\r\nblocks:\t\t"), 0x90);
|
||||||
D_PrintHex<uint8_t > (blocks, 0x90);
|
D_PrintHex<uint8_t> (blocks, 0x90);
|
||||||
Notify(PSTR("\r\nblock size:\t"), 0x90);
|
Notify(PSTR("\r\nblock size:\t"), 0x90);
|
||||||
D_PrintHex<uint16_t > (bsize, 0x90);
|
D_PrintHex<uint16_t> (bsize, 0x90);
|
||||||
Notify(PSTR("\r\n---------\r\n"), 0x80);
|
Notify(PSTR("\r\n---------\r\n"), 0x80);
|
||||||
CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr);
|
CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr);
|
||||||
|
|
||||||
again:
|
again:
|
||||||
uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT);
|
uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT);
|
||||||
|
|
||||||
if(er == MASS_ERR_WRITE_STALL) {
|
if (er == MASS_ERR_WRITE_STALL) {
|
||||||
MediaCTL(lun, 1);
|
MediaCTL(lun, 1);
|
||||||
delay(150);
|
delay(150);
|
||||||
if(!TestUnitReady(lun)) goto again;
|
if (!TestUnitReady(lun)) goto again;
|
||||||
}
|
}
|
||||||
return er;
|
return er;
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of user functions, the remaining code below is driver internals.
|
// End of user functions, the remaining code below is driver internals.
|
||||||
|
@ -236,10 +229,9 @@ qNextPollTime(0),
|
||||||
bPollEnable(false),
|
bPollEnable(false),
|
||||||
//dCBWTag(0),
|
//dCBWTag(0),
|
||||||
bLastUsbError(0) {
|
bLastUsbError(0) {
|
||||||
ClearAllEP();
|
ClearAllEP();
|
||||||
dCBWTag = 0;
|
dCBWTag = 0;
|
||||||
if(pUsb)
|
if (pUsb) pUsb->RegisterDeviceClass(this);
|
||||||
pUsb->RegisterDeviceClass(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -258,71 +250,66 @@ bLastUsbError(0) {
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
|
uint8_t BulkOnly::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
|
|
||||||
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
|
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
|
||||||
|
|
||||||
uint8_t buf[constBufSize];
|
uint8_t buf[constBufSize];
|
||||||
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
|
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
|
||||||
uint8_t rcode;
|
uint8_t rcode;
|
||||||
UsbDevice *p = NULL;
|
UsbDevice *p = NULL;
|
||||||
EpInfo *oldep_ptr = NULL;
|
EpInfo *oldep_ptr = NULL;
|
||||||
USBTRACE("MS ConfigureDevice\r\n");
|
USBTRACE("MS ConfigureDevice\r\n");
|
||||||
ClearAllEP();
|
ClearAllEP();
|
||||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
|
|
||||||
|
if (bAddress) return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
|
|
||||||
if(bAddress)
|
// <TECHNICAL>
|
||||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
// Get pointer to pseudo device with address 0 assigned
|
||||||
|
p = addrPool.GetUsbDevicePtr(0);
|
||||||
|
if (!p) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
// <TECHNICAL>
|
if (!p->epinfo) {
|
||||||
// Get pointer to pseudo device with address 0 assigned
|
USBTRACE("epinfo\r\n");
|
||||||
p = addrPool.GetUsbDevicePtr(0);
|
return USB_ERROR_EPINFO_IS_NULL;
|
||||||
if(!p) {
|
}
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!p->epinfo) {
|
// Save old pointer to EP_RECORD of address 0
|
||||||
USBTRACE("epinfo\r\n");
|
oldep_ptr = p->epinfo;
|
||||||
return USB_ERROR_EPINFO_IS_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save old pointer to EP_RECORD of address 0
|
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||||
oldep_ptr = p->epinfo;
|
p->epinfo = epInfo;
|
||||||
|
|
||||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
p->lowspeed = lowspeed;
|
||||||
p->epinfo = epInfo;
|
// Get device descriptor
|
||||||
|
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
|
||||||
|
|
||||||
p->lowspeed = lowspeed;
|
// Restore p->epinfo
|
||||||
// Get device descriptor
|
p->epinfo = oldep_ptr;
|
||||||
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
|
|
||||||
|
|
||||||
// Restore p->epinfo
|
if (rcode) goto FailGetDevDescr;
|
||||||
p->epinfo = oldep_ptr;
|
|
||||||
|
|
||||||
if(rcode) {
|
// Allocate new address according to device class
|
||||||
goto FailGetDevDescr;
|
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||||
}
|
|
||||||
// Allocate new address according to device class
|
|
||||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
|
||||||
|
|
||||||
if(!bAddress)
|
if (!bAddress) return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
|
||||||
|
|
||||||
// Extract Max Packet Size from the device descriptor
|
// Extract Max Packet Size from the device descriptor
|
||||||
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
|
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
|
||||||
// Steal and abuse from epInfo structure to save on memory.
|
// Steal and abuse from epInfo structure to save on memory.
|
||||||
epInfo[1].epAddr = udd->bNumConfigurations;
|
epInfo[1].epAddr = udd->bNumConfigurations;
|
||||||
// </TECHNICAL>
|
// </TECHNICAL>
|
||||||
return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
|
return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
|
||||||
|
|
||||||
FailGetDevDescr:
|
FailGetDevDescr:
|
||||||
#ifdef DEBUG_USB_HOST
|
|
||||||
NotifyFailGetDevDescr(rcode);
|
|
||||||
#endif
|
|
||||||
rcode = USB_ERROR_FailGetDevDescr;
|
|
||||||
|
|
||||||
Release();
|
#ifdef DEBUG_USB_HOST
|
||||||
return rcode;
|
NotifyFailGetDevDescr(rcode);
|
||||||
};
|
#endif
|
||||||
|
rcode = USB_ERROR_FailGetDevDescr;
|
||||||
|
|
||||||
|
Release();
|
||||||
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param parent (not used)
|
* @param parent (not used)
|
||||||
|
@ -331,211 +318,206 @@ FailGetDevDescr:
|
||||||
* @return 0 for success
|
* @return 0 for success
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
|
uint8_t BulkOnly::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
|
||||||
uint8_t rcode;
|
uint8_t rcode;
|
||||||
uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations
|
uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations
|
||||||
epInfo[1].epAddr = 0;
|
epInfo[1].epAddr = 0;
|
||||||
USBTRACE("MS Init\r\n");
|
USBTRACE("MS Init\r\n");
|
||||||
|
|
||||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress);
|
UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
|
|
||||||
if(!p)
|
if (!p) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
|
||||||
|
|
||||||
// Assign new address to the device
|
// Assign new address to the device
|
||||||
delay(2000);
|
delay(2000);
|
||||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||||
|
|
||||||
if(rcode) {
|
if (rcode) {
|
||||||
p->lowspeed = false;
|
p->lowspeed = false;
|
||||||
addrPool.FreeAddress(bAddress);
|
addrPool.FreeAddress(bAddress);
|
||||||
bAddress = 0;
|
bAddress = 0;
|
||||||
USBTRACE2("setAddr:", rcode);
|
USBTRACE2("setAddr:", rcode);
|
||||||
return rcode;
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBTRACE2("Addr:", bAddress);
|
||||||
|
|
||||||
|
p->lowspeed = false;
|
||||||
|
|
||||||
|
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||||
|
|
||||||
|
if (!p) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||||
|
|
||||||
|
p->lowspeed = lowspeed;
|
||||||
|
|
||||||
|
// Assign epInfo to epinfo pointer
|
||||||
|
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||||
|
|
||||||
|
if (rcode) goto FailSetDevTblEntry;
|
||||||
|
|
||||||
|
USBTRACE2("NC:", num_of_conf);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < num_of_conf; i++) {
|
||||||
|
ConfigDescParser< USB_CLASS_MASS_STORAGE,
|
||||||
|
MASS_SUBCLASS_SCSI,
|
||||||
|
MASS_PROTO_BBB,
|
||||||
|
CP_MASK_COMPARE_CLASS |
|
||||||
|
CP_MASK_COMPARE_SUBCLASS |
|
||||||
|
CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this);
|
||||||
|
|
||||||
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser);
|
||||||
|
|
||||||
|
if (rcode) goto FailGetConfDescr;
|
||||||
|
|
||||||
|
if (bNumEP > 1) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bNumEP < 3) return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
// Assign epInfo to epinfo pointer
|
||||||
|
pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||||
|
|
||||||
|
USBTRACE2("Conf:", bConfNum);
|
||||||
|
|
||||||
|
// Set Configuration Value
|
||||||
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
|
|
||||||
|
if (rcode) goto FailSetConfDescr;
|
||||||
|
|
||||||
|
//Linux does a 1sec delay after this.
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
rcode = GetMaxLUN(&bMaxLUN);
|
||||||
|
if (rcode) goto FailGetMaxLUN;
|
||||||
|
|
||||||
|
if (bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
|
||||||
|
ErrorMessage<uint8_t> (PSTR("MaxLUN"), bMaxLUN);
|
||||||
|
|
||||||
|
delay(1000); // Delay a bit for slow firmware.
|
||||||
|
|
||||||
|
for (uint8_t lun = 0; lun <= bMaxLUN; lun++) {
|
||||||
|
InquiryResponse response;
|
||||||
|
rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response);
|
||||||
|
if (rcode) {
|
||||||
|
ErrorMessage<uint8_t> (PSTR("Inquiry"), rcode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#if 0
|
||||||
|
printf("LUN %i `", lun);
|
||||||
|
uint8_t *buf = response.VendorID;
|
||||||
|
for (int i = 0; i < 28; i++) printf("%c", buf[i]);
|
||||||
|
printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier);
|
||||||
|
printf("Device type %2.2X ", response.DeviceType);
|
||||||
|
printf("RMB %1.1X ", response.Removable);
|
||||||
|
printf("SSCS %1.1X ", response.SCCS);
|
||||||
|
uint8_t sv = response.Version;
|
||||||
|
printf("SCSI version %2.2X\r\nDevice conforms to ", sv);
|
||||||
|
switch (sv) {
|
||||||
|
case 0:
|
||||||
|
printf("No specific");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
printf("ANSI X3.131-1986 (ANSI 1)");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf("ANSI X3.131-1994 (ANSI 2)");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
printf("ANSI INCITS 301-1997 (SPC)");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
printf("ANSI INCITS 351-2001 (SPC-2)");
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
printf("ANSI INCITS 408-2005 (SPC-4)");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
printf("T10/1731-D (SPC-4)");
|
||||||
|
break;
|
||||||
|
default: printf("unknown");
|
||||||
}
|
}
|
||||||
|
printf(" standards.\r\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
USBTRACE2("Addr:", bAddress);
|
uint8_t tries = 0xf0;
|
||||||
|
while ((rcode = TestUnitReady(lun))) {
|
||||||
p->lowspeed = false;
|
if (rcode == 0x08) break; // break on no media, this is OK to do.
|
||||||
|
// try to lock media and spin up
|
||||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
if (tries < 14) {
|
||||||
|
LockMedia(lun, 1);
|
||||||
if(!p)
|
MediaCTL(lun, 1); // I actually have a USB stick that needs this!
|
||||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
} else
|
||||||
|
delay(2 * (tries + 1));
|
||||||
p->lowspeed = lowspeed;
|
tries++;
|
||||||
|
if (!tries) break;
|
||||||
// Assign epInfo to epinfo pointer
|
}
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
if (!rcode) {
|
||||||
|
|
||||||
if(rcode)
|
|
||||||
goto FailSetDevTblEntry;
|
|
||||||
|
|
||||||
USBTRACE2("NC:", num_of_conf);
|
|
||||||
|
|
||||||
for(uint8_t i = 0; i < num_of_conf; i++) {
|
|
||||||
ConfigDescParser< USB_CLASS_MASS_STORAGE,
|
|
||||||
MASS_SUBCLASS_SCSI,
|
|
||||||
MASS_PROTO_BBB,
|
|
||||||
CP_MASK_COMPARE_CLASS |
|
|
||||||
CP_MASK_COMPARE_SUBCLASS |
|
|
||||||
CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this);
|
|
||||||
|
|
||||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser);
|
|
||||||
|
|
||||||
if(rcode)
|
|
||||||
goto FailGetConfDescr;
|
|
||||||
|
|
||||||
if(bNumEP > 1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bNumEP < 3)
|
|
||||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
|
||||||
|
|
||||||
// Assign epInfo to epinfo pointer
|
|
||||||
pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
|
||||||
|
|
||||||
USBTRACE2("Conf:", bConfNum);
|
|
||||||
|
|
||||||
// Set Configuration Value
|
|
||||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
|
||||||
|
|
||||||
if(rcode)
|
|
||||||
goto FailSetConfDescr;
|
|
||||||
|
|
||||||
//Linux does a 1sec delay after this.
|
|
||||||
delay(1000);
|
delay(1000);
|
||||||
|
LUNOk[lun] = CheckLUN(lun);
|
||||||
|
if (!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rcode = GetMaxLUN(&bMaxLUN);
|
CheckMedia();
|
||||||
if(rcode)
|
|
||||||
goto FailGetMaxLUN;
|
|
||||||
|
|
||||||
if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
|
rcode = OnInit();
|
||||||
ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN);
|
|
||||||
|
|
||||||
delay(1000); // Delay a bit for slow firmware.
|
if (rcode) goto FailOnInit;
|
||||||
|
|
||||||
for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
|
#ifdef DEBUG_USB_HOST
|
||||||
InquiryResponse response;
|
USBTRACE("MS configured\r\n\r\n");
|
||||||
rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response);
|
#endif
|
||||||
if(rcode) {
|
|
||||||
ErrorMessage<uint8_t > (PSTR("Inquiry"), rcode);
|
|
||||||
} else {
|
|
||||||
#if 0
|
|
||||||
printf("LUN %i `", lun);
|
|
||||||
uint8_t *buf = response.VendorID;
|
|
||||||
for(int i = 0; i < 28; i++) printf("%c", buf[i]);
|
|
||||||
printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier);
|
|
||||||
printf("Device type %2.2X ", response.DeviceType);
|
|
||||||
printf("RMB %1.1X ", response.Removable);
|
|
||||||
printf("SSCS %1.1X ", response.SCCS);
|
|
||||||
uint8_t sv = response.Version;
|
|
||||||
printf("SCSI version %2.2X\r\nDevice conforms to ", sv);
|
|
||||||
switch(sv) {
|
|
||||||
case 0:
|
|
||||||
printf("No specific");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
printf("ANSI X3.131-1986 (ANSI 1)");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
printf("ANSI X3.131-1994 (ANSI 2)");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
printf("ANSI INCITS 301-1997 (SPC)");
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
printf("ANSI INCITS 351-2001 (SPC-2)");
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
printf("ANSI INCITS 408-2005 (SPC-4)");
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
printf("T10/1731-D (SPC-4)");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("unknown");
|
|
||||||
}
|
|
||||||
printf(" standards.\r\n");
|
|
||||||
#endif
|
|
||||||
uint8_t tries = 0xf0;
|
|
||||||
while((rcode = TestUnitReady(lun))) {
|
|
||||||
if(rcode == 0x08) break; // break on no media, this is OK to do.
|
|
||||||
// try to lock media and spin up
|
|
||||||
if(tries < 14) {
|
|
||||||
LockMedia(lun, 1);
|
|
||||||
MediaCTL(lun, 1); // I actually have a USB stick that needs this!
|
|
||||||
} else delay(2 * (tries + 1));
|
|
||||||
tries++;
|
|
||||||
if(!tries) break;
|
|
||||||
}
|
|
||||||
if(!rcode) {
|
|
||||||
delay(1000);
|
|
||||||
LUNOk[lun] = CheckLUN(lun);
|
|
||||||
if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bPollEnable = true;
|
||||||
|
|
||||||
CheckMedia();
|
//USBTRACE("Poll enabled\r\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
rcode = OnInit();
|
FailSetConfDescr:
|
||||||
|
|
||||||
if(rcode)
|
#ifdef DEBUG_USB_HOST
|
||||||
goto FailOnInit;
|
NotifyFailSetConfDescr();
|
||||||
|
goto Fail;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_USB_HOST
|
FailOnInit:
|
||||||
USBTRACE("MS configured\r\n\r\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bPollEnable = true;
|
#ifdef DEBUG_USB_HOST
|
||||||
|
USBTRACE("OnInit:");
|
||||||
|
goto Fail;
|
||||||
|
#endif
|
||||||
|
|
||||||
//USBTRACE("Poll enabled\r\n");
|
FailGetMaxLUN:
|
||||||
return 0;
|
|
||||||
|
|
||||||
FailSetConfDescr:
|
#ifdef DEBUG_USB_HOST
|
||||||
#ifdef DEBUG_USB_HOST
|
USBTRACE("GetMaxLUN:");
|
||||||
NotifyFailSetConfDescr();
|
goto Fail;
|
||||||
goto Fail;
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
FailOnInit:
|
//#ifdef DEBUG_USB_HOST
|
||||||
#ifdef DEBUG_USB_HOST
|
// FailInvalidSectorSize:
|
||||||
USBTRACE("OnInit:");
|
// USBTRACE("Sector Size is NOT VALID: ");
|
||||||
goto Fail;
|
// goto Fail;
|
||||||
#endif
|
//#endif
|
||||||
|
|
||||||
FailGetMaxLUN:
|
FailSetDevTblEntry:
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
USBTRACE("GetMaxLUN:");
|
NotifyFailSetDevTblEntry();
|
||||||
goto Fail;
|
goto Fail;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#ifdef DEBUG_USB_HOST
|
FailGetConfDescr:
|
||||||
//FailInvalidSectorSize:
|
#ifdef DEBUG_USB_HOST
|
||||||
// USBTRACE("Sector Size is NOT VALID: ");
|
NotifyFailGetConfDescr();
|
||||||
// goto Fail;
|
#endif
|
||||||
//#endif
|
|
||||||
|
|
||||||
FailSetDevTblEntry:
|
#ifdef DEBUG_USB_HOST
|
||||||
#ifdef DEBUG_USB_HOST
|
Fail:
|
||||||
NotifyFailSetDevTblEntry();
|
NotifyFail(rcode);
|
||||||
goto Fail;
|
#endif
|
||||||
#endif
|
Release();
|
||||||
|
return rcode;
|
||||||
FailGetConfDescr:
|
|
||||||
#ifdef DEBUG_USB_HOST
|
|
||||||
NotifyFailGetConfDescr();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG_USB_HOST
|
|
||||||
Fail:
|
|
||||||
NotifyFail(rcode);
|
|
||||||
#endif
|
|
||||||
Release();
|
|
||||||
return rcode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -548,46 +530,45 @@ Fail:
|
||||||
* @param pep
|
* @param pep
|
||||||
*/
|
*/
|
||||||
void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR * pep) {
|
void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR * pep) {
|
||||||
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
|
ErrorMessage<uint8_t> (PSTR("Conf.Val"), conf);
|
||||||
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
|
ErrorMessage<uint8_t> (PSTR("Iface Num"), iface);
|
||||||
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
|
ErrorMessage<uint8_t> (PSTR("Alt.Set"), alt);
|
||||||
|
|
||||||
bConfNum = conf;
|
bConfNum = conf;
|
||||||
|
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) {
|
if ((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) {
|
||||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||||
// Fill in the endpoint info structure
|
// Fill in the endpoint info structure
|
||||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||||
epInfo[index].bmSndToggle = 0;
|
epInfo[index].bmSndToggle = 0;
|
||||||
epInfo[index].bmRcvToggle = 0;
|
epInfo[index].bmRcvToggle = 0;
|
||||||
|
|
||||||
bNumEP++;
|
bNumEP++;
|
||||||
|
|
||||||
PrintEndpointDescriptor(pep);
|
PrintEndpointDescriptor(pep);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if ((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||||
|
index = epInterruptInIndex;
|
||||||
|
else if ((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK)
|
||||||
|
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
}
|
// Fill in the endpoint info structure
|
||||||
#else
|
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||||
if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80)
|
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||||
index = epInterruptInIndex;
|
epInfo[index].bmSndToggle = 0;
|
||||||
else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK)
|
epInfo[index].bmRcvToggle = 0;
|
||||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Fill in the endpoint info structure
|
bNumEP++;
|
||||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
|
||||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
|
||||||
epInfo[index].bmSndToggle = 0;
|
|
||||||
epInfo[index].bmRcvToggle = 0;
|
|
||||||
|
|
||||||
bNumEP++;
|
PrintEndpointDescriptor(pep);
|
||||||
|
#endif
|
||||||
PrintEndpointDescriptor(pep);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -596,9 +577,9 @@ void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::Release() {
|
uint8_t BulkOnly::Release() {
|
||||||
ClearAllEP();
|
ClearAllEP();
|
||||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -608,38 +589,37 @@ uint8_t BulkOnly::Release() {
|
||||||
* @return true if LUN is ready for use.
|
* @return true if LUN is ready for use.
|
||||||
*/
|
*/
|
||||||
bool BulkOnly::CheckLUN(uint8_t lun) {
|
bool BulkOnly::CheckLUN(uint8_t lun) {
|
||||||
uint8_t rcode;
|
uint8_t rcode;
|
||||||
Capacity capacity;
|
Capacity capacity;
|
||||||
for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
|
for (uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
|
||||||
|
|
||||||
rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
|
rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
|
||||||
if(rcode) {
|
if (rcode) {
|
||||||
//printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
|
//printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun);
|
ErrorMessage<uint8_t> (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun);
|
||||||
for(uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++)
|
for (uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++)
|
||||||
D_PrintHex<uint8_t > (capacity.data[i], 0x80);
|
D_PrintHex<uint8_t> (capacity.data[i], 0x80);
|
||||||
Notify(PSTR("\r\n\r\n"), 0x80);
|
Notify(PSTR("\r\n\r\n"), 0x80);
|
||||||
// Only 512/1024/2048/4096 are valid values!
|
|
||||||
uint32_t c = BMAKE32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]);
|
|
||||||
if(c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Store capacity information.
|
|
||||||
CurrentSectorSize[lun] = (uint16_t)(c); // & 0xFFFF);
|
|
||||||
|
|
||||||
CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1;
|
// Only 512/1024/2048/4096 are valid values!
|
||||||
if(CurrentCapacity[lun] == /*0xffffffffLU */ 0x01LU || CurrentCapacity[lun] == 0x00LU) {
|
uint32_t c = BMAKE32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]);
|
||||||
// Buggy firmware will report 0xffffffff or 0 for no media
|
if (c != 0x0200UL && c != 0x0400UL && c != 0x0800UL && c != 0x1000UL) return false;
|
||||||
if(CurrentCapacity[lun])
|
|
||||||
ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun);
|
// Store capacity information.
|
||||||
return false;
|
CurrentSectorSize[lun] = (uint16_t)(c); // & 0xFFFF);
|
||||||
}
|
|
||||||
delay(20);
|
CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1;
|
||||||
Page3F(lun);
|
if (CurrentCapacity[lun] == /*0xFFFFFFFFUL */ 0x01UL || CurrentCapacity[lun] == 0x00UL) {
|
||||||
if(!TestUnitReady(lun)) return true;
|
// Buggy firmware will report 0xFFFFFFFF or 0 for no media
|
||||||
return false;
|
if (CurrentCapacity[lun])
|
||||||
|
ErrorMessage<uint8_t> (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
delay(20);
|
||||||
|
Page3F(lun);
|
||||||
|
return !TestUnitReady(lun);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -648,24 +628,20 @@ bool BulkOnly::CheckLUN(uint8_t lun) {
|
||||||
* Scan for media change on all LUNs
|
* Scan for media change on all LUNs
|
||||||
*/
|
*/
|
||||||
void BulkOnly::CheckMedia() {
|
void BulkOnly::CheckMedia() {
|
||||||
for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
|
for (uint8_t lun = 0; lun <= bMaxLUN; lun++) {
|
||||||
if(TestUnitReady(lun)) {
|
if (TestUnitReady(lun)) {
|
||||||
LUNOk[lun] = false;
|
LUNOk[lun] = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(!LUNOk[lun])
|
if (!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
|
||||||
LUNOk[lun] = CheckLUN(lun);
|
}
|
||||||
}
|
#if 0
|
||||||
#if 0
|
printf("}}}}}}}}}}}}}}}}STATUS ");
|
||||||
printf("}}}}}}}}}}}}}}}}STATUS ");
|
for (uint8_t lun = 0; lun <= bMaxLUN; lun++)
|
||||||
for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
|
printf(LUNOk[lun] ? "#" : ".");
|
||||||
if(LUNOk[lun])
|
printf("\r\n");
|
||||||
printf("#");
|
#endif
|
||||||
else printf(".");
|
qNextPollTime = (uint32_t)millis() + 2000;
|
||||||
}
|
|
||||||
printf("\r\n");
|
|
||||||
#endif
|
|
||||||
qNextPollTime = (uint32_t)millis() + 2000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -674,17 +650,11 @@ void BulkOnly::CheckMedia() {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::Poll() {
|
uint8_t BulkOnly::Poll() {
|
||||||
//uint8_t rcode = 0;
|
//uint8_t rcode = 0;
|
||||||
|
if (!bPollEnable) return 0;
|
||||||
if(!bPollEnable)
|
if ((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) CheckMedia();
|
||||||
return 0;
|
//rcode = 0;
|
||||||
|
return 0;
|
||||||
if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) {
|
|
||||||
CheckMedia();
|
|
||||||
}
|
|
||||||
//rcode = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -700,7 +670,7 @@ uint8_t BulkOnly::Poll() {
|
||||||
uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) {
|
uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) {
|
||||||
uint8_t ret = pUsb->ctrlReq(bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL);
|
uint8_t ret = pUsb->ctrlReq(bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL);
|
||||||
|
|
||||||
if(ret == hrSTALL)
|
if (ret == hrSTALL)
|
||||||
*plun = 0;
|
*plun = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -718,7 +688,7 @@ uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) {
|
||||||
Notify(PSTR("\r\nInquiry\r\n"), 0x80);
|
Notify(PSTR("\r\nInquiry\r\n"), 0x80);
|
||||||
Notify(PSTR("---------\r\n"), 0x80);
|
Notify(PSTR("---------\r\n"), 0x80);
|
||||||
|
|
||||||
CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0);
|
CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0UL, (uint8_t)bsize, 0);
|
||||||
uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN);
|
uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -732,7 +702,7 @@ uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) {
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::TestUnitReady(uint8_t lun) {
|
uint8_t BulkOnly::TestUnitReady(uint8_t lun) {
|
||||||
//SetCurLUN(lun);
|
//SetCurLUN(lun);
|
||||||
if(!bAddress)
|
if (!bAddress)
|
||||||
return MASS_ERR_UNIT_NOT_READY;
|
return MASS_ERR_UNIT_NOT_READY;
|
||||||
|
|
||||||
Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80);
|
Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80);
|
||||||
|
@ -788,7 +758,7 @@ uint8_t BulkOnly::ReadCapacity10(uint8_t lun, uint8_t *buf) {
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::Page3F(uint8_t lun) {
|
uint8_t BulkOnly::Page3F(uint8_t lun) {
|
||||||
uint8_t buf[192];
|
uint8_t buf[192];
|
||||||
for(int i = 0; i < 192; i++) {
|
for (int i = 0; i < 192; i++) {
|
||||||
buf[i] = 0x00;
|
buf[i] = 0x00;
|
||||||
}
|
}
|
||||||
WriteOk[lun] = true;
|
WriteOk[lun] = true;
|
||||||
|
@ -796,11 +766,11 @@ uint8_t BulkOnly::Page3F(uint8_t lun) {
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf);
|
uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf);
|
||||||
if(!rc) {
|
if (!rc) {
|
||||||
WriteOk[lun] = ((buf[2] & 0x80) == 0);
|
WriteOk[lun] = ((buf[2] & 0x80) == 0);
|
||||||
Notify(PSTR("Mode Sense: "), 0x80);
|
Notify(PSTR("Mode Sense: "), 0x80);
|
||||||
for(int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
D_PrintHex<uint8_t > (buf[i], 0x80);
|
D_PrintHex<uint8_t> (buf[i], 0x80);
|
||||||
Notify(PSTR(" "), 0x80);
|
Notify(PSTR(" "), 0x80);
|
||||||
}
|
}
|
||||||
Notify(PSTR("\r\n"), 0x80);
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
|
@ -820,7 +790,7 @@ uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) {
|
||||||
Notify(PSTR("\r\nRequestSense\r\n"), 0x80);
|
Notify(PSTR("\r\nRequestSense\r\n"), 0x80);
|
||||||
Notify(PSTR("----------------\r\n"), 0x80);
|
Notify(PSTR("----------------\r\n"), 0x80);
|
||||||
|
|
||||||
CDB6_t cdb = CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0);
|
CDB6_t cdb = CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0UL, (uint8_t)size, 0);
|
||||||
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)MASS_CMD_DIR_IN);
|
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)MASS_CMD_DIR_IN);
|
||||||
//SetCurLUN(lun);
|
//SetCurLUN(lun);
|
||||||
return Transaction(&cbw, size, buf);
|
return Transaction(&cbw, size, buf);
|
||||||
|
@ -838,17 +808,17 @@ uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::ClearEpHalt(uint8_t index) {
|
uint8_t BulkOnly::ClearEpHalt(uint8_t index) {
|
||||||
if(index == 0)
|
if (index == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint8_t ret = 0;
|
uint8_t ret = 0;
|
||||||
|
|
||||||
while((ret = (pUsb->ctrlReq(bAddress, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT, USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr), 0, 0, NULL, NULL)) == 0x01))
|
while ((ret = (pUsb->ctrlReq(bAddress, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT, USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr), 0, 0, NULL, NULL)) == 0x01))
|
||||||
delay(6);
|
delay(6);
|
||||||
|
|
||||||
if(ret) {
|
if (ret) {
|
||||||
ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret);
|
ErrorMessage<uint8_t> (PSTR("ClearEpHalt"), ret);
|
||||||
ErrorMessage<uint8_t > (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr));
|
ErrorMessage<uint8_t> (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
epInfo[index].bmSndToggle = 0;
|
epInfo[index].bmSndToggle = 0;
|
||||||
|
@ -861,7 +831,7 @@ uint8_t BulkOnly::ClearEpHalt(uint8_t index) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void BulkOnly::Reset() {
|
void BulkOnly::Reset() {
|
||||||
while(pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL) == 0x01) delay(6);
|
while (pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL) == 0x01) delay(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -889,29 +859,29 @@ uint8_t BulkOnly::ResetRecovery() {
|
||||||
* Clear all EP data and clear all LUN status
|
* Clear all EP data and clear all LUN status
|
||||||
*/
|
*/
|
||||||
void BulkOnly::ClearAllEP() {
|
void BulkOnly::ClearAllEP() {
|
||||||
for(uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) {
|
for (uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) {
|
||||||
epInfo[i].epAddr = 0;
|
epInfo[i].epAddr = 0;
|
||||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||||
epInfo[i].bmSndToggle = 0;
|
epInfo[i].bmSndToggle = 0;
|
||||||
epInfo[i].bmRcvToggle = 0;
|
epInfo[i].bmRcvToggle = 0;
|
||||||
epInfo[i].bmNakPower = USB_NAK_DEFAULT;
|
epInfo[i].bmNakPower = USB_NAK_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) {
|
for (uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) {
|
||||||
LUNOk[i] = false;
|
LUNOk[i] = false;
|
||||||
WriteOk[i] = false;
|
WriteOk[i] = false;
|
||||||
CurrentCapacity[i] = 0lu;
|
CurrentCapacity[i] = 0UL;
|
||||||
CurrentSectorSize[i] = 0;
|
CurrentSectorSize[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bIface = 0;
|
bIface = 0;
|
||||||
bNumEP = 1;
|
bNumEP = 1;
|
||||||
bAddress = 0;
|
bAddress = 0;
|
||||||
qNextPollTime = 0;
|
qNextPollTime = 0;
|
||||||
bPollEnable = false;
|
bPollEnable = false;
|
||||||
bLastUsbError = 0;
|
bLastUsbError = 0;
|
||||||
bMaxLUN = 0;
|
bMaxLUN = 0;
|
||||||
bTheLUN = 0;
|
bTheLUN = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -922,15 +892,15 @@ void BulkOnly::ClearAllEP() {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) {
|
bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) {
|
||||||
if(pcsw->dCSWSignature != MASS_CSW_SIGNATURE) {
|
if (pcsw->dCSWSignature != MASS_CSW_SIGNATURE) {
|
||||||
Notify(PSTR("CSW:Sig error\r\n"), 0x80);
|
Notify(PSTR("CSW:Sig error\r\n"), 0x80);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(pcsw->dCSWTag != pcbw->dCBWTag) {
|
if (pcsw->dCSWTag != pcbw->dCBWTag) {
|
||||||
Notify(PSTR("CSW:Wrong tag\r\n"), 0x80);
|
Notify(PSTR("CSW:Wrong tag\r\n"), 0x80);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -941,65 +911,56 @@ bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *p
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) {
|
uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) {
|
||||||
uint8_t count = 3;
|
uint8_t count = 3;
|
||||||
|
|
||||||
bLastUsbError = error;
|
bLastUsbError = error;
|
||||||
//if (error)
|
//if (error)
|
||||||
//ClearEpHalt(index);
|
//ClearEpHalt(index);
|
||||||
while(error && count) {
|
while (error && count) {
|
||||||
if(error != hrSUCCESS) {
|
if (error != hrSUCCESS) {
|
||||||
ErrorMessage<uint8_t > (PSTR("USB Error"), error);
|
ErrorMessage<uint8_t> (PSTR("USB Error"), error);
|
||||||
ErrorMessage<uint8_t > (PSTR("Index"), index);
|
ErrorMessage<uint8_t> (PSTR("Index"), index);
|
||||||
}
|
}
|
||||||
switch(error) {
|
switch (error) {
|
||||||
// case hrWRONGPID:
|
// case hrWRONGPID:
|
||||||
case hrSUCCESS:
|
case hrSUCCESS: return MASS_ERR_SUCCESS;
|
||||||
return MASS_ERR_SUCCESS;
|
case hrBUSY: return MASS_ERR_UNIT_BUSY; // SIE is busy, just hang out and try again.
|
||||||
case hrBUSY:
|
case hrTIMEOUT:
|
||||||
// SIE is busy, just hang out and try again.
|
case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED;
|
||||||
return MASS_ERR_UNIT_BUSY;
|
case hrSTALL:
|
||||||
case hrTIMEOUT:
|
if (index) {
|
||||||
case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED;
|
ClearEpHalt(index);
|
||||||
case hrSTALL:
|
return (index == epDataInIndex) ? MASS_ERR_STALL : MASS_ERR_WRITE_STALL;
|
||||||
if(index == 0)
|
}
|
||||||
return MASS_ERR_STALL;
|
return MASS_ERR_STALL;
|
||||||
ClearEpHalt(index);
|
|
||||||
if(index != epDataInIndex)
|
|
||||||
return MASS_ERR_WRITE_STALL;
|
|
||||||
return MASS_ERR_STALL;
|
|
||||||
|
|
||||||
case hrNAK:
|
case hrNAK:
|
||||||
if(index == 0)
|
return index ? MASS_ERR_UNIT_BUSY : MASS_ERR_UNIT_BUSY;
|
||||||
return MASS_ERR_UNIT_BUSY;
|
|
||||||
return MASS_ERR_UNIT_BUSY;
|
|
||||||
|
|
||||||
case hrTOGERR:
|
case hrTOGERR:
|
||||||
// Handle a very super rare corner case, where toggles become de-synched.
|
// Handle a super rare corner case, where toggles become de-synced.
|
||||||
// I have only ran into one device that has this firmware bug, and this is
|
// I've only run into one device that has this firmware bug, and this is
|
||||||
// the only clean way to get back into sync with the buggy device firmware.
|
// the only clean way to get back into sync with the buggy device firmware.
|
||||||
// --AJK
|
// --AJK
|
||||||
if(bAddress && bConfNum) {
|
if (bAddress && bConfNum) {
|
||||||
error = pUsb->setConf(bAddress, 0, bConfNum);
|
error = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
|
if (error) break;
|
||||||
|
}
|
||||||
|
return MASS_ERR_SUCCESS;
|
||||||
|
default:
|
||||||
|
ErrorMessage<uint8_t> (PSTR("\r\nUSB"), error);
|
||||||
|
return MASS_ERR_GENERAL_USB_ERROR;
|
||||||
|
}
|
||||||
|
count--;
|
||||||
|
} // while
|
||||||
|
|
||||||
if(error)
|
return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS);
|
||||||
break;
|
|
||||||
}
|
|
||||||
return MASS_ERR_SUCCESS;
|
|
||||||
default:
|
|
||||||
ErrorMessage<uint8_t > (PSTR("\r\nUSB"), error);
|
|
||||||
return MASS_ERR_GENERAL_USB_ERROR;
|
|
||||||
}
|
|
||||||
count--;
|
|
||||||
} // while
|
|
||||||
|
|
||||||
return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MS_WANT_PARSER
|
#if MS_WANT_PARSER
|
||||||
|
uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) {
|
||||||
uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) {
|
return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0);
|
||||||
return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0);
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1012,101 +973,100 @@ uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf
|
uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf
|
||||||
#if MS_WANT_PARSER
|
#if MS_WANT_PARSER
|
||||||
, uint8_t flags
|
, uint8_t flags
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
|
#if MS_WANT_PARSER
|
||||||
|
uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength;
|
||||||
|
printf("Transfersize %i\r\n", bytes);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
#if MS_WANT_PARSER
|
bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK;
|
||||||
uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength;
|
#else
|
||||||
printf("Transfersize %i\r\n", bytes);
|
uint16_t bytes = buf_size;
|
||||||
delay(1000);
|
#endif
|
||||||
|
|
||||||
bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK;
|
bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN;
|
||||||
#else
|
uint8_t ret = 0;
|
||||||
uint16_t bytes = buf_size;
|
uint8_t usberr;
|
||||||
#endif
|
CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles.
|
||||||
bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN;
|
SetCurLUN(pcbw->bmCBWLUN);
|
||||||
uint8_t ret = 0;
|
ErrorMessage<uint32_t> (PSTR("CBW.dCBWTag"), pcbw->dCBWTag);
|
||||||
uint8_t usberr;
|
|
||||||
CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles.
|
|
||||||
SetCurLUN(pcbw->bmCBWLUN);
|
|
||||||
ErrorMessage<uint32_t > (PSTR("CBW.dCBWTag"), pcbw->dCBWTag);
|
|
||||||
|
|
||||||
while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) delay(1);
|
while ((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) delay(1);
|
||||||
|
|
||||||
|
ret = HandleUsbError(usberr, epDataOutIndex);
|
||||||
|
//ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex);
|
||||||
|
if (ret)
|
||||||
|
ErrorMessage<uint8_t> (PSTR("============================ CBW"), ret);
|
||||||
|
else {
|
||||||
|
if (bytes) {
|
||||||
|
if (!write) {
|
||||||
|
#if MS_WANT_PARSER
|
||||||
|
if (callback) {
|
||||||
|
uint8_t rbuf[bytes];
|
||||||
|
while ((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) delay(1);
|
||||||
|
if (usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
while ((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) delay(1);
|
||||||
|
}
|
||||||
|
ret = HandleUsbError(usberr, epDataInIndex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while ((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) delay(1);
|
||||||
ret = HandleUsbError(usberr, epDataOutIndex);
|
ret = HandleUsbError(usberr, epDataOutIndex);
|
||||||
//ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex);
|
}
|
||||||
if(ret) {
|
if (ret) ErrorMessage<uint8_t> (PSTR("============================ DAT"), ret);
|
||||||
ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret);
|
}
|
||||||
} else {
|
}
|
||||||
if(bytes) {
|
|
||||||
if(!write) {
|
|
||||||
#if MS_WANT_PARSER
|
|
||||||
if(callback) {
|
|
||||||
uint8_t rbuf[bytes];
|
|
||||||
while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) delay(1);
|
|
||||||
if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0);
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) delay(1);
|
|
||||||
#if MS_WANT_PARSER
|
|
||||||
|
|
||||||
}
|
bytes = sizeof (CommandStatusWrapper);
|
||||||
#endif
|
int tries = 2;
|
||||||
ret = HandleUsbError(usberr, epDataInIndex);
|
while (tries--) {
|
||||||
} else {
|
while ((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) delay(1);
|
||||||
while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) delay(1);
|
if (!usberr) break;
|
||||||
ret = HandleUsbError(usberr, epDataOutIndex);
|
ClearEpHalt(epDataInIndex);
|
||||||
}
|
if (tries) ResetRecovery();
|
||||||
if(ret) {
|
}
|
||||||
ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
if (!ret) {
|
||||||
bytes = sizeof (CommandStatusWrapper);
|
Notify(PSTR("CBW:\t\tOK\r\n"), 0x80);
|
||||||
int tries = 2;
|
Notify(PSTR("Data Stage:\tOK\r\n"), 0x80);
|
||||||
while(tries--) {
|
}
|
||||||
while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) delay(1);
|
else {
|
||||||
if(!usberr) break;
|
// Throw away csw, IT IS NOT OF ANY USE.
|
||||||
ClearEpHalt(epDataInIndex);
|
ResetRecovery();
|
||||||
if(tries) ResetRecovery();
|
return ret;
|
||||||
}
|
}
|
||||||
if(!ret) {
|
|
||||||
Notify(PSTR("CBW:\t\tOK\r\n"), 0x80);
|
ret = HandleUsbError(usberr, epDataInIndex);
|
||||||
Notify(PSTR("Data Stage:\tOK\r\n"), 0x80);
|
if (ret) ErrorMessage<uint8_t> (PSTR("============================ CSW"), ret);
|
||||||
} else {
|
|
||||||
// Throw away csw, IT IS NOT OF ANY USE.
|
if (usberr == hrSUCCESS) {
|
||||||
ResetRecovery();
|
if (IsValidCSW(&csw, pcbw)) {
|
||||||
return ret;
|
//ErrorMessage<uint32_t> (PSTR("CSW.dCBWTag"), csw.dCSWTag);
|
||||||
}
|
//ErrorMessage<uint8_t> (PSTR("bCSWStatus"), csw.bCSWStatus);
|
||||||
ret = HandleUsbError(usberr, epDataInIndex);
|
//ErrorMessage<uint32_t> (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
|
||||||
if(ret) {
|
Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
|
||||||
ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret);
|
return csw.bCSWStatus;
|
||||||
}
|
}
|
||||||
if(usberr == hrSUCCESS) {
|
else {
|
||||||
if(IsValidCSW(&csw, pcbw)) {
|
// NOTE! Sometimes this is caused by the reported residue being wrong.
|
||||||
//ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag);
|
// Get a different device. It isn't compliant, and should have never passed Q&A.
|
||||||
//ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus);
|
// I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter.
|
||||||
//ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
|
// Other devices that exhibit this behavior exist in the wild too.
|
||||||
Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
|
// Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk
|
||||||
return csw.bCSWStatus;
|
Notify(PSTR("Invalid CSW\r\n"), 0x80);
|
||||||
} else {
|
ResetRecovery();
|
||||||
// NOTE! Sometimes this is caused by the reported residue being wrong.
|
//return MASS_ERR_SUCCESS;
|
||||||
// Get a different device. It isn't compliant, and should have never passed Q&A.
|
return MASS_ERR_INVALID_CSW;
|
||||||
// I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter.
|
}
|
||||||
// Other devices that exhibit this behavior exist in the wild too.
|
}
|
||||||
// Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk
|
return ret;
|
||||||
Notify(PSTR("Invalid CSW\r\n"), 0x80);
|
|
||||||
ResetRecovery();
|
|
||||||
//return MASS_ERR_SUCCESS;
|
|
||||||
return MASS_ERR_INVALID_CSW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1116,11 +1076,10 @@ uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::SetCurLUN(uint8_t lun) {
|
uint8_t BulkOnly::SetCurLUN(uint8_t lun) {
|
||||||
if(lun > bMaxLUN)
|
if (lun > bMaxLUN) return MASS_ERR_INVALID_LUN;
|
||||||
return MASS_ERR_INVALID_LUN;
|
bTheLUN = lun;
|
||||||
bTheLUN = lun;
|
return MASS_ERR_SUCCESS;
|
||||||
return MASS_ERR_SUCCESS;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For driver use only.
|
* For driver use only.
|
||||||
|
@ -1129,83 +1088,78 @@ uint8_t BulkOnly::SetCurLUN(uint8_t lun) {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint8_t BulkOnly::HandleSCSIError(uint8_t status) {
|
uint8_t BulkOnly::HandleSCSIError(uint8_t status) {
|
||||||
uint8_t ret = 0;
|
uint8_t ret = 0;
|
||||||
|
|
||||||
switch(status) {
|
switch (status) {
|
||||||
case 0: return MASS_ERR_SUCCESS;
|
case 0: return MASS_ERR_SUCCESS;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
ErrorMessage<uint8_t > (PSTR("Phase Error"), status);
|
ErrorMessage<uint8_t> (PSTR("Phase Error"), status);
|
||||||
ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
|
ErrorMessage<uint8_t> (PSTR("LUN"), bTheLUN);
|
||||||
ResetRecovery();
|
ResetRecovery();
|
||||||
return MASS_ERR_GENERAL_SCSI_ERROR;
|
return MASS_ERR_GENERAL_SCSI_ERROR;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
ErrorMessage<uint8_t > (PSTR("SCSI Error"), status);
|
ErrorMessage<uint8_t> (PSTR("SCSI Error"), status);
|
||||||
ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
|
ErrorMessage<uint8_t> (PSTR("LUN"), bTheLUN);
|
||||||
RequestSenseResponce rsp;
|
RequestSenseResponce rsp;
|
||||||
|
|
||||||
ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp);
|
ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp);
|
||||||
|
|
||||||
if(ret) {
|
if (ret) return MASS_ERR_GENERAL_SCSI_ERROR;
|
||||||
return MASS_ERR_GENERAL_SCSI_ERROR;
|
|
||||||
}
|
|
||||||
ErrorMessage<uint8_t > (PSTR("Response Code"), rsp.bResponseCode);
|
|
||||||
if(rsp.bResponseCode & 0x80) {
|
|
||||||
Notify(PSTR("Information field: "), 0x80);
|
|
||||||
for(int i = 0; i < 4; i++) {
|
|
||||||
D_PrintHex<uint8_t > (rsp.CmdSpecificInformation[i], 0x80);
|
|
||||||
Notify(PSTR(" "), 0x80);
|
|
||||||
}
|
|
||||||
Notify(PSTR("\r\n"), 0x80);
|
|
||||||
}
|
|
||||||
ErrorMessage<uint8_t > (PSTR("Sense Key"), rsp.bmSenseKey);
|
|
||||||
ErrorMessage<uint8_t > (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode);
|
|
||||||
ErrorMessage<uint8_t > (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier);
|
|
||||||
// warning, this is not testing ASQ, only SK and ASC.
|
|
||||||
switch(rsp.bmSenseKey) {
|
|
||||||
case SCSI_S_UNIT_ATTENTION:
|
|
||||||
switch(rsp.bAdditionalSenseCode) {
|
|
||||||
case SCSI_ASC_MEDIA_CHANGED:
|
|
||||||
return MASS_ERR_MEDIA_CHANGED;
|
|
||||||
default:
|
|
||||||
return MASS_ERR_UNIT_NOT_READY;
|
|
||||||
}
|
|
||||||
case SCSI_S_NOT_READY:
|
|
||||||
switch(rsp.bAdditionalSenseCode) {
|
|
||||||
case SCSI_ASC_MEDIUM_NOT_PRESENT:
|
|
||||||
return MASS_ERR_NO_MEDIA;
|
|
||||||
default:
|
|
||||||
return MASS_ERR_UNIT_NOT_READY;
|
|
||||||
}
|
|
||||||
case SCSI_S_ILLEGAL_REQUEST:
|
|
||||||
switch(rsp.bAdditionalSenseCode) {
|
|
||||||
case SCSI_ASC_LBA_OUT_OF_RANGE:
|
|
||||||
return MASS_ERR_BAD_LBA;
|
|
||||||
default:
|
|
||||||
return MASS_ERR_CMD_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return MASS_ERR_GENERAL_SCSI_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later.
|
ErrorMessage<uint8_t> (PSTR("Response Code"), rsp.bResponseCode);
|
||||||
// case 0x05/0x14: we stalled out
|
if (rsp.bResponseCode & 0x80) {
|
||||||
// case 0x15/0x16: we naked out.
|
Notify(PSTR("Information field: "), 0x80);
|
||||||
default:
|
for (int i = 0; i < 4; i++) {
|
||||||
ErrorMessage<uint8_t > (PSTR("Gen SCSI Err"), status);
|
D_PrintHex<uint8_t> (rsp.CmdSpecificInformation[i], 0x80);
|
||||||
ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
|
Notify(PSTR(" "), 0x80);
|
||||||
return status;
|
}
|
||||||
} // switch
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
|
}
|
||||||
|
ErrorMessage<uint8_t> (PSTR("Sense Key"), rsp.bmSenseKey);
|
||||||
|
ErrorMessage<uint8_t> (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode);
|
||||||
|
ErrorMessage<uint8_t> (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier);
|
||||||
|
// warning, this is not testing ASQ, only SK and ASC.
|
||||||
|
switch (rsp.bmSenseKey) {
|
||||||
|
case SCSI_S_UNIT_ATTENTION:
|
||||||
|
switch (rsp.bAdditionalSenseCode) {
|
||||||
|
case SCSI_ASC_MEDIA_CHANGED:
|
||||||
|
return MASS_ERR_MEDIA_CHANGED;
|
||||||
|
default:
|
||||||
|
return MASS_ERR_UNIT_NOT_READY;
|
||||||
|
}
|
||||||
|
case SCSI_S_NOT_READY:
|
||||||
|
switch (rsp.bAdditionalSenseCode) {
|
||||||
|
case SCSI_ASC_MEDIUM_NOT_PRESENT:
|
||||||
|
return MASS_ERR_NO_MEDIA;
|
||||||
|
default:
|
||||||
|
return MASS_ERR_UNIT_NOT_READY;
|
||||||
|
}
|
||||||
|
case SCSI_S_ILLEGAL_REQUEST:
|
||||||
|
switch (rsp.bAdditionalSenseCode) {
|
||||||
|
case SCSI_ASC_LBA_OUT_OF_RANGE:
|
||||||
|
return MASS_ERR_BAD_LBA;
|
||||||
|
default:
|
||||||
|
return MASS_ERR_CMD_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return MASS_ERR_GENERAL_SCSI_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later.
|
||||||
|
// case 0x05/0x14: we stalled out
|
||||||
|
// case 0x15/0x16: we naked out.
|
||||||
|
default:
|
||||||
|
ErrorMessage<uint8_t> (PSTR("Gen SCSI Err"), status);
|
||||||
|
ErrorMessage<uint8_t> (PSTR("LUN"), bTheLUN);
|
||||||
|
return status;
|
||||||
|
} // switch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
// Debugging code
|
// Debugging code
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1213,20 +1167,20 @@ uint8_t BulkOnly::HandleSCSIError(uint8_t status) {
|
||||||
* @param ep_ptr
|
* @param ep_ptr
|
||||||
*/
|
*/
|
||||||
void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) {
|
void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) {
|
||||||
Notify(PSTR("Endpoint descriptor:"), 0x80);
|
Notify(PSTR("Endpoint descriptor:"), 0x80);
|
||||||
Notify(PSTR("\r\nLength:\t\t"), 0x80);
|
Notify(PSTR("\r\nLength:\t\t"), 0x80);
|
||||||
D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
|
D_PrintHex<uint8_t> (ep_ptr->bLength, 0x80);
|
||||||
Notify(PSTR("\r\nType:\t\t"), 0x80);
|
Notify(PSTR("\r\nType:\t\t"), 0x80);
|
||||||
D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
|
D_PrintHex<uint8_t> (ep_ptr->bDescriptorType, 0x80);
|
||||||
Notify(PSTR("\r\nAddress:\t"), 0x80);
|
Notify(PSTR("\r\nAddress:\t"), 0x80);
|
||||||
D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
|
D_PrintHex<uint8_t> (ep_ptr->bEndpointAddress, 0x80);
|
||||||
Notify(PSTR("\r\nAttributes:\t"), 0x80);
|
Notify(PSTR("\r\nAttributes:\t"), 0x80);
|
||||||
D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
|
D_PrintHex<uint8_t> (ep_ptr->bmAttributes, 0x80);
|
||||||
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
|
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
|
||||||
D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
|
D_PrintHex<uint16_t> (ep_ptr->wMaxPacketSize, 0x80);
|
||||||
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
|
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
|
||||||
D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
|
D_PrintHex<uint8_t> (ep_ptr->bInterval, 0x80);
|
||||||
Notify(PSTR("\r\n"), 0x80);
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1235,31 +1189,31 @@ void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) {
|
||||||
|
|
||||||
/* We won't be needing this... */
|
/* We won't be needing this... */
|
||||||
uint8_t BulkOnly::Read(uint8_t lun __attribute__((unused)), uint32_t addr __attribute__((unused)), uint16_t bsize __attribute__((unused)), uint8_t blocks __attribute__((unused)), USBReadParser * prs __attribute__((unused))) {
|
uint8_t BulkOnly::Read(uint8_t lun __attribute__((unused)), uint32_t addr __attribute__((unused)), uint16_t bsize __attribute__((unused)), uint8_t blocks __attribute__((unused)), USBReadParser * prs __attribute__((unused))) {
|
||||||
#if MS_WANT_PARSER
|
#if MS_WANT_PARSER
|
||||||
if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
|
if (!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
|
||||||
Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80);
|
Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80);
|
||||||
Notify(PSTR("---------\r\n"), 0x80);
|
Notify(PSTR("---------\r\n"), 0x80);
|
||||||
|
|
||||||
CommandBlockWrapper cbw = CommandBlockWrapper();
|
CommandBlockWrapper cbw = CommandBlockWrapper();
|
||||||
|
|
||||||
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
|
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
|
||||||
cbw.dCBWTag = ++dCBWTag;
|
cbw.dCBWTag = ++dCBWTag;
|
||||||
cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks);
|
cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks);
|
||||||
cbw.bmCBWFlags = MASS_CMD_DIR_IN,
|
cbw.bmCBWFlags = MASS_CMD_DIR_IN,
|
||||||
cbw.bmCBWLUN = lun;
|
cbw.bmCBWLUN = lun;
|
||||||
cbw.bmCBWCBLength = 10;
|
cbw.bmCBWCBLength = 10;
|
||||||
|
|
||||||
cbw.CBWCB[0] = SCSI_CMD_READ_10;
|
cbw.CBWCB[0] = SCSI_CMD_READ_10;
|
||||||
cbw.CBWCB[8] = blocks;
|
cbw.CBWCB[8] = blocks;
|
||||||
cbw.CBWCB[2] = ((addr >> 24) & 0xff);
|
cbw.CBWCB[2] = ((addr >> 24) & 0xff);
|
||||||
cbw.CBWCB[3] = ((addr >> 16) & 0xff);
|
cbw.CBWCB[3] = ((addr >> 16) & 0xff);
|
||||||
cbw.CBWCB[4] = ((addr >> 8) & 0xff);
|
cbw.CBWCB[4] = ((addr >> 8) & 0xff);
|
||||||
cbw.CBWCB[5] = (addr & 0xff);
|
cbw.CBWCB[5] = (addr & 0xff);
|
||||||
|
|
||||||
return HandleSCSIError(Transaction(&cbw, bsize, prs, 1));
|
return HandleSCSIError(Transaction(&cbw, bsize, prs, 1));
|
||||||
#else
|
#else
|
||||||
return MASS_ERR_NOT_IMPLEMENTED;
|
return MASS_ERR_NOT_IMPLEMENTED;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // USB_FLASH_DRIVE_SUPPORT
|
#endif // USB_FLASH_DRIVE_SUPPORT
|
||||||
|
|
|
@ -408,7 +408,7 @@ public:
|
||||||
|
|
||||||
CommandBlockWrapper() :
|
CommandBlockWrapper() :
|
||||||
CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
|
CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
|
||||||
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
|
for (int i = 0; i < 16; i++) CBWCB[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic Wrap, CDB zeroed.
|
// Generic Wrap, CDB zeroed.
|
||||||
|
@ -416,7 +416,7 @@ public:
|
||||||
CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
|
CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
|
||||||
CommandBlockWrapperBase(tag, xflen, flgs),
|
CommandBlockWrapperBase(tag, xflen, flgs),
|
||||||
bmCBWLUN(lu), bmReserved1(0), bmCBWCBLength(cmdlen), bmReserved2(0) {
|
bmCBWLUN(lu), bmReserved1(0), bmCBWCBLength(cmdlen), bmReserved2(0) {
|
||||||
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
|
for (int i = 0; i < 16; i++) CBWCB[i] = 0;
|
||||||
// Type punning can cause optimization problems and bugs.
|
// Type punning can cause optimization problems and bugs.
|
||||||
// Using reinterpret_cast to a dreinterpretifferent object is the proper way to do this.
|
// Using reinterpret_cast to a dreinterpretifferent object is the proper way to do this.
|
||||||
//(((BASICCDB_t *) CBWCB)->LUN) = cmd;
|
//(((BASICCDB_t *) CBWCB)->LUN) = cmd;
|
||||||
|
@ -493,27 +493,17 @@ protected:
|
||||||
bool WriteOk[MASS_MAX_SUPPORTED_LUN];
|
bool WriteOk[MASS_MAX_SUPPORTED_LUN];
|
||||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||||
|
|
||||||
|
|
||||||
// Additional Initialization Method for Subclasses
|
// Additional Initialization Method for Subclasses
|
||||||
|
|
||||||
virtual uint8_t OnInit() {
|
virtual uint8_t OnInit() { return 0; }
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BulkOnly(USB *p);
|
BulkOnly(USB *p);
|
||||||
|
|
||||||
uint8_t GetLastUsbError() {
|
uint8_t GetLastUsbError() { return bLastUsbError; };
|
||||||
return bLastUsbError;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t GetbMaxLUN() {
|
uint8_t GetbMaxLUN() { return bMaxLUN; } // Max LUN
|
||||||
return bMaxLUN; // Max LUN
|
uint8_t GetbTheLUN() { return bTheLUN; } // Active LUN
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GetbTheLUN() {
|
|
||||||
return bTheLUN; // Active LUN
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WriteProtected(uint8_t lun);
|
bool WriteProtected(uint8_t lun);
|
||||||
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
|
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
|
||||||
|
@ -533,16 +523,12 @@ public:
|
||||||
uint8_t Release();
|
uint8_t Release();
|
||||||
uint8_t Poll();
|
uint8_t Poll();
|
||||||
|
|
||||||
virtual uint8_t GetAddress() {
|
virtual uint8_t GetAddress() { return bAddress; }
|
||||||
return bAddress;
|
|
||||||
};
|
|
||||||
|
|
||||||
// UsbConfigXtracter implementation
|
// UsbConfigXtracter implementation
|
||||||
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||||
|
|
||||||
virtual bool DEVCLASSOK(uint8_t klass) {
|
virtual bool DEVCLASSOK(uint8_t klass) { return klass == USB_CLASS_MASS_STORAGE; }
|
||||||
return (klass == USB_CLASS_MASS_STORAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
uint8_t SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
||||||
uint8_t SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
uint8_t SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
||||||
|
@ -573,5 +559,4 @@ private:
|
||||||
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf);
|
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf);
|
||||||
uint8_t HandleUsbError(uint8_t error, uint8_t index);
|
uint8_t HandleUsbError(uint8_t error, uint8_t index);
|
||||||
uint8_t HandleSCSIError(uint8_t status);
|
uint8_t HandleSCSIError(uint8_t status);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,11 +22,11 @@
|
||||||
* Web : http://www.circuitsathome.com
|
* Web : http://www.circuitsathome.com
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
#if !defined(_usb_h_) || defined(_max3421e_h_)
|
#pragma once
|
||||||
#error "Never include max3421e.h directly; include Usb.h instead"
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define _max3421e_h_
|
#ifndef _usb_h_
|
||||||
|
#error "Never include max3421e.h directly; include Usb.h instead"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* MAX3421E register/bit names and bitmasks */
|
/* MAX3421E register/bit names and bitmasks */
|
||||||
|
|
||||||
|
@ -231,6 +231,3 @@
|
||||||
|
|
||||||
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
|
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
|
||||||
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
|
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
|
||||||
|
|
||||||
|
|
||||||
#endif //_max3421e_h_
|
|
||||||
|
|
|
@ -35,97 +35,94 @@
|
||||||
int UsbDEBUGlvl = 0x80;
|
int UsbDEBUGlvl = 0x80;
|
||||||
|
|
||||||
void E_Notifyc(char c, int lvl) {
|
void E_Notifyc(char c, int lvl) {
|
||||||
if(UsbDEBUGlvl < lvl) return;
|
if (UsbDEBUGlvl < lvl) return;
|
||||||
#if defined(ARDUINO) && ARDUINO >=100
|
USB_HOST_SERIAL.print(c
|
||||||
USB_HOST_SERIAL.print(c);
|
#if !defined(ARDUINO) || ARDUINO < 100
|
||||||
#else
|
, BYTE
|
||||||
USB_HOST_SERIAL.print(c, BYTE);
|
#endif
|
||||||
#endif
|
);
|
||||||
//USB_HOST_SERIAL.flush();
|
//USB_HOST_SERIAL.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void E_Notify(char const * msg, int lvl) {
|
void E_Notify(char const * msg, int lvl) {
|
||||||
if(UsbDEBUGlvl < lvl) return;
|
if (UsbDEBUGlvl < lvl) return;
|
||||||
if(!msg) return;
|
if (!msg) return;
|
||||||
char c;
|
while (const char c = pgm_read_byte(msg++)) E_Notifyc(c, lvl);
|
||||||
|
|
||||||
while((c = pgm_read_byte(msg++))) E_Notifyc(c, lvl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void E_NotifyStr(char const * msg, int lvl) {
|
void E_NotifyStr(char const * msg, int lvl) {
|
||||||
if(UsbDEBUGlvl < lvl) return;
|
if (UsbDEBUGlvl < lvl) return;
|
||||||
if(!msg) return;
|
if (!msg) return;
|
||||||
char c;
|
while (const char c = *msg++) E_Notifyc(c, lvl);
|
||||||
|
|
||||||
while((c = *msg++)) E_Notifyc(c, lvl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void E_Notify(uint8_t b, int lvl) {
|
void E_Notify(uint8_t b, int lvl) {
|
||||||
if(UsbDEBUGlvl < lvl) return;
|
if (UsbDEBUGlvl < lvl) return;
|
||||||
#if defined(ARDUINO) && ARDUINO >=100
|
USB_HOST_SERIAL.print(b
|
||||||
USB_HOST_SERIAL.print(b);
|
#if !defined(ARDUINO) || ARDUINO < 100
|
||||||
#else
|
, DEC
|
||||||
USB_HOST_SERIAL.print(b, DEC);
|
#endif
|
||||||
#endif
|
);
|
||||||
//USB_HOST_SERIAL.flush();
|
//USB_HOST_SERIAL.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void E_Notify(double d, int lvl) {
|
void E_Notify(double d, int lvl) {
|
||||||
if(UsbDEBUGlvl < lvl) return;
|
if (UsbDEBUGlvl < lvl) return;
|
||||||
USB_HOST_SERIAL.print(d);
|
USB_HOST_SERIAL.print(d);
|
||||||
//USB_HOST_SERIAL.flush();
|
//USB_HOST_SERIAL.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
|
|
||||||
void NotifyFailGetDevDescr(void) {
|
void NotifyFailGetDevDescr(void) {
|
||||||
Notify(PSTR("\r\ngetDevDescr "), 0x80);
|
Notify(PSTR("\r\ngetDevDescr "), 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyFailSetDevTblEntry(void) {
|
void NotifyFailSetDevTblEntry(void) {
|
||||||
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
|
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyFailGetConfDescr(void) {
|
void NotifyFailGetConfDescr(void) {
|
||||||
Notify(PSTR("\r\ngetConf "), 0x80);
|
Notify(PSTR("\r\ngetConf "), 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyFailSetConfDescr(void) {
|
void NotifyFailSetConfDescr(void) {
|
||||||
Notify(PSTR("\r\nsetConf "), 0x80);
|
Notify(PSTR("\r\nsetConf "), 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyFailGetDevDescr(uint8_t reason) {
|
void NotifyFailGetDevDescr(uint8_t reason) {
|
||||||
NotifyFailGetDevDescr();
|
NotifyFailGetDevDescr();
|
||||||
NotifyFail(reason);
|
NotifyFail(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyFailSetDevTblEntry(uint8_t reason) {
|
void NotifyFailSetDevTblEntry(uint8_t reason) {
|
||||||
NotifyFailSetDevTblEntry();
|
NotifyFailSetDevTblEntry();
|
||||||
NotifyFail(reason);
|
NotifyFail(reason);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyFailGetConfDescr(uint8_t reason) {
|
void NotifyFailGetConfDescr(uint8_t reason) {
|
||||||
NotifyFailGetConfDescr();
|
NotifyFailGetConfDescr();
|
||||||
NotifyFail(reason);
|
NotifyFail(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyFailSetConfDescr(uint8_t reason) {
|
void NotifyFailSetConfDescr(uint8_t reason) {
|
||||||
NotifyFailSetConfDescr();
|
NotifyFailSetConfDescr();
|
||||||
NotifyFail(reason);
|
NotifyFail(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
|
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
|
||||||
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
|
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
|
||||||
D_PrintHex<uint16_t > (VID, 0x80);
|
D_PrintHex<uint16_t > (VID, 0x80);
|
||||||
Notify(PSTR(" PID: "), 0x80);
|
Notify(PSTR(" PID: "), 0x80);
|
||||||
D_PrintHex<uint16_t > (PID, 0x80);
|
D_PrintHex<uint16_t > (PID, 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NotifyFail(uint8_t rcode) {
|
||||||
|
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||||
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
void NotifyFail(uint8_t rcode) {
|
|
||||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
|
||||||
Notify(PSTR("\r\n"), 0x80);
|
|
||||||
}
|
|
||||||
#endif // DEBUG_USB_HOST
|
#endif // DEBUG_USB_HOST
|
||||||
|
|
||||||
#endif // USB_FLASH_DRIVE_SUPPORT
|
#endif // USB_FLASH_DRIVE_SUPPORT
|
||||||
|
|
|
@ -22,10 +22,11 @@
|
||||||
* Web : http://www.circuitsathome.com
|
* Web : http://www.circuitsathome.com
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
#if !defined(_usb_h_) || defined(__MESSAGE_H__)
|
#pragma once
|
||||||
#error "Never include message.h directly; include Usb.h instead"
|
|
||||||
#else
|
#ifndef _usb_h_
|
||||||
#define __MESSAGE_H__
|
#error "Never include message.h directly; include Usb.h instead"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern int UsbDEBUGlvl;
|
extern int UsbDEBUGlvl;
|
||||||
|
|
||||||
|
@ -35,52 +36,50 @@ void E_NotifyStr(char const * msg, int lvl);
|
||||||
void E_Notifyc(char c, int lvl);
|
void E_Notifyc(char c, int lvl);
|
||||||
|
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
#define Notify E_Notify
|
#define Notify E_Notify
|
||||||
#define NotifyStr E_NotifyStr
|
#define NotifyStr E_NotifyStr
|
||||||
#define Notifyc E_Notifyc
|
#define Notifyc E_Notifyc
|
||||||
void NotifyFailGetDevDescr(uint8_t reason);
|
void NotifyFailGetDevDescr(uint8_t reason);
|
||||||
void NotifyFailSetDevTblEntry(uint8_t reason);
|
void NotifyFailSetDevTblEntry(uint8_t reason);
|
||||||
void NotifyFailGetConfDescr(uint8_t reason);
|
void NotifyFailGetConfDescr(uint8_t reason);
|
||||||
void NotifyFailSetConfDescr(uint8_t reason);
|
void NotifyFailSetConfDescr(uint8_t reason);
|
||||||
void NotifyFailGetDevDescr(void);
|
void NotifyFailGetDevDescr(void);
|
||||||
void NotifyFailSetDevTblEntry(void);
|
void NotifyFailSetDevTblEntry(void);
|
||||||
void NotifyFailGetConfDescr(void);
|
void NotifyFailGetConfDescr(void);
|
||||||
void NotifyFailSetConfDescr(void);
|
void NotifyFailSetConfDescr(void);
|
||||||
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
|
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
|
||||||
void NotifyFail(uint8_t rcode);
|
void NotifyFail(uint8_t rcode);
|
||||||
#else
|
#else
|
||||||
#define Notify(...) ((void)0)
|
#define Notify(...) ((void)0)
|
||||||
#define NotifyStr(...) ((void)0)
|
#define NotifyStr(...) ((void)0)
|
||||||
#define Notifyc(...) ((void)0)
|
#define Notifyc(...) ((void)0)
|
||||||
#define NotifyFailGetDevDescr(...) ((void)0)
|
#define NotifyFailGetDevDescr(...) ((void)0)
|
||||||
#define NotifyFailSetDevTblEntry(...) ((void)0)
|
#define NotifyFailSetDevTblEntry(...) ((void)0)
|
||||||
#define NotifyFailGetConfDescr(...) ((void)0)
|
#define NotifyFailGetConfDescr(...) ((void)0)
|
||||||
#define NotifyFailGetDevDescr(...) ((void)0)
|
#define NotifyFailGetDevDescr(...) ((void)0)
|
||||||
#define NotifyFailSetDevTblEntry(...) ((void)0)
|
#define NotifyFailSetDevTblEntry(...) ((void)0)
|
||||||
#define NotifyFailGetConfDescr(...) ((void)0)
|
#define NotifyFailGetConfDescr(...) ((void)0)
|
||||||
#define NotifyFailSetConfDescr(...) ((void)0)
|
#define NotifyFailSetConfDescr(...) ((void)0)
|
||||||
#define NotifyFailUnknownDevice(...) ((void)0)
|
#define NotifyFailUnknownDevice(...) ((void)0)
|
||||||
#define NotifyFail(...) ((void)0)
|
#define NotifyFail(...) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class ERROR_TYPE>
|
template <class ERROR_TYPE>
|
||||||
void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
|
void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
Notify(msg, level);
|
Notify(msg, level);
|
||||||
Notify(PSTR(": "), level);
|
Notify(PSTR(": "), level);
|
||||||
D_PrintHex<ERROR_TYPE > (rcode, level);
|
D_PrintHex<ERROR_TYPE > (rcode, level);
|
||||||
Notify(PSTR("\r\n"), level);
|
Notify(PSTR("\r\n"), level);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ERROR_TYPE>
|
template <class ERROR_TYPE>
|
||||||
void ErrorMessage(char const * msg __attribute__((unused)), ERROR_TYPE rcode __attribute__((unused)) = 0) {
|
void ErrorMessage(char const * msg __attribute__((unused)), ERROR_TYPE rcode __attribute__((unused)) = 0) {
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
Notify(msg, 0x80);
|
Notify(msg, 0x80);
|
||||||
Notify(PSTR(": "), 0x80);
|
Notify(PSTR(": "), 0x80);
|
||||||
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
|
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
|
||||||
Notify(PSTR("\r\n"), 0x80);
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __MESSAGE_H__
|
|
||||||
|
|
|
@ -30,53 +30,48 @@
|
||||||
#include "Usb.h"
|
#include "Usb.h"
|
||||||
|
|
||||||
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
|
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
|
||||||
if(!pBuf) {
|
if (!pBuf) {
|
||||||
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
|
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for(; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
|
for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
|
||||||
pBuf[valueSize - countDown] = (**pp);
|
pBuf[valueSize - countDown] = (**pp);
|
||||||
|
|
||||||
if(countDown)
|
if (countDown) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
countDown = valueSize;
|
countDown = valueSize;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
|
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
|
||||||
switch(nStage) {
|
switch (nStage) {
|
||||||
case 0:
|
case 0:
|
||||||
pBuf->valueSize = lenSize;
|
pBuf->valueSize = lenSize;
|
||||||
theParser.Initialize(pBuf);
|
theParser.Initialize(pBuf);
|
||||||
nStage = 1;
|
nStage = 1;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
if(!theParser.Parse(pp, pcntdn))
|
if (!theParser.Parse(pp, pcntdn)) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
arLen = 0;
|
arLen = 0;
|
||||||
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
|
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
|
||||||
arLenCntdn = arLen;
|
arLenCntdn = arLen;
|
||||||
nStage = 2;
|
nStage = 2;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
pBuf->valueSize = valSize;
|
pBuf->valueSize = valSize;
|
||||||
theParser.Initialize(pBuf);
|
theParser.Initialize(pBuf);
|
||||||
nStage = 3;
|
nStage = 3;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
for(; arLenCntdn; arLenCntdn--) {
|
for (; arLenCntdn; arLenCntdn--) {
|
||||||
if(!theParser.Parse(pp, pcntdn))
|
if (!theParser.Parse(pp, pcntdn)) return false;
|
||||||
return false;
|
if (pf) pf(pBuf, (arLen - arLenCntdn), me);
|
||||||
|
}
|
||||||
|
|
||||||
if(pf)
|
nStage = 0;
|
||||||
pf(pBuf, (arLen - arLenCntdn), me);
|
}
|
||||||
}
|
return true;
|
||||||
|
|
||||||
nStage = 0;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // USB_FLASH_DRIVE_SUPPORT
|
#endif // USB_FLASH_DRIVE_SUPPORT
|
||||||
|
|
|
@ -22,67 +22,65 @@
|
||||||
* Web : http://www.circuitsathome.com
|
* Web : http://www.circuitsathome.com
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#if !defined(_usb_h_) || defined(__PARSETOOLS_H__)
|
#ifndef _usb_h_
|
||||||
#error "Never include parsetools.h directly; include Usb.h instead"
|
#error "Never include parsetools.h directly; include Usb.h instead"
|
||||||
#else
|
#endif
|
||||||
#define __PARSETOOLS_H__
|
|
||||||
|
|
||||||
struct MultiValueBuffer {
|
struct MultiValueBuffer {
|
||||||
uint8_t valueSize;
|
uint8_t valueSize;
|
||||||
void *pValue;
|
void *pValue;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
class MultiByteValueParser {
|
class MultiByteValueParser {
|
||||||
uint8_t * pBuf;
|
uint8_t * pBuf;
|
||||||
uint8_t countDown;
|
uint8_t countDown;
|
||||||
uint8_t valueSize;
|
uint8_t valueSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
|
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t* GetBuffer() {
|
const uint8_t* GetBuffer() { return pBuf; }
|
||||||
return pBuf;
|
|
||||||
};
|
|
||||||
|
|
||||||
void Initialize(MultiValueBuffer * const pbuf) {
|
void Initialize(MultiValueBuffer * const pbuf) {
|
||||||
pBuf = (uint8_t*)pbuf->pValue;
|
pBuf = (uint8_t*)pbuf->pValue;
|
||||||
countDown = valueSize = pbuf->valueSize;
|
countDown = valueSize = pbuf->valueSize;
|
||||||
};
|
}
|
||||||
|
|
||||||
bool Parse(uint8_t **pp, uint16_t *pcntdn);
|
bool Parse(uint8_t **pp, uint16_t *pcntdn);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ByteSkipper {
|
class ByteSkipper {
|
||||||
uint8_t *pBuf;
|
uint8_t *pBuf;
|
||||||
uint8_t nStage;
|
uint8_t nStage;
|
||||||
uint16_t countDown;
|
uint16_t countDown;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
|
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
|
||||||
};
|
}
|
||||||
|
|
||||||
void Initialize(MultiValueBuffer *pbuf) {
|
void Initialize(MultiValueBuffer *pbuf) {
|
||||||
pBuf = (uint8_t*)pbuf->pValue;
|
pBuf = (uint8_t*)pbuf->pValue;
|
||||||
countDown = 0;
|
countDown = 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
|
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
|
||||||
switch(nStage) {
|
switch (nStage) {
|
||||||
case 0:
|
case 0:
|
||||||
countDown = bytes_to_skip;
|
countDown = bytes_to_skip;
|
||||||
nStage++;
|
nStage++;
|
||||||
case 1:
|
case 1:
|
||||||
for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
|
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
|
||||||
|
|
||||||
if(!countDown)
|
if (!countDown)
|
||||||
nStage = 0;
|
nStage = 0;
|
||||||
};
|
}
|
||||||
return (!countDown);
|
return (!countDown);
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser
|
// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser
|
||||||
|
@ -91,58 +89,57 @@ typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t cou
|
||||||
class PTPListParser {
|
class PTPListParser {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum ParseMode {
|
enum ParseMode {
|
||||||
modeArray, modeRange/*, modeEnum*/
|
modeArray, modeRange/*, modeEnum*/
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t nStage;
|
uint8_t nStage;
|
||||||
uint8_t enStage;
|
uint8_t enStage;
|
||||||
|
|
||||||
uint32_t arLen;
|
uint32_t arLen;
|
||||||
uint32_t arLenCntdn;
|
uint32_t arLenCntdn;
|
||||||
|
|
||||||
uint8_t lenSize; // size of the array length field in bytes
|
uint8_t lenSize; // size of the array length field in bytes
|
||||||
uint8_t valSize; // size of the array element in bytes
|
uint8_t valSize; // size of the array element in bytes
|
||||||
|
|
||||||
MultiValueBuffer *pBuf;
|
MultiValueBuffer *pBuf;
|
||||||
|
|
||||||
// The only parser for both size and array element parsing
|
// The only parser for both size and array element parsing
|
||||||
MultiByteValueParser theParser;
|
MultiByteValueParser theParser;
|
||||||
|
|
||||||
uint8_t /*ParseMode*/ prsMode;
|
uint8_t /*ParseMode*/ prsMode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PTPListParser() :
|
PTPListParser() :
|
||||||
nStage(0),
|
nStage(0),
|
||||||
enStage(0),
|
enStage(0),
|
||||||
arLen(0),
|
arLen(0),
|
||||||
arLenCntdn(0),
|
arLenCntdn(0),
|
||||||
lenSize(0),
|
lenSize(0),
|
||||||
valSize(0),
|
valSize(0),
|
||||||
pBuf(NULL),
|
pBuf(NULL),
|
||||||
prsMode(modeArray) {
|
prsMode(modeArray) { }
|
||||||
};
|
;
|
||||||
|
|
||||||
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
|
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
|
||||||
pBuf = p;
|
pBuf = p;
|
||||||
lenSize = len_size;
|
lenSize = len_size;
|
||||||
valSize = val_size;
|
valSize = val_size;
|
||||||
prsMode = mode;
|
prsMode = mode;
|
||||||
|
|
||||||
if(prsMode == modeRange) {
|
if (prsMode == modeRange) {
|
||||||
arLenCntdn = arLen = 3;
|
arLenCntdn = arLen = 3;
|
||||||
nStage = 2;
|
nStage = 2;
|
||||||
} else {
|
}
|
||||||
arLenCntdn = arLen = 0;
|
else {
|
||||||
nStage = 0;
|
arLenCntdn = arLen = 0;
|
||||||
}
|
nStage = 0;
|
||||||
enStage = 0;
|
}
|
||||||
theParser.Initialize(p);
|
enStage = 0;
|
||||||
};
|
theParser.Initialize(p);
|
||||||
|
}
|
||||||
|
|
||||||
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
|
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __PARSETOOLS_H__
|
|
||||||
|
|
|
@ -22,71 +22,59 @@
|
||||||
* Web : http://www.circuitsathome.com
|
* Web : http://www.circuitsathome.com
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#if !defined(_usb_h_) || defined(__PRINTHEX_H__)
|
#ifndef _usb_h_
|
||||||
#error "Never include printhex.h directly; include Usb.h instead"
|
#error "Never include printhex.h directly; include Usb.h instead"
|
||||||
#else
|
#endif
|
||||||
#define __PRINTHEX_H__
|
|
||||||
|
|
||||||
void E_Notifyc(char c, int lvl);
|
void E_Notifyc(char c, int lvl);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void PrintHex(T val, int lvl) {
|
void PrintHex(T val, int lvl) {
|
||||||
int num_nibbles = sizeof (T) * 2;
|
int num_nibbles = sizeof (T) * 2;
|
||||||
|
do {
|
||||||
do {
|
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
|
||||||
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
|
if (v > 57) v += 7;
|
||||||
if(v > 57) v += 7;
|
E_Notifyc(v, lvl);
|
||||||
E_Notifyc(v, lvl);
|
} while (--num_nibbles);
|
||||||
} while(--num_nibbles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void PrintBin(T val, int lvl) {
|
void PrintBin(T val, int lvl) {
|
||||||
for(T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
|
for (T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
|
||||||
if(val & mask)
|
E_Notifyc(val & mask ? '1' : '0', lvl);
|
||||||
E_Notifyc('1', lvl);
|
|
||||||
else
|
|
||||||
E_Notifyc('0', lvl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void SerialPrintHex(T val) {
|
void SerialPrintHex(T val) {
|
||||||
int num_nibbles = sizeof (T) * 2;
|
int num_nibbles = sizeof (T) * 2;
|
||||||
|
do {
|
||||||
do {
|
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
|
||||||
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
|
if (v > 57) v += 7;
|
||||||
if(v > 57) v += 7;
|
USB_HOST_SERIAL.print(v);
|
||||||
USB_HOST_SERIAL.print(v);
|
} while (--num_nibbles);
|
||||||
} while(--num_nibbles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void PrintHex2(Print *prn, T val) {
|
void PrintHex2(Print *prn, T val) {
|
||||||
T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2));
|
T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2));
|
||||||
|
while (mask > 1) {
|
||||||
while(mask > 1) {
|
if (val < mask) prn->print("0");
|
||||||
if(val < mask)
|
mask >>= 4;
|
||||||
prn->print("0");
|
}
|
||||||
|
prn->print((T)val, HEX);
|
||||||
mask >>= 4;
|
|
||||||
}
|
|
||||||
prn->print((T)val, HEX);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> void D_PrintHex(T val __attribute__((unused)), int lvl __attribute__((unused))) {
|
template <class T> void D_PrintHex(T val __attribute__((unused)), int lvl __attribute__((unused))) {
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
PrintHex<T > (val, lvl);
|
PrintHex<T > (val, lvl);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void D_PrintBin(T val, int lvl) {
|
void D_PrintBin(T val, int lvl) {
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
PrintBin<T > (val, lvl);
|
PrintBin<T > (val, lvl);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // __PRINTHEX_H__
|
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
* flash drives and simple USB hard drives.
|
* flash drives and simple USB hard drives.
|
||||||
* Disable this by defining DELAY(x) to be delay(x).
|
* Disable this by defining DELAY(x) to be delay(x).
|
||||||
*/
|
*/
|
||||||
#define delay(x) if((x) < 200) safe_delay(x)
|
#define delay(x) if ((x) < 200) safe_delay(x)
|
||||||
/* Almost all USB flash drives and simple USB hard drives fail the write
|
/* Almost all USB flash drives and simple USB hard drives fail the write
|
||||||
* protect test and add 20 - 30 seconds to USB init. Set SKIP_WRITE_PROTECT
|
* protect test and add 20 - 30 seconds to USB init. Set SKIP_WRITE_PROTECT
|
||||||
* to nonzero to skip the test and assume the drive is writable.
|
* to nonzero to skip the test and assume the drive is writable.
|
||||||
|
|
|
@ -23,12 +23,11 @@
|
||||||
* e-mail : support@circuitsathome.com
|
* e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(_usb_h_) || defined(_ch9_h_)
|
#ifndef _usb_h_
|
||||||
#error "Never include usb_ch9.h directly; include Usb.h instead"
|
#error "Never include usb_ch9.h directly; include Usb.h instead"
|
||||||
#else
|
#endif
|
||||||
|
|
||||||
/* USB chapter 9 structures */
|
/* USB chapter 9 structures */
|
||||||
#define _ch9_h_
|
|
||||||
|
|
||||||
/* Misc.USB constants */
|
/* Misc.USB constants */
|
||||||
#define DEV_DESCR_LEN 18 //device descriptor length
|
#define DEV_DESCR_LEN 18 //device descriptor length
|
||||||
|
@ -81,7 +80,6 @@
|
||||||
#define HID_DESCRIPTOR_HID 0x21
|
#define HID_DESCRIPTOR_HID 0x21
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* OTG SET FEATURE Constants */
|
/* OTG SET FEATURE Constants */
|
||||||
#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
|
#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
|
||||||
#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
|
#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
|
||||||
|
@ -170,5 +168,3 @@ typedef struct {
|
||||||
uint8_t bDescrType; // Type of class descriptor
|
uint8_t bDescrType; // Type of class descriptor
|
||||||
uint16_t wDescriptorLength; // Total size of the Report descriptor
|
uint16_t wDescriptorLength; // Total size of the Report descriptor
|
||||||
} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
|
} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
|
||||||
|
|
||||||
#endif // _ch9_h_
|
|
||||||
|
|
Reference in a new issue