Coding standards

This commit is contained in:
Scott Lahteine 2019-02-12 16:25:49 -06:00
parent 19af90face
commit 3a1b6fe8c1
43 changed files with 2033 additions and 2344 deletions

View file

@ -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) {

View file

@ -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;

View file

@ -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" {

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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];

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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;
} }

View file

@ -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);
} }
} }

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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) {

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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))

View file

@ -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)

View file

@ -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_

View file

@ -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;
} }

View file

@ -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__

View file

@ -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__

View file

@ -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__

View file

@ -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__

View file

@ -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

View file

@ -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);
}; };

View file

@ -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_

View file

@ -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

View file

@ -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__

View file

@ -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

View file

@ -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__

View file

@ -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__

View file

@ -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.

View file

@ -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_