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
NVIC_SystemReset();
while(1) { WDT_Restart(WDT); }
for (;;) WDT_Restart(WDT);
}
__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) {
switch(msg) {
switch (msg) {
case U8G_COM_MSG_STOP:
break;

View file

@ -206,7 +206,7 @@ void HardFault_HandlerC(unsigned long *sp, unsigned long lr, unsigned long cause
// Reset controller
NVIC_SystemReset();
while(1) { watchdog_init(); }
for (;;) watchdog_init();
}
extern "C" {

View file

@ -45,12 +45,11 @@
#define OUTPUT 1
#define INPUT_PULLUP 2
uint8_t LPC1768_PIN_PORT(const uint8_t pin);
uint8_t LPC1768_PIN_PIN(const uint8_t pin);
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif
// I/O functions
@ -63,22 +62,21 @@ void pinMode_LCD(uint8_t pin, uint8_t mode) {
PINSEL_FUNC_0,
PINSEL_PINMODE_TRISTATE,
PINSEL_PINMODE_NORMAL };
switch(mode) {
case INPUT:
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR &= ~LPC_PIN(LPC1768_PIN_PIN(pin));
PINSEL_ConfigPin(&config);
break;
case OUTPUT:
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR |= LPC_PIN(LPC1768_PIN_PIN(pin));
PINSEL_ConfigPin(&config);
break;
case INPUT_PULLUP:
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR &= ~LPC_PIN(LPC1768_PIN_PIN(pin));
config.Pinmode = PINSEL_PINMODE_PULLUP;
PINSEL_ConfigPin(&config);
break;
default:
break;
switch (mode) {
case INPUT:
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR &= ~LPC_PIN(LPC1768_PIN_PIN(pin));
PINSEL_ConfigPin(&config);
break;
case OUTPUT:
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR |= LPC_PIN(LPC1768_PIN_PIN(pin));
PINSEL_ConfigPin(&config);
break;
case INPUT_PULLUP:
LPC_GPIO(LPC1768_PIN_PORT(pin))->FIODIR &= ~LPC_PIN(LPC1768_PIN_PIN(pin));
config.Pinmode = PINSEL_PINMODE_PULLUP;
PINSEL_ConfigPin(&config);
break;
default: 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;
}
#ifdef __cplusplus
}
#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;
/* setup bus, might be a repeated start */
if (u8g_i2c_start(I2C_SLA) == 0)
return 0;
if (u8g->pin_list[U8G_PI_A0_STATE] == 0 ) {
if (u8g_i2c_start(I2C_SLA) == 0) return 0;
if (u8g->pin_list[U8G_PI_A0_STATE] == 0) {
if (u8g_i2c_send_byte(I2C_CMD_MODE) == 0) return 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) {
switch(msg) {
switch (msg) {
case U8G_COM_MSG_INIT:
//u8g_com_arduino_digital_write(u8g, U8G_PI_SCL, 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) {
switch(msg) {
switch (msg) {
case U8G_COM_MSG_INIT:
u8g_SetPILevel(u8g, U8G_PI_CS, 0);
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);
}
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)
{
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) {
case U8G_COM_MSG_INIT:
SCK_pin_ST7920_HAL = u8g->pin_list[U8G_PI_SCK];
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) {
switch(msg) {
switch (msg) {
case U8G_COM_MSG_INIT:
u8g_SetPIOutput(u8g, U8G_PI_SCK);
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;
switch(msg) {
switch (msg) {
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_INIT:
@ -154,7 +154,7 @@ void LCD_IO_Init(uint8_t cs, uint8_t rs) {
if (fsmcInit) return;
fsmcInit = 1;
switch(cs) {
switch (cs) {
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_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)
switch(rs) {
switch (rs) {
case FSMC_RS_A0: _ORADDR( 1); break;
case FSMC_RS_A1: _ORADDR( 2); 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) {
switch(timer_num) {
switch (timer_num) {
case 0: NVIC_ENABLE_IRQ(IRQ_FTM0); 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) {
switch(timer_num) {
switch (timer_num) {
case 0:
FTM0_CNT = 0x0000;
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) {
switch(timer_num) {
switch (timer_num) {
case 0: NVIC_ENABLE_IRQ(IRQ_FTM0); 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) {
switch(timer_num) {
switch (timer_num) {
case 0:
FTM0_CNT = 0x0000;
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) {
char buffer[20]; // for the sprintf statements
switch(pin) {
switch (pin) {
FTM_CASE(0,0);
FTM_CASE(0,1);
FTM_CASE(0,2);

View file

@ -103,7 +103,7 @@ typedef struct {
* Macros
**************************************************************************/
#define M_IsOriginValid(v) (((v) & 0x7F) ? true : false)
#define M_IsOriginValid(v) !!((v) & 0x7F)
#define M_Origin2Str(v) ((v) ? "VALID" : "INVALID")
#ifdef UNW_DEBUG

View file

@ -32,23 +32,17 @@
* \retval false This is not a data-processing instruction,
*/
static bool isDataProc(uint32_t instr) {
uint8_t opcode = (instr & 0x01E00000) >> 21;
bool S = (instr & 0x00100000) ? true : false;
if ((instr & 0xFC000000) != 0xE0000000) return false;
if ((instr & 0xFC000000) != 0xE0000000) {
return false;
}
else if (!S && opcode >= 8 && opcode <= 11) {
/* TST, TEQ, CMP and CMN all require S to be set */
return false;
}
else
return true;
/* TST, TEQ, CMP and CMN all require S to be set */
bool S = !!(instr & 0x00100000);
if (!S && opcode >= 8 && opcode <= 11) return false;
return true;
}
UnwResult UnwStartArm(UnwState * const state) {
bool found = false;
uint16_t t = UNW_MAX_INSTR_COUNT;
@ -56,9 +50,8 @@ UnwResult UnwStartArm(UnwState * const state) {
uint32_t instr;
/* 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;
}
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 */
if (state->regData[rn].v & 0x1) {
/* Branching to THUMB */
if (state->regData[rn].v & 0x1) /* Branching to THUMB */
return UnwStartThumb(state);
}
else {
/* Branch to ARM */
/* Account for the auto-increment which isn't needed */
state->regData[15].v -= 4;
}
/* Branch to ARM */
/* Account for the auto-increment which isn't needed */
state->regData[15].v -= 4;
}
/* Branch */
else if ((instr & 0xFF000000) == 0xEA000000) {
int32_t offset = (instr & 0x00FFFFFF);
/* Shift value */
offset = offset << 2;
int32_t offset = (instr & 0x00FFFFFF) << 2;
/* Sign extend if needed */
if (offset & 0x02000000) {
offset |= 0xFC000000;
}
if (offset & 0x02000000) offset |= 0xFC000000;
UnwPrintd2("B %d\n", offset);
@ -142,11 +124,12 @@ UnwResult UnwStartArm(UnwState * const state) {
/* MRS */
else if ((instr & 0xFFBF0FFF) == 0xE10F0000) {
#ifdef UNW_DEBUG
bool R = (instr & 0x00400000) ? true : false;
#endif
#ifdef UNW_DEBUG
const bool R = !!(instr & 0x00400000);
#else
constexpr bool R = false;
#endif
uint8_t rd = (instr & 0x0000F000) >> 12;
UnwPrintd4("MRS r%d,%s\t; r%d invalidated", rd, R ? "SPSR" : "CPSR", rd);
/* Status registers untracked */
@ -154,11 +137,10 @@ UnwResult UnwStartArm(UnwState * const state) {
}
/* MSR */
else if ((instr & 0xFFB0F000) == 0xE120F000) {
#ifdef UNW_DEBUG
bool R = (instr & 0x00400000) ? true : false;
#ifdef UNW_DEBUG
UnwPrintd2("MSR %s_?, ???", (instr & 0x00400000) ? "SPSR" : "CPSR");
#endif
UnwPrintd2("MSR %s_?, ???", R ? "SPSR" : "CPSR");
#endif
/* Status registers untracked.
* Potentially this could change processor mode and switch
* banked registers r8-r14. Most likely is that r13 (sp) will
@ -170,18 +152,18 @@ UnwResult UnwStartArm(UnwState * const state) {
}
/* Data processing */
else if (isDataProc(instr)) {
bool I = (instr & 0x02000000) ? true : false;
bool I = !!(instr & 0x02000000);
uint8_t opcode = (instr & 0x01E00000) >> 21;
#ifdef UNW_DEBUG
bool S = (instr & 0x00100000) ? true : false;
#endif
#ifdef UNW_DEBUG
bool S = !!(instr & 0x00100000);
#endif
uint8_t rn = (instr & 0x000F0000) >> 16;
uint8_t rd = (instr & 0x0000F000) >> 12;
uint16_t operand2 = (instr & 0x00000FFF);
uint32_t op2val;
int op2origin;
switch(opcode) {
switch (opcode) {
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 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 */
uint8_t rm = (operand2 & 0x000F);
uint8_t regShift = (operand2 & 0x0010) ? true : false;
uint8_t regShift = !!(operand2 & 0x0010);
uint8_t shiftType = (operand2 & 0x0060) >> 5;
uint32_t shiftDist;
#ifdef UNW_DEBUG
const char * const shiftMnu[4] = { "LSL", "LSR", "ASR", "ROR" };
#endif
#ifdef UNW_DEBUG
const char * const shiftMnu[4] = { "LSL", "LSR", "ASR", "ROR" };
#endif
UnwPrintd2("r%d ", rm);
/* Get the shift distance */
if (regShift) {
uint8_t rs = (operand2 & 0x0F00) >> 8;
if (operand2 & 0x00800) {
UnwPrintd1("\nError: Bit should be zero\n");
return UNWIND_ILLEGAL_INSTR;
}
else if (rs == 15) {
UnwPrintd1("\nError: Cannot use R15 with register shift\n");
return UNWIND_ILLEGAL_INSTR;
}
@ -250,46 +229,33 @@ UnwResult UnwStartArm(UnwState * const state) {
else {
shiftDist = (operand2 & 0x0F80) >> 7;
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));
}
/* Apply the shift type to the source register */
switch(shiftType) {
switch (shiftType) {
case 0: /* logical left */
op2val = state->regData[rm].v << shiftDist;
break;
case 1: /* logical right */
if (!regShift && shiftDist == 0) {
shiftDist = 32;
}
if (!regShift && shiftDist == 0) shiftDist = 32;
op2val = state->regData[rm].v >> shiftDist;
break;
case 2: /* arithmetic right */
if (!regShift && shiftDist == 0) {
shiftDist = 32;
}
if (!regShift && shiftDist == 0) shiftDist = 32;
if (state->regData[rm].v & 0x80000000) {
/* Register shifts maybe greater than 32 */
if (shiftDist >= 32) {
if (shiftDist >= 32)
op2val = 0xFFFFFFFF;
}
else {
op2val = state->regData[rm].v >> shiftDist;
op2val |= 0xFFFFFFFF << (32 - shiftDist);
}
else
op2val = (state->regData[rm].v >> shiftDist) | (0xFFFFFFFF << (32 - shiftDist));
}
else {
else
op2val = state->regData[rm].v >> shiftDist;
}
break;
case 3: /* rotate right */
@ -317,19 +283,14 @@ UnwResult UnwStartArm(UnwState * const state) {
}
/* Decide the data origin */
if (M_IsOriginValid(op2origin) &&
M_IsOriginValid(state->regData[rm].o)) {
op2origin = state->regData[rm].o;
op2origin |= REG_VAL_ARITHMETIC;
}
else {
if (M_IsOriginValid(op2origin) && M_IsOriginValid(state->regData[rm].o))
op2origin = REG_VAL_ARITHMETIC | state->regData[rm].o;
else
op2origin = REG_VAL_INVALID;
}
}
/* Propagate register validity */
switch(opcode) {
switch (opcode) {
case 0: /* AND: Rd := Op1 AND Op2 */
case 1: /* EOR: Rd := Op1 EOR 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
* ahead.
*/
if (!I && (operand2 & 0x0010))
state->regData[rn].v += 12;
else
state->regData[rn].v += 8;
state->regData[rn].v += ((!I && (operand2 & 0x0010)) ? 12 : 8);
}
/* Compute values */
switch(opcode) {
switch (opcode) {
case 0: /* AND: Rd := Op1 AND Op2 */
state->regData[rd].v = state->regData[rn].v & op2val;
break;
@ -429,12 +387,8 @@ UnwResult UnwStartArm(UnwState * const state) {
}
/* Remove the prefetch offset from the PC */
if (rd != 15 && rn == 15) {
if (!I && (operand2 & 0x0010))
state->regData[rn].v -= 12;
else
state->regData[rn].v -= 8;
}
if (rd != 15 && rn == 15)
state->regData[rn].v -= ((!I && (operand2 & 0x0010)) ? 12 : 8);
}
/* Block Data Transfer
@ -442,26 +396,25 @@ UnwResult UnwStartArm(UnwState * const state) {
*/
else if ((instr & 0xFE000000) == 0xE8000000) {
bool P = (instr & 0x01000000) ? true : false;
bool U = (instr & 0x00800000) ? true : false;
bool S = (instr & 0x00400000) ? true : false;
bool W = (instr & 0x00200000) ? true : false;
bool L = (instr & 0x00100000) ? true : false;
bool P = !!(instr & 0x01000000),
U = !!(instr & 0x00800000),
S = !!(instr & 0x00400000),
W = !!(instr & 0x00200000),
L = !!(instr & 0x00100000);
uint16_t baseReg = (instr & 0x000F0000) >> 16;
uint16_t regList = (instr & 0x0000FFFF);
uint32_t addr = state->regData[baseReg].v;
bool addrValid = M_IsOriginValid(state->regData[baseReg].o);
int8_t r;
#ifdef UNW_DEBUG
/* Display the instruction */
if (L) {
UnwPrintd6("LDM%c%c r%d%s, {reglist}%s\n", P ? 'E' : 'F', U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
}
else {
UnwPrintd6("STM%c%c r%d%s, {reglist}%s\n", !P ? 'E' : 'F', !U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
}
#endif
#ifdef UNW_DEBUG
/* Display the instruction */
if (L)
UnwPrintd6("LDM%c%c r%d%s, {reglist}%s\n", P ? 'E' : 'F', U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
else
UnwPrintd6("STM%c%c r%d%s, {reglist}%s\n", !P ? 'E' : 'F', !U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
#endif
/* S indicates that banked registers (untracked) are used, unless
* this is a load including the PC when the S-bit indicates that
* 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 */
if (regList & (0x01 << r)) {
if (P)
addr += U ? 4 : -4;
if (P) addr += U ? 4 : -4;
if (L) {
if (addrValid) {
if (!UnwMemReadRegister(state, addr, &state->regData[r])) {
if (!UnwMemReadRegister(state, addr, &state->regData[r]))
return UNWIND_DREAD_W_FAIL;
}
/* 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;
}
UnwPrintd5(" R%d = 0x%08x\t; r%d %s\n",r,state->regData[r].v,r, M_Origin2Str(state->regData[r].o));
}
else {
/* Invalidate the register as the base reg was invalid */
state->regData[r].o = REG_VAL_INVALID;
UnwPrintd2(" R%d = ???\n", r);
}
}
else {
if (addrValid) {
if (!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
return UNWIND_DWRITE_W_FAIL;
}
}
if (addrValid && !UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r]))
return UNWIND_DWRITE_W_FAIL;
UnwPrintd2(" R%d = 0x%08x\n", r);
}
if (!P)
addr += U ? 4 : -4;
if (!P) addr += U ? 4 : -4;
}
/* Check the next register */
@ -535,8 +479,7 @@ UnwResult UnwStartArm(UnwState * const state) {
} while (r >= 0 && r <= 15);
/* Check the writeback bit */
if (W)
state->regData[baseReg].v = addr;
if (W) state->regData[baseReg].v = addr;
/* Check if the PC was loaded */
if (L && (regList & (0x01 << 15))) {
@ -547,9 +490,8 @@ UnwResult UnwStartArm(UnwState * const state) {
}
else {
/* Store the return address */
if (!UnwReportRetAddr(state, state->regData[15].v)) {
if (!UnwReportRetAddr(state, state->regData[15].v))
return UNWIND_TRUNCATED;
}
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) */
UnwMemHashGC(state);
t--;
if (t == 0)
return UNWIND_EXHAUSTED;
if (--t == 0) return UNWIND_EXHAUSTED;
} while (!found);

View file

@ -25,17 +25,11 @@
* \param value The value to sign extend.
* \return The signed-11 bit value stored in a 16bit data type.
*/
static int32_t signExtend11(uint16_t value) {
if(value & 0x400) {
value |= 0xFFFFF800;
}
return value;
static int32_t signExtend11(const uint16_t value) {
return (value & 0x400) ? value | 0xFFFFF800 : value;
}
UnwResult UnwStartThumb(UnwState * const state) {
bool found = false;
uint16_t t = UNW_MAX_INSTR_COUNT;
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;
/* 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;
}
UnwPrintd4("T %x %x %04x:", state->regData[13].v, state->regData[15].v, instr);
/* 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");
return UNWIND_INCONSISTENT;
}
/* 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");
return UNWIND_INCONSISTENT;
}
@ -73,9 +66,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
state->regData[15].v += 2;
/* 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;
}
UnwPrintd3(" %x %04x:", state->regData[15].v, instr2);
@ -84,26 +76,25 @@ UnwResult UnwStartThumb(UnwState * const state) {
* PUSH and POP
*/
if ((instr & 0xFE6F) == 0xE82D) {
bool L = (instr & 0x10) ? true : false;
bool L = !!(instr & 0x10);
uint16_t rList = instr2;
if(L) {
if (L) {
uint8_t r;
/* Load from memory: POP */
UnwPrintd1("POP {Rlist}\n");
/* Load registers from stack */
for(r = 0; r < 16; r++) {
if(rList & (0x1 << r)) {
for (r = 0; r < 16; r++) {
if (rList & (0x1 << r)) {
/* 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;
}
/* 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;
@ -114,7 +105,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
* the caller was from Thumb. This would allow return
* 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);
/* Pop into the PC will not switch mode */
@ -122,9 +113,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
}
/* Store the return address */
if(!UnwReportRetAddr(state, state->regData[15].v)) {
if (!UnwReportRetAddr(state, state->regData[15].v))
return UNWIND_TRUNCATED;
}
/* Now have the return address */
UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
@ -155,15 +145,14 @@ UnwResult UnwStartThumb(UnwState * const state) {
/* Store to memory: PUSH */
UnwPrintd1("PUSH {Rlist}");
for(r = 15; r >= 0; r--) {
if(rList & (0x1 << r)) {
for (r = 15; r >= 0; r--) {
if (rList & (0x1 << r)) {
UnwPrintd4("\n r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
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;
}
}
}
}
@ -180,9 +169,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
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;
}
}
/*
* POP register
@ -194,12 +182,11 @@ UnwResult UnwStartThumb(UnwState * const state) {
UnwPrintd2("POP {R%d}\n", r);
/* 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;
}
/* 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;
@ -210,7 +197,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
* the caller was from Thumb. This would allow return
* 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);
/* Pop into the PC will not switch mode */
@ -218,9 +205,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
}
/* Store the return address */
if(!UnwReportRetAddr(state, state->regData[15].v)) {
if (!UnwReportRetAddr(state, state->regData[15].v))
return UNWIND_TRUNCATED;
}
/* Now have the return address */
UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
@ -255,7 +241,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
* the switch clauses
*/
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" : "");
@ -263,15 +249,14 @@ UnwResult UnwStartThumb(UnwState * const state) {
if (rn == 15) {
if (H) {
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;
}
state->regData[15].v += rv * 2;
} else {
}
else {
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;
}
state->regData[15].v += rv * 2;
}
}
@ -355,12 +340,11 @@ UnwResult UnwStartThumb(UnwState * const state) {
UnwPrintd2(" Return PC=%x", state->regData[15].v);
/* Report the return address, including mode bit */
if(!UnwReportRetAddr(state, state->regData[15].v)) {
if (!UnwReportRetAddr(state, state->regData[15].v))
return UNWIND_TRUNCATED;
}
/* Determine the new mode */
if(state->regData[15].v & 0x1) {
if (state->regData[15].v & 0x1) {
/* Branching to THUMB */
/* Account for the auto-increment which isn't needed */
@ -411,10 +395,10 @@ UnwResult UnwStartThumb(UnwState * const state) {
* PC-relative load
* LDR Rd,[PC, #+/-imm]
*/
else if((instr & 0xFF7F) == 0xF85F) {
else if ((instr & 0xFF7F) == 0xF85F) {
uint8_t rt = (instr2 & 0xF000) >> 12;
uint8_t imm12 = (instr2 & 0x0FFF);
bool A = (instr & 0x80) ? true : false;
bool A = !!(instr & 0x80);
uint32_t address;
/* 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);
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
if (!UnwMemReadRegister(state, address, &state->regData[rt]))
return UNWIND_DREAD_W_FAIL;
}
}
/*
* 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 (!M_IsOriginValid(state->regData[rn].o)) {
state->regData[rt].o = state->regData[rn].o;
} else {
}
else {
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;
}
}
}
/*
@ -459,31 +442,20 @@ UnwResult UnwStartThumb(UnwState * const state) {
uint8_t rn = (instr & 0xF);
uint8_t rt = (instr2 & 0xF000) >> 12;
uint16_t imm8 = (instr2 & 0xFF);
bool P = (instr2 & 0x400) ? true : false;
bool U = (instr2 & 0x200) ? true : false;
bool W = (instr2 & 0x100) ? true : false;
bool P = !!(instr2 & 0x400);
bool U = !!(instr2 & 0x200);
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;
} else {
uint32_t offaddress = state->regData[rn].v + imm8;
if (U) offaddress += imm8;
else offaddress -= imm8;
else {
uint32_t offaddress = state->regData[rn].v + (U ? imm8 + imm8 : 0),
address = P ? offaddress : state->regData[rn].v;
uint32_t address;
if (P) {
address = offaddress;
} else {
address = state->regData[rn].v;
}
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
if (!UnwMemReadRegister(state, address, &state->regData[rt]))
return UNWIND_DREAD_W_FAIL;
}
if (W) {
state->regData[rn].v = offaddress;
}
if (W) 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
*/
else if ((instr & 0xFFF0) == 0xF850 && (instr2 & 0x0FC0) == 0x0000) {
uint8_t rn = (instr & 0xF);
uint8_t rt = (instr2 & 0xF000) >> 12;
uint8_t rm = (instr2 & 0xF);
uint8_t imm2 = (instr2 & 0x30) >> 4;
const uint8_t rn = (instr & 0xF),
rt = (instr2 & 0xF000) >> 12,
rm = (instr2 & 0xF),
imm2 = (instr2 & 0x30) >> 4;
if (!M_IsOriginValid(state->regData[rn].o) ||
!M_IsOriginValid(state->regData[rm].o)) {
if (!M_IsOriginValid(state->regData[rn].o) || !M_IsOriginValid(state->regData[rm].o)) {
/* 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() */
if (rt == 15 && M_IsOriginValid(state->regData[rn].o)) {
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;
}
} else {
/* Propagate unknown value */
}
else /* Propagate unknown value */
state->regData[rt].o = state->regData[rn].o;
}
} else {
}
else {
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;
}
}
}
else {
@ -533,14 +503,14 @@ UnwResult UnwStartThumb(UnwState * const state) {
* LSR 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;
uint8_t op = (instr & 0x1800) >> 11;
uint8_t offset5 = (instr & 0x07C0) >> 6;
uint8_t rs = (instr & 0x0038) >> 3;
uint8_t rd = (instr & 0x0007);
const uint8_t op = (instr & 0x1800) >> 11,
offset5 = (instr & 0x07C0) >> 6,
rs = (instr & 0x0038) >> 3,
rd = (instr & 0x0007);
switch(op) {
switch (op) {
case 0: /* LSL */
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;
@ -558,11 +528,9 @@ UnwResult UnwStartThumb(UnwState * const state) {
case 2: /* ASR */
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;
if(signExtend) {
state->regData[rd].v |= 0xFFFFFFFF << (32 - offset5);
}
if (signExtend) state->regData[rd].v |= 0xFFFFFFFF << (32 - offset5);
state->regData[rd].o = state->regData[rs].o;
state->regData[rd].o |= REG_VAL_ARITHMETIC;
break;
@ -574,9 +542,9 @@ UnwResult UnwStartThumb(UnwState * const state) {
* SUB Rd, Rs, Rn
* SUB Rd, Rs, #Offset3
*/
else if((instr & 0xF800) == 0x1800) {
bool I = (instr & 0x0400) ? true : false;
bool op = (instr & 0x0200) ? true : false;
else if ((instr & 0xF800) == 0x1800) {
bool I = !!(instr & 0x0400);
bool op = !!(instr & 0x0200);
uint8_t rn = (instr & 0x01C0) >> 6;
uint8_t rs = (instr & 0x0038) >> 3;
uint8_t rd = (instr & 0x0007);
@ -584,36 +552,24 @@ UnwResult UnwStartThumb(UnwState * const state) {
/* Print decoding */
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));
if(!I) {
if (!I) {
UnwPrintd3(", r%d %s", rn, M_Origin2Str(state->regData[rn].o));
/* Perform calculation */
if(op) {
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;
}
state->regData[rd].v = state->regData[rs].v + (op ? -state->regData[rn].v : state->regData[rn].v);
/* Propagate the origin */
if(M_IsOriginValid(state->regData[rs].o) &&
M_IsOriginValid(state->regData[rn].o)) {
if (M_IsOriginValid(state->regData[rs].o) && M_IsOriginValid(state->regData[rn].o)) {
state->regData[rd].o = state->regData[rs].o;
state->regData[rd].o |= REG_VAL_ARITHMETIC;
}
else {
else
state->regData[rd].o = REG_VAL_INVALID;
}
}
else {
/* Perform calculation */
if(op) {
state->regData[rd].v = state->regData[rs].v - rn;
}
else {
state->regData[rd].v = state->regData[rs].v + rn;
}
state->regData[rd].v = state->regData[rs].v + (op ? -rn : rn);
/* Propagate the origin */
state->regData[rd].o = state->regData[rs].o;
@ -626,13 +582,13 @@ UnwResult UnwStartThumb(UnwState * const state) {
* ADD Rd, #Offset8
* SUB Rd, #Offset8
*/
else if((instr & 0xE000) == 0x2000) {
else if ((instr & 0xE000) == 0x2000) {
uint8_t op = (instr & 0x1800) >> 11;
uint8_t rd = (instr & 0x0700) >> 8;
uint8_t offset8 = (instr & 0x00FF);
switch(op) {
switch (op) {
case 0: /* MOV */
UnwPrintd3("MOV r%d, #0x%x", rd, offset8);
state->regData[rd].v = offset8;
@ -675,7 +631,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
* BIC Rd, Rs
* MVN Rd, Rs
*/
else if((instr & 0xFC00) == 0x4000) {
else if ((instr & 0xFC00) == 0x4000) {
uint8_t op = (instr & 0x03C0) >> 6;
uint8_t rs = (instr & 0x0038) >> 3;
uint8_t rd = (instr & 0x0007);
@ -688,7 +644,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
"ORR", "MUL", "BIC", "MVN" };
#endif
/* Print the mnemonic and registers */
switch(op) {
switch (op) {
case 0: /* AND */
case 1: /* EOR */
case 2: /* LSL */
@ -720,7 +676,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
}
/* Perform operation */
switch(op) {
switch (op) {
case 0: /* AND */
state->regData[rd].v &= state->regData[rs].v;
break;
@ -738,7 +694,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
break;
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 |= 0xFFFFFFFF << (32 - state->regData[rs].v);
}
@ -782,7 +738,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
}
/* Propagate data origins */
switch(op) {
switch (op) {
case 0: /* AND */
case 1: /* EOR */
case 2: /* LSL */
@ -792,13 +748,12 @@ UnwResult UnwStartThumb(UnwState * const state) {
case 12: /* ORR */
case 13: /* MUL */
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 |= REG_VAL_ARITHMETIC;
}
else {
else
state->regData[rd].o = REG_VAL_INVALID;
}
break;
case 5: /* ADC */
@ -825,7 +780,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
* CMP Hd, Rs
* MOV Hd, Hs
*/
else if((instr & 0xFC00) == 0x4400) {
else if ((instr & 0xFC00) == 0x4400) {
uint8_t op = (instr & 0x0300) >> 8;
bool h1 = (instr & 0x0080) ? true: false;
bool h2 = (instr & 0x0040) ? true: false;
@ -833,12 +788,10 @@ UnwResult UnwStartThumb(UnwState * const state) {
uint8_t rhd = (instr & 0x0007);
/* Adjust the register numbers */
if(h2)
rhs += 8;
if(h1)
rhd += 8;
if (h2) rhs += 8;
if (h1) rhd += 8;
switch(op) {
switch (op) {
case 0: /* ADD */
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;
@ -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));
/* 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));
/* Report the return address, including mode bit */
if(!UnwReportRetAddr(state, state->regData[rhs].v)) {
if (!UnwReportRetAddr(state, state->regData[rhs].v))
return UNWIND_TRUNCATED;
}
/* Update the PC */
state->regData[15].v = state->regData[rhs].v;
/* Determine the new mode */
if(state->regData[rhs].v & 0x1) {
if (state->regData[rhs].v & 0x1) {
/* Branching to THUMB */
/* Account for the auto-increment which isn't needed */
state->regData[15].v -= 2;
}
else {
/* Branch to ARM */
else /* Branch to ARM */
return UnwStartArm(state);
}
}
else {
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
* LDR Rd,[PC, #imm]
*/
else if((instr & 0xF800) == 0x4800) {
else if ((instr & 0xF800) == 0x4800) {
uint8_t rd = (instr & 0x0700) >> 8;
uint8_t word8 = (instr & 0x00FF);
uint32_t address;
@ -903,19 +853,18 @@ UnwResult UnwStartThumb(UnwState * const state) {
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;
}
}
/* Format 13: add offset to Stack Pointer
* ADD sp,#+imm
* ADD sp,#-imm
*/
else if((instr & 0xFF00) == 0xB000) {
else if ((instr & 0xFF00) == 0xB000) {
uint8_t value = (instr & 0x7F) * 4;
/* Check the negative bit */
if((instr & 0x80) != 0) {
if ((instr & 0x80) != 0) {
UnwPrintd2("SUB sp,#0x%x", value);
state->regData[13].v -= value;
}
@ -930,29 +879,27 @@ UnwResult UnwStartThumb(UnwState * const state) {
* POP {Rlist}
* POP {Rlist, PC}
*/
else if((instr & 0xF600) == 0xB400) {
bool L = (instr & 0x0800) ? true : false;
bool R = (instr & 0x0100) ? true : false;
else if ((instr & 0xF600) == 0xB400) {
bool L = !!(instr & 0x0800);
bool R = !!(instr & 0x0100);
uint8_t rList = (instr & 0x00FF);
if(L) {
if (L) {
uint8_t r;
/* Load from memory: POP */
UnwPrintd2("POP {Rlist%s}\n", R ? ", PC" : "");
for(r = 0; r < 8; r++) {
if(rList & (0x1 << r)) {
for (r = 0; r < 8; r++) {
if (rList & (0x1 << r)) {
/* 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;
}
/* 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[13].v += 4;
@ -961,14 +908,13 @@ UnwResult UnwStartThumb(UnwState * const state) {
}
/* Check if the PC is to be popped */
if(R) {
if (R) {
/* 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;
}
/* 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 */
UnwPrintd1("PC popped with invalid address\n");
return UNWIND_FAILURE;
@ -978,7 +924,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
* the caller was from Thumb. This would allow return
* 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);
/* Pop into the PC will not switch mode */
@ -986,9 +932,8 @@ UnwResult UnwStartThumb(UnwState * const state) {
}
/* Store the return address */
if(!UnwReportRetAddr(state, state->regData[15].v)) {
if (!UnwReportRetAddr(state, state->regData[15].v))
return UNWIND_TRUNCATED;
}
/* Now have the return address */
UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
@ -1008,26 +953,24 @@ UnwResult UnwStartThumb(UnwState * const state) {
UnwPrintd2("PUSH {Rlist%s}", R ? ", LR" : "");
/* 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));
state->regData[13].v -= 4;
/* 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;
}
}
for(r = 7; r >= 0; r--) {
if(rList & (0x1 << r)) {
for (r = 7; r >= 0; r--) {
if (rList & (0x1 << r)) {
UnwPrintd4("\n r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
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;
}
}
}
}
@ -1037,7 +980,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
* Conditional branches
* Bcond
*/
else if((instr & 0xF000) == 0xD000) {
else if ((instr & 0xF000) == 0xD000) {
int32_t branchValue = (instr & 0xFF);
if (branchValue & 0x80) branchValue |= 0xFFFFFF00;
@ -1066,7 +1009,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
/* Format 18: unconditional branch
* B label
*/
else if((instr & 0xF800) == 0xE000) {
else if ((instr & 0xF800) == 0xE000) {
uint32_t v;
int32_t branchValue = signExtend11(instr & 0x07FF);
@ -1106,8 +1049,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
UnwPrintd1("\n");
/* Should never hit the reset vector */
if(state->regData[15].v == 0)
return UNWIND_RESET;
if (state->regData[15].v == 0) return UNWIND_RESET;
/* Check next address */
state->regData[15].v += 2;
@ -1115,11 +1057,9 @@ UnwResult UnwStartThumb(UnwState * const state) {
/* Garbage collect the memory hash (used only for the stack) */
UnwMemHashGC(state);
t--;
if(t == 0)
return UNWIND_EXHAUSTED;
if (--t == 0) return UNWIND_EXHAUSTED;
} while(!found);
} while (!found);
return UNWIND_SUCCESS;
}

View file

@ -19,7 +19,7 @@
#include "unwarmmem.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_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 {
/* 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 */
if(memData->a[s] == addr) {
return s;
}
if (memData->a[s] == addr) return s;
}
else {
/* 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 */
s++;
if(s > MEM_HASH_SIZE) {
s = 0;
}
} while(s != v);
if (s > MEM_HASH_SIZE) s = 0;
} while (s != v);
/* Search failed, hash is full and the address not stored */
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) {
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];
*tracked = M_IsIdxUsed(memData->tracked, i);
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) {
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){
/* Hash full */
return false;
if (valValid) {
memData->v[i] = val;
M_SetIdxUsed(memData->tracked, i);
}
else {
/* Store the item */
memData->a[i] = addr;
M_SetIdxUsed(memData->used, 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;
#ifdef UNW_DEBUG
memData->v[i] = 0xDEADBEEF;
#endif
M_ClrIdxUsed(memData->tracked, i);
}
return true;
}
void UnwMemHashGC(UnwState * const state) {
const uint32_t minValidAddr = state->regData[13].v;
MemData * const memData = &state->memData;
uint16_t t;
uint16_t t;
for(t = 0; t < MEM_HASH_SIZE; t++) {
if(M_IsIdxUsed(memData->used, t) && (memData->a[t] < minValidAddr)) {
for (t = 0; t < MEM_HASH_SIZE; t++) {
if (M_IsIdxUsed(memData->used, t) && (memData->a[t] < minValidAddr)) {
UnwPrintd3("MemHashGC: Free elem %d, addr 0x%08x\n", t, memData->a[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) {
if (HasUnwindTableInfo()) {
/* We have unwind information tables */
return UnwindByTableStart(frame, cb, data);
} else {
}
else {
/* We don't have unwind information tables */
UnwState state;
@ -48,12 +46,7 @@ UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data)
UnwInitState(&state, cb, data, frame->pc, frame->sp);
/* Check the Thumb bit */
if(frame->pc & 0x1) {
return UnwStartThumb(&state);
}
else {
return UnwStartArm(&state);
}
return (frame->pc & 0x1) ? UnwStartThumb(&state) : UnwStartArm(&state);
}
}
#endif

View file

@ -143,7 +143,7 @@ public:
break;
case EP_M876:
switch(c) {
switch (c) {
case ' ': break;
case 'S': state = EP_M876S; break;
default: state = EP_IGNORE; break;

View file

@ -557,7 +557,7 @@ void MMU2::toolChange(const char* special) {
set_runout_valid(false);
KEEPALIVE_STATE(IN_HANDLER);
switch(*special) {
switch (*special) {
case '?': {
uint8_t index = mmu2_chooseFilament();
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);
switch(side) {
switch (side) {
case TOP: {
const float measurement = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty);
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) {
switch(msg) {
switch (msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
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) {
switch(msg) {
switch (msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
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 is_escape = 0;
uint8_t value;
for(;;) {
for (;;) {
value = u8g_pgm_read(esc_seq);
if (is_escape == 0) {
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) {
switch(msg) {
switch (msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
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) {
switch(msg) {
switch (msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
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) {
switch(msg) {
switch (msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
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) {
switch(msg) {
switch (msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_400NS);
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];
uint32_t i, j, k;
switch(msg) {
switch (msg) {
case U8G_DEV_MSG_INIT:
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

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) {
switch(msg) {
switch (msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
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) {
switch(msg) {
switch (msg) {
case U8G_DEV_MSG_INIT:
u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
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)
uint8_t retryCnt = 3;
for(;;) {
for (;;) {
if (cardCommand(CMD17, blockNumber))
error(SD_CARD_ERROR_CMD17);
else if (readData(dst, 512))

View file

@ -35,98 +35,98 @@ static uint8_t usb_task_state;
/* constructor */
USB::USB() : bmHubPre(0) {
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
init();
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
init();
}
/* Initialize data structures */
void USB::init() {
//devConfigIndex = 0;
bmHubPre = 0;
//devConfigIndex = 0;
bmHubPre = 0;
}
uint8_t USB::getUsbTaskState(void) {
return ( usb_task_state);
return ( usb_task_state);
}
void USB::setUsbTaskState(uint8_t state) {
usb_task_state = state;
usb_task_state = state;
}
EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) {
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if(!p || !p->epinfo)
return NULL;
if (!p || !p->epinfo)
return NULL;
EpInfo *pep = p->epinfo;
EpInfo *pep = p->epinfo;
for(uint8_t i = 0; i < p->epcount; i++) {
if((pep)->epAddr == ep)
return pep;
for (uint8_t i = 0; i < p->epcount; i++) {
if ((pep)->epAddr == ep)
return pep;
pep++;
}
return NULL;
pep++;
}
return NULL;
}
/* 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 */
uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) {
if(!eprecord_ptr)
return USB_ERROR_INVALID_ARGUMENT;
if (!eprecord_ptr)
return USB_ERROR_INVALID_ARGUMENT;
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->address.devAddress = addr;
p->epinfo = eprecord_ptr;
p->epcount = epcount;
p->address.devAddress = addr;
p->epinfo = eprecord_ptr;
p->epcount = epcount;
return 0;
return 0;
}
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)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo)
return USB_ERROR_EPINFO_IS_NULL;
if (!p->epinfo)
return USB_ERROR_EPINFO_IS_NULL;
*ppep = getEpInfoEntry(addr, ep);
*ppep = getEpInfoEntry(addr, ep);
if(!*ppep)
return USB_ERROR_EP_NOT_FOUND_IN_TBL;
if (!*ppep)
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)--;
/*
USBTRACE2("\r\nAddress: ", addr);
USBTRACE2(" EP: ", ep);
USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
USBTRACE2(" NAK Limit: ", nak_limit);
USBTRACE("\r\n");
*/
regWr(rPERADDR, addr); //set peripheral address
*nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
(*nak_limit)--;
/*
USBTRACE2("\r\nAddress: ", addr);
USBTRACE2(" EP: ", ep);
USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
USBTRACE2(" NAK Limit: ", nak_limit);
USBTRACE("\r\n");
*/
regWr(rPERADDR, addr); //set peripheral address
uint8_t mode = regRd(rMODE);
uint8_t mode = regRd(rMODE);
//Serial.print("\r\nMode: ");
//Serial.println( mode, HEX);
//Serial.print("\r\nLS: ");
//Serial.println(p->lowspeed, HEX);
//Serial.print("\r\nMode: ");
//Serial.println( mode, HEX);
//Serial.print("\r\nLS: ");
//Serial.println(p->lowspeed, HEX);
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
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, */
@ -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 */
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) {
bool direction = false; //request direction, IN or OUT
uint8_t rcode;
SETUP_PKT setup_pkt;
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) {
bool direction = false; //request direction, IN or OUT
uint8_t rcode;
SETUP_PKT setup_pkt;
EpInfo *pep = NULL;
uint16_t nak_limit = 0;
EpInfo *pep = NULL;
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)
return rcode;
direction = ((bmReqType & 0x80) > 0);
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 */
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
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
return ( rcode);
while (left) {
// Bytes read into buffer
uint16_t read = nbytes;
//uint16_t read = (left<nbytes) ? left : nbytes;
if(dataptr != NULL) //data stage, if present
{
if(direction) //IN transfer
{
uint16_t left = total;
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);
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;
}
// 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. */
/* 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,
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*/) {
EpInfo *pep = NULL;
uint16_t nak_limit = 0;
EpInfo *pep = NULL;
uint16_t nak_limit = 0;
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
if(rcode) {
USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81);
USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81);
USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81);
return rcode;
}
return InTransfer(pep, nak_limit, nbytesptr, data, bInterval);
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
if (rcode) {
USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81);
USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81);
USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81);
return rcode;
}
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 rcode = 0;
uint8_t pktsize;
uint8_t rcode = 0;
uint8_t pktsize;
uint16_t nbytes = *nbytesptr;
//printf("Requesting %i bytes ", nbytes);
uint8_t maxpktsize = pep->maxPktSize;
uint16_t nbytes = *nbytesptr;
//printf("Requesting %i bytes ", nbytes);
uint8_t maxpktsize = pep->maxPktSize;
*nbytesptr = 0;
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
*nbytesptr = 0;
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
// use a 'break' to exit this loop
while(1) {
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
if(rcode == hrTOGERR) {
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmRcvToggle = (regRd(rHRSL) & bmRCVTOGRD) ? 0 : 1;
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
continue;
}
if(rcode) {
//printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
break; //should be 0, indicating ACK. Else return error code.
}
/* 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 */
if((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
//printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
rcode = 0xf0; //receive error
break;
}
pktsize = regRd(rRCVBC); //number of received bytes
//printf("Got %i bytes \r\n", pktsize);
// This would be OK, but...
//assert(pktsize <= nbytes);
if(pktsize > nbytes) {
// This can happen. Use of assert on Arduino locks up the Arduino.
// So I will trim the value, and hope for the best.
//printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
pktsize = nbytes;
}
// use a 'break' to exit this loop
for (;;) {
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
if (rcode == hrTOGERR) {
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmRcvToggle = (regRd(rHRSL) & bmRCVTOGRD) ? 0 : 1;
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
continue;
}
if (rcode) {
//printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
break; //should be 0, indicating ACK. Else return error code.
}
/* 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 */
if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
//printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
rcode = 0xF0; //receive error
break;
}
pktsize = regRd(rRCVBC); //number of received bytes
//printf("Got %i bytes \r\n", pktsize);
// This would be OK, but...
//assert(pktsize <= nbytes);
if (pktsize > nbytes) {
// This can happen. Use of assert on Arduino locks up the Arduino.
// So I will trim the value, and hope for the best.
//printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
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)
mem_left = 0;
data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
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
*nbytesptr += pktsize; // add this packet's byte count to total transfer length
/* The transfer is complete under two conditions: */
/* 1. The device sent a short packet (L.T. maxPacketSize) */
/* 2. 'nbytes' have been transferred. */
if((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes?
{
// Save toggle value
pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
//printf("\r\n");
rcode = 0;
break;
} else if(bInterval > 0)
delay(bInterval); // Delay according to polling interval
} //while( 1 )
return ( rcode);
/* The transfer is complete under two conditions: */
/* 1. The device sent a short packet (L.T. maxPacketSize) */
/* 2. 'nbytes' have been transferred. */
if (pktsize < maxpktsize || *nbytesptr >= nbytes) { // Transferred 'nbytes' bytes?
// Save toggle value
pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
//printf("\r\n");
rcode = 0;
break;
}
else if (bInterval > 0)
delay(bInterval); // Delay according to polling interval
}
return rcode;
}
/* 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 */
uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
EpInfo *pep = NULL;
uint16_t nak_limit = 0;
EpInfo *pep = NULL;
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 rcode;
return OutTransfer(pep, nak_limit, nbytes, data);
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 rcode = hrSUCCESS, retry_count;
uint8_t *data_p = data; //local copy of the data pointer
uint16_t bytes_tosend, nak_count;
uint16_t bytes_left = nbytes;
uint8_t rcode = hrSUCCESS, retry_count;
uint8_t *data_p = data; //local copy of the data pointer
uint16_t bytes_tosend, nak_count;
uint16_t bytes_left = nbytes;
uint8_t maxpktsize = pep->maxPktSize;
uint8_t maxpktsize = pep->maxPktSize;
if(maxpktsize < 1 || maxpktsize > 64)
return USB_ERROR_INVALID_MAX_PKT_SIZE;
if (maxpktsize < 1 || maxpktsize > 64)
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) {
retry_count = 0;
nak_count = 0;
bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
regWr(rSNDBC, bytes_tosend); //set number of bytes
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
rcode = (regRd(rHRSL) & 0x0f);
while (bytes_left) {
retry_count = 0;
nak_count = 0;
bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
regWr(rSNDBC, bytes_tosend); //set number of bytes
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
rcode = (regRd(rHRSL) & 0x0F);
while(rcode && ((int32_t)((uint32_t)millis() - timeout) < 0L)) {
switch(rcode) {
case hrNAK:
nak_count++;
if(nak_limit && (nak_count == nak_limit))
goto breakout;
//return ( rcode);
break;
case hrTIMEOUT:
retry_count++;
if(retry_count == USB_RETRY_LIMIT)
goto breakout;
//return ( rcode);
break;
case hrTOGERR:
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
break;
default:
goto breakout;
}//switch( rcode
while (rcode && ((int32_t)((uint32_t)millis() - timeout) < 0L)) {
switch (rcode) {
case hrNAK:
nak_count++;
if (nak_limit && (nak_count == nak_limit))
goto breakout;
//return ( rcode);
break;
case hrTIMEOUT:
retry_count++;
if (retry_count == USB_RETRY_LIMIT)
goto breakout;
//return ( rcode);
break;
case hrTOGERR:
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
break;
default:
goto breakout;
}
/* process NAK according to Host out NAK bug */
regWr(rSNDBC, 0);
regWr(rSNDFIFO, *data_p);
regWr(rSNDBC, bytes_tosend);
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
rcode = (regRd(rHRSL) & 0x0f);
}//while( rcode && ....
bytes_left -= bytes_tosend;
data_p += bytes_tosend;
}//while( bytes_left...
/* process NAK according to Host out NAK bug */
regWr(rSNDBC, 0);
regWr(rSNDFIFO, *data_p);
regWr(rSNDBC, bytes_tosend);
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
rcode = (regRd(rHRSL) & 0x0F);
} // while rcode && ....
bytes_left -= bytes_tosend;
data_p += bytes_tosend;
} // while bytes_left...
breakout:
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
return ( rcode); //should be 0 in all cases
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
return ( rcode); //should be 0 in all cases
}
/* 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_limit == 0, do not count NAKs, exit after timeout */
/* 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) {
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
uint8_t tmpdata;
uint8_t rcode = hrSUCCESS;
uint8_t retry_count = 0;
uint16_t nak_count = 0;
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
uint8_t tmpdata;
uint8_t rcode = hrSUCCESS;
uint8_t retry_count = 0;
uint16_t nak_count = 0;
while((int32_t)((uint32_t)millis() - timeout) < 0L) {
#if defined(ESP8266) || defined(ESP32)
yield(); // needed in order to reset the watchdog timer on the ESP8266
#endif
regWr(rHXFR, (token | ep)); //launch the transfer
rcode = USB_ERROR_TRANSFER_TIMEOUT;
while ((int32_t)((uint32_t)millis() - timeout) < 0L) {
#if defined(ESP8266) || defined(ESP32)
yield(); // needed in order to reset the watchdog timer on the ESP8266
#endif
regWr(rHXFR, (token | ep)); //launch the transfer
rcode = USB_ERROR_TRANSFER_TIMEOUT;
while((int32_t)((uint32_t)millis() - timeout) < 0L) //wait for transfer completion
{
#if defined(ESP8266) || defined(ESP32)
yield(); // needed in order to reset the watchdog timer on the ESP8266
#endif
tmpdata = regRd(rHIRQ);
while ((int32_t)((uint32_t)millis() - timeout) < 0L) { //wait for transfer completion
#if defined(ESP8266) || defined(ESP32)
yield(); // needed to reset the watchdog timer on the ESP8266
#endif
tmpdata = regRd(rHIRQ);
if(tmpdata & bmHXFRDNIRQ) {
regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
rcode = 0x00;
break;
}//if( tmpdata & bmHXFRDNIRQ
if (tmpdata & bmHXFRDNIRQ) {
regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
rcode = 0x00;
break;
}
}//while ( millis() < timeout
} // while millis() < timeout
//if (rcode != 0x00) //exit if timeout
// return ( rcode);
//if (rcode != 0x00) //exit if timeout
// return ( rcode);
rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
rcode = (regRd(rHRSL) & 0x0F); //analyze transfer result
switch(rcode) {
case hrNAK:
nak_count++;
if(nak_limit && (nak_count == nak_limit))
return (rcode);
break;
case hrTIMEOUT:
retry_count++;
if(retry_count == USB_RETRY_LIMIT)
return (rcode);
break;
default:
return (rcode);
}//switch( rcode
switch (rcode) {
case hrNAK:
nak_count++;
if (nak_limit && (nak_count == nak_limit))
return (rcode);
break;
case hrTIMEOUT:
retry_count++;
if (retry_count == USB_RETRY_LIMIT)
return (rcode);
break;
default:
return (rcode);
}
}//while( timeout > millis()
return ( rcode);
} // while timeout > millis()
return rcode;
}
/* USB main task. Performs enumeration/cleanup */
void USB::Task(void) //USB state machine
{
uint8_t rcode;
uint8_t tmpdata;
static uint32_t delay = 0;
//USB_DEVICE_DESCRIPTOR buf;
bool lowspeed = false;
void USB::Task(void) { //USB state machine
uint8_t rcode;
uint8_t tmpdata;
static uint32_t delay = 0;
//USB_DEVICE_DESCRIPTOR buf;
bool lowspeed = false;
MAX3421E::Task();
MAX3421E::Task();
tmpdata = getVbusState();
tmpdata = getVbusState();
/* modify USB task state if Vbus changed */
switch(tmpdata) {
case SE1: //illegal state
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
lowspeed = false;
break;
case SE0: //disconnected
if((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
lowspeed = false;
break;
case LSHOST:
/* modify USB task state if Vbus changed */
switch (tmpdata) {
case SE1: //illegal state
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
lowspeed = false;
break;
case SE0: //disconnected
if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
lowspeed = false;
break;
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;
//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;
}// switch( tmpdata
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
if (devConfig[i]) rcode = devConfig[i]->Poll();
for(uint8_t i = 0; i < USB_NUMDEVICES; i++)
if(devConfig[i])
rcode = devConfig[i]->Poll();
switch (usb_task_state) {
case USB_DETACHED_SUBSTATE_INITIALIZE:
init();
switch(usb_task_state) {
case USB_DETACHED_SUBSTATE_INITIALIZE:
init();
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
if (devConfig[i])
rcode = devConfig[i]->Release();
for(uint8_t i = 0; i < USB_NUMDEVICES; i++)
if(devConfig[i])
rcode = devConfig[i]->Release();
usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
break;
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;
break;
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: ");
//Serial.println(lowspeed, HEX);
//Serial.print("\r\nConf.LS: ");
//Serial.println(lowspeed, HEX);
rcode = Configuring(0, 0, lowspeed);
rcode = Configuring(0, 0, lowspeed);
if(rcode) {
if(rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
usb_error = rcode;
usb_task_state = USB_STATE_ERROR;
}
} else
usb_task_state = USB_STATE_RUNNING;
break;
case USB_STATE_RUNNING:
break;
case USB_STATE_ERROR:
//MAX3421E::Init();
break;
} // switch( usb_task_state )
if (!rcode)
usb_task_state = USB_STATE_RUNNING;
else if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
usb_error = rcode;
usb_task_state = USB_STATE_ERROR;
}
break;
case USB_STATE_RUNNING:
break;
case USB_STATE_ERROR:
//MAX3421E::Init();
break;
}
}
uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
//uint8_t buf[12];
uint8_t rcode;
UsbDevice *p0 = NULL, *p = NULL;
//uint8_t buf[12];
uint8_t rcode;
UsbDevice *p0 = NULL, *p = NULL;
// Get pointer to pseudo device with address 0 assigned
p0 = addrPool.GetUsbDevicePtr(0);
// Get pointer to pseudo device with address 0 assigned
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)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p0->lowspeed = lowspeed;
if(!p0->epinfo)
return USB_ERROR_EPINFO_IS_NULL;
// Allocate new address according to device class
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
uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
p->lowspeed = lowspeed;
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
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;
// Assign new address to the device
rcode = setAddr(0, 0, bAddress);
if (rcode) {
addrPool.FreeAddress(bAddress);
bAddress = 0;
}
return rcode;
}
/*
* This is broken. We need to enumerate differently.
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;
}
/**
* This is broken. It needs to enumerate differently.
* 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.
* i.e.(delays are not indicated for brevity):
* 1. reset
@ -649,7 +623,7 @@ again:
* 4: set address
* 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
* 6: while (configurations) {
* for(each configuration) {
* for (each configuration) {
* for (each driver) {
* 6a: Ask device if it likes configuration. Returns 0 on OK.
* 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
* 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 bAddress = 0;
//printf("Configuring: parent = %i, port = %i\r\n", parent, port);
uint8_t devConfigIndex;
uint8_t rcode = 0;
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
USB_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR *>(buf);
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
EpInfo epInfo;
//uint8_t bAddress = 0;
//printf("Configuring: parent = %i, port = %i\r\n", parent, port);
uint8_t devConfigIndex;
uint8_t rcode = 0;
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
USB_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR *>(buf);
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
EpInfo epInfo;
epInfo.epAddr = 0;
epInfo.maxPktSize = 8;
epInfo.bmSndToggle = 0;
epInfo.bmRcvToggle = 0;
epInfo.bmNakPower = USB_NAK_MAX_POWER;
epInfo.epAddr = 0;
epInfo.maxPktSize = 8;
epInfo.bmSndToggle = 0;
epInfo.bmRcvToggle = 0;
epInfo.bmNakPower = USB_NAK_MAX_POWER;
//delay(2000);
AddressPool &addrPool = GetAddressPool();
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p) {
//printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
//delay(2000);
AddressPool &addrPool = GetAddressPool();
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if (!p) {
//printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to
// avoid toggle inconsistence
// Temporary assign new pointer to epInfo to p->epinfo in order to
// avoid toggle inconsistence
p->epinfo = &epInfo;
p->epinfo = &epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
p->lowspeed = lowspeed;
// Get device descriptor
rcode = getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode) {
//printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n");
return rcode;
}
if (rcode) {
//printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n");
return rcode;
}
// to-do?
// Allocate new address according to device class
//bAddress = addrPool.AllocAddress(parent, false, port);
// to-do?
// Allocate new address according to device class
//bAddress = addrPool.AllocAddress(parent, false, port);
uint16_t vid = udd->idVendor;
uint16_t pid = udd->idProduct;
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;
}
}
uint16_t vid = udd->idVendor, pid = udd->idProduct;
uint8_t klass = udd->bDeviceClass, subklass = udd->bDeviceSubClass;
if(devConfigIndex < USB_NUMDEVICES) {
return rcode;
}
// 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) return rcode;
// blindly attempt to configure
for(devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
if(!devConfig[devConfigIndex]) continue;
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
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
// blindly attempt to configure
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
if (!devConfig[devConfigIndex]) continue;
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
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
//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)) {
// in case of an error dev_index should be reset to 0
// in order to start from the very beginning the
// next time the program gets here
//if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
// devConfigIndex = 0;
return rcode;
}
}
// if we get here that means that the device class is not supported by any of registered classes
rcode = DefaultAddressing(parent, port, lowspeed);
return 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)) {
// in case of an error dev_index should be reset to 0
// in order to start from the very beginning the
// next time the program gets here
//if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
// devConfigIndex = 0;
return rcode;
}
}
// Arriving here means the device class is unsupported by registered classes
return DefaultAddressing(parent, port, lowspeed);
}
uint8_t USB::ReleaseDevice(uint8_t addr) {
if(!addr)
return 0;
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if(!devConfig[i]) continue;
if(devConfig[i]->GetAddress() == addr)
return devConfig[i]->Release();
}
return 0;
if (addr) {
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if (!devConfig[i]) continue;
if (devConfig[i]->GetAddress() == addr)
return devConfig[i]->Release();
}
}
return 0;
}
#if 1 //!defined(USB_METHODS_INLINE)
//get device descriptor
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
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
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) {
const uint8_t bufSize = 64;
uint8_t buf[bufSize];
USB_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR *>(buf);
const uint8_t bufSize = 64;
uint8_t buf[bufSize];
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)
return ret;
uint16_t total = ucd->wTotalLength;
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
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
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);
//delay(2); //per USB 2.0 sect.9.2.6.3
delay(300); // Older spec says you should wait at least 200ms
return rcode;
//return ( 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(300); // Older spec says you should wait at least 200ms
return rcode;
//return ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL);
}
//set configuration
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)

View file

@ -22,8 +22,9 @@
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
/* USB functions */
#ifndef _usb_h_
#define _usb_h_
#include "../../../inc/MarlinConfigPre.h"
@ -50,4 +51,4 @@
#include "parsetools.h"
#include "confdescparser.h"
#endif //_usb_h_
#undef _usb_h_

View file

@ -231,8 +231,8 @@ public:
};
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if(!devConfig[i]) {
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if (!devConfig[i]) {
devConfig[i] = pdev;
return 0;
}

View file

@ -22,13 +22,11 @@
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#if !defined(_usb_h_) || defined(__ADDRESS_H__)
#error "Never include address.h directly; include Usb.h instead"
#else
#define __ADDRESS_H__
#ifndef _usb_h_
#error "Never include address.h directly; include Usb.h instead"
#endif
/* 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) */
@ -38,18 +36,18 @@
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
struct EpInfo {
uint8_t epAddr; // Endpoint address
uint8_t maxPktSize; // Maximum packet size
uint8_t epAddr; // Endpoint address
uint8_t maxPktSize; // Maximum packet size
union {
uint8_t epAttribs;
union {
uint8_t epAttribs;
struct {
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
} __attribute__((packed));
};
struct {
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
} __attribute__((packed));
};
} __attribute__((packed));
// 7 6 5 4 3 2 1 0
@ -63,17 +61,15 @@ struct EpInfo {
//
struct UsbDeviceAddress {
union {
struct {
uint8_t bmAddress : 3; // device address/port number
uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zero
} __attribute__((packed));
uint8_t devAddress;
};
union {
struct {
uint8_t bmAddress : 3; // device address/port number
uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zero
} __attribute__((packed));
uint8_t devAddress;
};
} __attribute__((packed));
#define bmUSB_DEV_ADDR_ADDRESS 0x07
@ -81,18 +77,18 @@ struct UsbDeviceAddress {
#define bmUSB_DEV_ADDR_HUB 0x40
struct UsbDevice {
EpInfo *epinfo; // endpoint info pointer
UsbDeviceAddress address;
uint8_t epcount; // number of endpoints
bool lowspeed; // indicates if a device is the low speed one
// uint8_t devclass; // device class
EpInfo *epinfo; // endpoint info pointer
UsbDeviceAddress address;
uint8_t epcount; // number of endpoints
bool lowspeed; // indicates if a device is the low speed one
// uint8_t devclass; // device class
} __attribute__((packed));
class AddressPool {
public:
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
virtual void FreeAddress(uint8_t addr) = 0;
public:
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
virtual void FreeAddress(uint8_t addr) = 0;
};
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
@ -102,190 +98,174 @@ typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
template <const uint8_t MAX_DEVICES_ALLOWED>
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
// in order to avoid hub address duplication
uint8_t hubCounter; // hub counter is kept
// 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) {
thePool[index].address.devAddress = 0;
thePool[index].epcount = 1;
thePool[index].lowspeed = 0;
thePool[index].epinfo = &dev0ep;
};
void InitEntry(uint8_t index) {
thePool[index].address.devAddress = 0;
thePool[index].epcount = 1;
thePool[index].lowspeed = 0;
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) {
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
if(thePool[i].address.devAddress == address)
return i;
}
return 0;
};
uint8_t FindAddressIndex(uint8_t address = 0) {
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
if (thePool[i].address.devAddress == address)
return i;
// Returns thePool child index for a given parent
return 0;
}
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;
};
// Return thePool child index for a given parent
// 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) {
// Zero field is reserved and should not be affected
if(index == 0)
return;
// Frees address entry specified by index parameter
UsbDeviceAddress uda = thePool[index].address;
// If a hub was switched off all port addresses should be freed
if(uda.bmHub == 1) {
for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
FreeAddressByIndex(i);
void FreeAddressByIndex(uint8_t index) {
// Zero field is reserved and should not be affected
if (index == 0) return;
// If the hub had the last allocated address, hubCounter should be decremented
if(hubCounter == uda.bmAddress)
hubCounter--;
}
InitEntry(index);
}
UsbDeviceAddress uda = thePool[index].address;
// If a hub was switched off all port addresses should be freed
if (uda.bmHub == 1) {
for (uint8_t i = 1; (i = FindChildIndex(uda, i));)
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() {
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
// Initialize the whole address pool at once
hubCounter = 0;
};
void InitAllAddresses() {
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
hubCounter = 0;
}
public:
AddressPoolImpl() : hubCounter(0) {
// Zero address is reserved
InitEntry(0);
AddressPoolImpl() : hubCounter(0) {
// Zero address is reserved
InitEntry(0);
thePool[0].address.devAddress = 0;
thePool[0].epinfo = &dev0ep;
dev0ep.epAddr = 0;
dev0ep.maxPktSize = 8;
dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
dev0ep.bmRcvToggle = 0;
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
thePool[0].address.devAddress = 0;
thePool[0].epinfo = &dev0ep;
dev0ep.epAddr = 0;
dev0ep.maxPktSize = 8;
dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
dev0ep.bmRcvToggle = 0;
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) {
if(!addr)
return thePool;
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
if (!addr) 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) {
if(!pfunc)
return;
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
/* 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;
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
if(thePool[i].address.devAddress)
pfunc(thePool + i);
};
if (is_hub && hubCounter == 7) return 0;
// 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 (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 (!index) return 0; // if empty entry is not found
if(is_hub && hubCounter == 7)
return 0;
if (_parent.devAddress == 0) {
if (is_hub) {
thePool[index].address.devAddress = 0x41;
hubCounter++;
}
else
thePool[index].address.devAddress = 1;
// finds first empty address entry starting from one
uint8_t index = FindAddressIndex(0);
return thePool[index].address.devAddress;
}
if(!index) // if empty entry is not found
return 0;
UsbDeviceAddress addr;
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) {
if(is_hub) {
thePool[index].address.devAddress = 0x41;
hubCounter++;
} else
thePool[index].address.devAddress = 1;
// Empty the pool entry
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;
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;
};
// 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;
//};
// Return number of hubs attached
// It can be helpful to find out if hubs are attached when 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
* e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__CONFDESCPARSER_H__)
#error "Never include confdescparser.h directly; include Usb.h instead"
#else
#pragma once
#define __CONFDESCPARSER_H__
#ifndef _usb_h_
#error "Never include confdescparser.h directly; include Usb.h instead"
#endif
class UsbConfigXtracter {
public:
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
//virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 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_SUBCLASS 2
#define CP_MASK_COMPARE_PROTOCOL 4
#define CP_MASK_COMPARE_ALL 7
#define CP_MASK_COMPARE_CLASS 1
#define CP_MASK_COMPARE_SUBCLASS 2
#define CP_MASK_COMPARE_PROTOCOL 4
#define CP_MASK_COMPARE_ALL 7
// 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>
class ConfigDescParser : public USBReadParser {
UsbConfigXtracter *theXtractor;
MultiValueBuffer theBuffer;
MultiByteValueParser valParser;
ByteSkipper theSkipper;
uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
UsbConfigXtracter *theXtractor;
MultiValueBuffer theBuffer;
MultiByteValueParser valParser;
ByteSkipper theSkipper;
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 dscrType; // Descriptor type
uint8_t dscrLen; // Descriptor length
uint8_t dscrType; // Descriptor type
bool isGoodInterface; // Apropriate interface flag
uint8_t confValue; // Configuration value
uint8_t protoValue; // Protocol value
uint8_t ifaceNumber; // Interface number
uint8_t ifaceAltSet; // Interface alternate settings
bool isGoodInterface; // Apropriate interface flag
uint8_t confValue; // Configuration value
uint8_t protoValue; // Protocol value
uint8_t ifaceNumber; // Interface number
uint8_t ifaceAltSet; // Interface alternate settings
bool UseOr;
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
bool UseOr;
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
public:
void SetOR(void) {
UseOr = true;
}
ConfigDescParser(UsbConfigXtracter *xtractor);
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
void SetOR(void) { UseOr = true; }
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>
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
theXtractor(xtractor),
stateParseDescr(0),
dscrLen(0),
dscrType(0),
UseOr(false) {
theBuffer.pValue = varBuffer;
valParser.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
};
theXtractor(xtractor),
stateParseDescr(0),
dscrLen(0),
dscrType(0),
UseOr(false) {
theBuffer.pValue = varBuffer;
valParser.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>
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;
uint8_t *p = (uint8_t*)pbuf;
while(cntdn)
if(!ParseDescriptor(&p, &cntdn))
return;
uint16_t cntdn = (uint16_t)len;
uint8_t *p = (uint8_t*)pbuf;
while (cntdn) if (!ParseDescriptor(&p, &cntdn)) return;
}
/* 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 */
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) {
USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
switch(stateParseDescr) {
case 0:
theBuffer.valueSize = 2;
valParser.Initialize(&theBuffer);
stateParseDescr = 1;
case 1:
if(!valParser.Parse(pp, pcntdn))
return false;
dscrLen = *((uint8_t*)theBuffer.pValue);
dscrType = *((uint8_t*)theBuffer.pValue + 1);
stateParseDescr = 2;
case 2:
// 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
// to be read right after the size and the type fields.
// This should be used carefully. varBuffer should be used directly to handle data
// in the buffer.
theBuffer.pValue = varBuffer + 2;
stateParseDescr = 3;
case 3:
switch(dscrType) {
case USB_DESCRIPTOR_INTERFACE:
isGoodInterface = false;
break;
case USB_DESCRIPTOR_CONFIGURATION:
case USB_DESCRIPTOR_ENDPOINT:
case HID_DESCRIPTOR_HID:
break;
}
theBuffer.valueSize = dscrLen - 2;
valParser.Initialize(&theBuffer);
stateParseDescr = 4;
case 4:
switch(dscrType) {
case USB_DESCRIPTOR_CONFIGURATION:
if(!valParser.Parse(pp, pcntdn))
return false;
confValue = ucd->bConfigurationValue;
break;
case USB_DESCRIPTOR_INTERFACE:
if(!valParser.Parse(pp, pcntdn))
return false;
if((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
break;
if((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
break;
if(UseOr) {
if((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol)))
break;
} else {
if((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
break;
}
isGoodInterface = true;
ifaceNumber = uid->bInterfaceNumber;
ifaceAltSet = uid->bAlternateSetting;
protoValue = uid->bInterfaceProtocol;
break;
case USB_DESCRIPTOR_ENDPOINT:
if(!valParser.Parse(pp, pcntdn))
return false;
if(isGoodInterface)
if(theXtractor)
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
break;
//case HID_DESCRIPTOR_HID:
// if (!valParser.Parse(pp, pcntdn))
// return false;
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
// break;
default:
if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
return false;
}
theBuffer.pValue = varBuffer;
stateParseDescr = 0;
}
return true;
USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
switch (stateParseDescr) {
case 0:
theBuffer.valueSize = 2;
valParser.Initialize(&theBuffer);
stateParseDescr = 1;
case 1:
if (!valParser.Parse(pp, pcntdn)) return false;
dscrLen = *((uint8_t*)theBuffer.pValue);
dscrType = *((uint8_t*)theBuffer.pValue + 1);
stateParseDescr = 2;
case 2:
// 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
// to be read right after the size and the type fields.
// This should be used carefully. varBuffer should be used directly to handle data
// in the buffer.
theBuffer.pValue = varBuffer + 2;
stateParseDescr = 3;
case 3:
switch (dscrType) {
case USB_DESCRIPTOR_INTERFACE:
isGoodInterface = false;
break;
case USB_DESCRIPTOR_CONFIGURATION:
case USB_DESCRIPTOR_ENDPOINT:
case HID_DESCRIPTOR_HID:
break;
}
theBuffer.valueSize = dscrLen - 2;
valParser.Initialize(&theBuffer);
stateParseDescr = 4;
case 4:
switch (dscrType) {
case USB_DESCRIPTOR_CONFIGURATION:
if (!valParser.Parse(pp, pcntdn)) return false;
confValue = ucd->bConfigurationValue;
break;
case USB_DESCRIPTOR_INTERFACE:
if (!valParser.Parse(pp, pcntdn)) return false;
if ((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
break;
if ((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
break;
if (UseOr) {
if ((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol))) break;
}
else if ((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
break;
isGoodInterface = true;
ifaceNumber = uid->bInterfaceNumber;
ifaceAltSet = uid->bAlternateSetting;
protoValue = uid->bInterfaceProtocol;
break;
case USB_DESCRIPTOR_ENDPOINT:
if (!valParser.Parse(pp, pcntdn)) return false;
if (isGoodInterface && theXtractor)
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
break;
//case HID_DESCRIPTOR_HID:
// if (!valParser.Parse(pp, pcntdn)) return false;
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
// 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>
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("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
for(uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
for (uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
}
Notify(PSTR("\r\n"), 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
}
Notify(PSTR("\r\n"), 0x80);
}
#endif // __CONFDESCPARSER_H__

View file

@ -22,49 +22,47 @@
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#if !defined(_usb_h_) || defined(__HEXDUMP_H__)
#error "Never include hexdump.h directly; include Usb.h instead"
#else
#define __HEXDUMP_H__
#ifndef _usb_h_
#error "Never include hexdump.h directly; include Usb.h instead"
#endif
extern int UsbDEBUGlvl;
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
class HexDumper : public BASE_CLASS {
uint8_t byteCount;
OFFSET_TYPE byteTotal;
uint8_t byteCount;
OFFSET_TYPE byteTotal;
public:
HexDumper() : byteCount(0), byteTotal(0) {
};
HexDumper() : byteCount(0), byteTotal(0) {
};
void Initialize() {
byteCount = 0;
byteTotal = 0;
};
void Initialize() {
byteCount = 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>
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.
for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
if(!byteCount) {
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
E_Notify(PSTR(": "), 0x80);
}
PrintHex<uint8_t > (pbuf[j], 0x80);
E_Notify(PSTR(" "), 0x80);
if (UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
for (LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
if (!byteCount) {
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
E_Notify(PSTR(": "), 0x80);
}
PrintHex<uint8_t > (pbuf[j], 0x80);
E_Notify(PSTR(" "), 0x80);
if(byteCount == 15) {
E_Notify(PSTR("\r\n"), 0x80);
byteCount = 0xFF;
}
}
}
if (byteCount == 15) {
E_Notify(PSTR("\r\n"), 0x80);
byteCount = 0xFF;
}
}
}
}
#endif // __HEXDUMP_H__

View file

@ -22,13 +22,12 @@
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#ifndef _usb_h_
#error "Never include macros.h directly; include Usb.h instead"
#endif
#pragma once
////////////////////////////////////////////////////////////////////////////////
// HANDY MACROS
////////////////////////////////////////////////////////////////////////////////
@ -36,7 +35,7 @@
#define VALUE_BETWEEN(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_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)))
#ifndef __BYTE_GRABBING_DEFINED__

View file

@ -44,9 +44,7 @@ const uint8_t BulkOnly::epInterruptInIndex = 3;
* @return media capacity
*/
uint32_t BulkOnly::GetCapacity(uint8_t lun) {
if(LUNOk[lun])
return CurrentCapacity[lun];
return 0LU;
return LUNOk[lun] ? CurrentCapacity[lun] : 0UL;
}
/**
@ -56,9 +54,7 @@ uint32_t BulkOnly::GetCapacity(uint8_t lun) {
* @return media sector size
*/
uint16_t BulkOnly::GetSectorSize(uint8_t lun) {
if(LUNOk[lun])
return CurrentSectorSize[lun];
return 0U;
return LUNOk[lun] ? CurrentSectorSize[lun] : 0U;
}
/**
@ -67,9 +63,7 @@ uint16_t BulkOnly::GetSectorSize(uint8_t lun) {
* @param lun Logical Unit Number
* @return true if LUN is ready for use
*/
bool BulkOnly::LUNIsGood(uint8_t lun) {
return LUNOk[lun];
}
bool BulkOnly::LUNIsGood(uint8_t lun) { return LUNOk[lun]; }
/**
* Test if LUN is write protected
@ -77,9 +71,7 @@ bool BulkOnly::LUNIsGood(uint8_t lun) {
* @param lun Logical Unit Number
* @return cached status of write protect switch
*/
bool BulkOnly::WriteProtected(uint8_t lun) {
return WriteOk[lun];
}
bool BulkOnly::WriteProtected(uint8_t lun) { return WriteOk[lun]; }
/**
* Wrap and execute a SCSI CDB with length of 6
@ -91,10 +83,10 @@ bool BulkOnly::WriteProtected(uint8_t lun) {
* @return
*/
uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
// promote buf_size to 32bits.
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
//SetCurLUN(cdb->LUN);
return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
// promote buf_size to 32bits.
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
//SetCurLUN(cdb->LUN);
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
*/
uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
// promote buf_size to 32bits.
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
//SetCurLUN(cdb->LUN);
return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
// promote buf_size to 32bits.
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
//SetCurLUN(cdb->LUN);
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
*/
uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) {
Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
Notify(PSTR("---------\r\n"), 0x80);
Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
Notify(PSTR("---------\r\n"), 0x80);
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);
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);
}
/**
@ -138,17 +130,18 @@ uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) {
* @return 0 on success
*/
uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
Notify(PSTR("-----------------\r\n"), 0x80);
Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
Notify(PSTR("-----------------\r\n"), 0x80);
uint8_t rcode = MASS_ERR_UNIT_NOT_READY;
if(bAddress) {
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);
} else {
SetCurLUN(lun);
}
return rcode;
uint8_t rcode = MASS_ERR_UNIT_NOT_READY;
if (bAddress) {
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);
}
else
SetCurLUN(lun);
return rcode;
}
/**
@ -162,27 +155,27 @@ uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
* @return 0 on success
*/
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;
Notify(PSTR("\r\nRead LUN:\t"), 0x80);
D_PrintHex<uint8_t > (lun, 0x90);
Notify(PSTR("\r\nLBA:\t\t"), 0x90);
D_PrintHex<uint32_t > (addr, 0x90);
Notify(PSTR("\r\nblocks:\t\t"), 0x90);
D_PrintHex<uint8_t > (blocks, 0x90);
Notify(PSTR("\r\nblock size:\t"), 0x90);
D_PrintHex<uint16_t > (bsize, 0x90);
Notify(PSTR("\r\n---------\r\n"), 0x80);
CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr);
if (!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
Notify(PSTR("\r\nRead LUN:\t"), 0x80);
D_PrintHex<uint8_t> (lun, 0x90);
Notify(PSTR("\r\nLBA:\t\t"), 0x90);
D_PrintHex<uint32_t> (addr, 0x90);
Notify(PSTR("\r\nblocks:\t\t"), 0x90);
D_PrintHex<uint8_t> (blocks, 0x90);
Notify(PSTR("\r\nblock size:\t"), 0x90);
D_PrintHex<uint16_t> (bsize, 0x90);
Notify(PSTR("\r\n---------\r\n"), 0x80);
CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr);
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) {
MediaCTL(lun, 1);
delay(150);
if(!TestUnitReady(lun)) goto again;
}
return er;
if (er == MASS_ERR_STALL) {
MediaCTL(lun, 1);
delay(150);
if (!TestUnitReady(lun)) goto again;
}
return er;
}
/**
@ -196,28 +189,28 @@ again:
* @return 0 on success
*/
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(!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED;
Notify(PSTR("\r\nWrite LUN:\t"), 0x80);
D_PrintHex<uint8_t > (lun, 0x90);
Notify(PSTR("\r\nLBA:\t\t"), 0x90);
D_PrintHex<uint32_t > (addr, 0x90);
Notify(PSTR("\r\nblocks:\t\t"), 0x90);
D_PrintHex<uint8_t > (blocks, 0x90);
Notify(PSTR("\r\nblock size:\t"), 0x90);
D_PrintHex<uint16_t > (bsize, 0x90);
Notify(PSTR("\r\n---------\r\n"), 0x80);
CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr);
if (!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
if (!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED;
Notify(PSTR("\r\nWrite LUN:\t"), 0x80);
D_PrintHex<uint8_t> (lun, 0x90);
Notify(PSTR("\r\nLBA:\t\t"), 0x90);
D_PrintHex<uint32_t> (addr, 0x90);
Notify(PSTR("\r\nblocks:\t\t"), 0x90);
D_PrintHex<uint8_t> (blocks, 0x90);
Notify(PSTR("\r\nblock size:\t"), 0x90);
D_PrintHex<uint16_t> (bsize, 0x90);
Notify(PSTR("\r\n---------\r\n"), 0x80);
CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr);
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) {
MediaCTL(lun, 1);
delay(150);
if(!TestUnitReady(lun)) goto again;
}
return er;
if (er == MASS_ERR_WRITE_STALL) {
MediaCTL(lun, 1);
delay(150);
if (!TestUnitReady(lun)) goto again;
}
return er;
}
// End of user functions, the remaining code below is driver internals.
@ -236,10 +229,9 @@ qNextPollTime(0),
bPollEnable(false),
//dCBWTag(0),
bLastUsbError(0) {
ClearAllEP();
dCBWTag = 0;
if(pUsb)
pUsb->RegisterDeviceClass(this);
ClearAllEP();
dCBWTag = 0;
if (pUsb) pUsb->RegisterDeviceClass(this);
}
/**
@ -258,71 +250,66 @@ bLastUsbError(0) {
*/
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];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
USBTRACE("MS ConfigureDevice\r\n");
ClearAllEP();
AddressPool &addrPool = pUsb->GetAddressPool();
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
USBTRACE("MS ConfigureDevice\r\n");
ClearAllEP();
AddressPool &addrPool = pUsb->GetAddressPool();
if (bAddress) return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// <TECHNICAL>
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if (!p) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
// <TECHNICAL>
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p) {
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
// Restore p->epinfo
p->epinfo = oldep_ptr;
if (rcode) goto FailGetDevDescr;
if(rcode) {
goto FailGetDevDescr;
}
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
if (!bAddress) return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Steal and abuse from epInfo structure to save on memory.
epInfo[1].epAddr = udd->bNumConfigurations;
// </TECHNICAL>
return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Steal and abuse from epInfo structure to save on memory.
epInfo[1].epAddr = udd->bNumConfigurations;
// </TECHNICAL>
return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr(rcode);
#endif
rcode = USB_ERROR_FailGetDevDescr;
Release();
return rcode;
};
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr(rcode);
#endif
rcode = USB_ERROR_FailGetDevDescr;
Release();
return rcode;
}
/**
* @param parent (not used)
@ -331,211 +318,206 @@ FailGetDevDescr:
* @return 0 for success
*/
uint8_t BulkOnly::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
uint8_t rcode;
uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations
epInfo[1].epAddr = 0;
USBTRACE("MS Init\r\n");
uint8_t rcode;
uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations
epInfo[1].epAddr = 0;
USBTRACE("MS Init\r\n");
AddressPool &addrPool = pUsb->GetAddressPool();
UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress);
AddressPool &addrPool = pUsb->GetAddressPool();
UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
// Assign new address to the device
delay(2000);
rcode = pUsb->setAddr(0, 0, bAddress);
// Assign new address to the device
delay(2000);
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
if (rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", 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);
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.
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);
}
}
}
rcode = GetMaxLUN(&bMaxLUN);
if(rcode)
goto FailGetMaxLUN;
CheckMedia();
if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN);
rcode = OnInit();
delay(1000); // Delay a bit for slow firmware.
if (rcode) goto FailOnInit;
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
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);
}
}
}
#ifdef DEBUG_USB_HOST
USBTRACE("MS configured\r\n\r\n");
#endif
bPollEnable = true;
CheckMedia();
//USBTRACE("Poll enabled\r\n");
return 0;
rcode = OnInit();
FailSetConfDescr:
if(rcode)
goto FailOnInit;
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
#ifdef DEBUG_USB_HOST
USBTRACE("MS configured\r\n\r\n");
#endif
FailOnInit:
bPollEnable = true;
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
goto Fail;
#endif
//USBTRACE("Poll enabled\r\n");
return 0;
FailGetMaxLUN:
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
#ifdef DEBUG_USB_HOST
USBTRACE("GetMaxLUN:");
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
goto Fail;
#endif
//#ifdef DEBUG_USB_HOST
// FailInvalidSectorSize:
// USBTRACE("Sector Size is NOT VALID: ");
// goto Fail;
//#endif
FailGetMaxLUN:
#ifdef DEBUG_USB_HOST
USBTRACE("GetMaxLUN:");
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
//#ifdef DEBUG_USB_HOST
//FailInvalidSectorSize:
// USBTRACE("Sector Size is NOT VALID: ");
// goto Fail;
//#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
#endif
#ifdef DEBUG_USB_HOST
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
#ifdef DEBUG_USB_HOST
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
/**
@ -548,46 +530,45 @@ Fail:
* @param 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("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
ErrorMessage<uint8_t> (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t> (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t> (PSTR("Alt.Set"), alt);
bConfNum = conf;
bConfNum = conf;
uint8_t index;
uint8_t index;
#if 1
if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) {
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].bmSndToggle = 0;
epInfo[index].bmRcvToggle = 0;
#if 1
if ((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) {
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].bmSndToggle = 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;
}
#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
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].bmSndToggle = 0;
epInfo[index].bmRcvToggle = 0;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].bmSndToggle = 0;
epInfo[index].bmRcvToggle = 0;
bNumEP++;
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
*/
uint8_t BulkOnly::Release() {
ClearAllEP();
pUsb->GetAddressPool().FreeAddress(bAddress);
return 0;
ClearAllEP();
pUsb->GetAddressPool().FreeAddress(bAddress);
return 0;
}
/**
@ -608,38 +589,37 @@ uint8_t BulkOnly::Release() {
* @return true if LUN is ready for use.
*/
bool BulkOnly::CheckLUN(uint8_t lun) {
uint8_t rcode;
Capacity capacity;
for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
uint8_t rcode;
Capacity capacity;
for (uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
if(rcode) {
//printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
return false;
}
ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun);
for(uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++)
D_PrintHex<uint8_t > (capacity.data[i], 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);
rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
if (rcode) {
//printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
return false;
}
ErrorMessage<uint8_t> (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun);
for (uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++)
D_PrintHex<uint8_t> (capacity.data[i], 0x80);
Notify(PSTR("\r\n\r\n"), 0x80);
CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1;
if(CurrentCapacity[lun] == /*0xffffffffLU */ 0x01LU || CurrentCapacity[lun] == 0x00LU) {
// Buggy firmware will report 0xffffffff or 0 for no media
if(CurrentCapacity[lun])
ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun);
return false;
}
delay(20);
Page3F(lun);
if(!TestUnitReady(lun)) return true;
return false;
// 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 != 0x0200UL && c != 0x0400UL && c != 0x0800UL && c != 0x1000UL) 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;
if (CurrentCapacity[lun] == /*0xFFFFFFFFUL */ 0x01UL || CurrentCapacity[lun] == 0x00UL) {
// Buggy firmware will report 0xFFFFFFFF or 0 for no media
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
*/
void BulkOnly::CheckMedia() {
for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
if(TestUnitReady(lun)) {
LUNOk[lun] = false;
continue;
}
if(!LUNOk[lun])
LUNOk[lun] = CheckLUN(lun);
}
#if 0
printf("}}}}}}}}}}}}}}}}STATUS ");
for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
if(LUNOk[lun])
printf("#");
else printf(".");
}
printf("\r\n");
#endif
qNextPollTime = (uint32_t)millis() + 2000;
for (uint8_t lun = 0; lun <= bMaxLUN; lun++) {
if (TestUnitReady(lun)) {
LUNOk[lun] = false;
continue;
}
if (!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
}
#if 0
printf("}}}}}}}}}}}}}}}}STATUS ");
for (uint8_t lun = 0; lun <= bMaxLUN; lun++)
printf(LUNOk[lun] ? "#" : ".");
printf("\r\n");
#endif
qNextPollTime = (uint32_t)millis() + 2000;
}
/**
@ -674,17 +650,11 @@ void BulkOnly::CheckMedia() {
* @return
*/
uint8_t BulkOnly::Poll() {
//uint8_t rcode = 0;
if(!bPollEnable)
return 0;
if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) {
CheckMedia();
}
//rcode = 0;
return 0;
//uint8_t rcode = 0;
if (!bPollEnable) 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 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;
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\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);
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) {
//SetCurLUN(lun);
if(!bAddress)
if (!bAddress)
return MASS_ERR_UNIT_NOT_READY;
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 buf[192];
for(int i = 0; i < 192; i++) {
for (int i = 0; i < 192; i++) {
buf[i] = 0x00;
}
WriteOk[lun] = true;
@ -796,11 +766,11 @@ uint8_t BulkOnly::Page3F(uint8_t lun) {
return 0;
#endif
uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf);
if(!rc) {
if (!rc) {
WriteOk[lun] = ((buf[2] & 0x80) == 0);
Notify(PSTR("Mode Sense: "), 0x80);
for(int i = 0; i < 4; i++) {
D_PrintHex<uint8_t > (buf[i], 0x80);
for (int i = 0; i < 4; i++) {
D_PrintHex<uint8_t> (buf[i], 0x80);
Notify(PSTR(" "), 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\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);
//SetCurLUN(lun);
return Transaction(&cbw, size, buf);
@ -838,17 +808,17 @@ uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) {
* @return
*/
uint8_t BulkOnly::ClearEpHalt(uint8_t index) {
if(index == 0)
if (index == 0)
return 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);
if(ret) {
ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret);
ErrorMessage<uint8_t > (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr));
if (ret) {
ErrorMessage<uint8_t> (PSTR("ClearEpHalt"), ret);
ErrorMessage<uint8_t> (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr));
return ret;
}
epInfo[index].bmSndToggle = 0;
@ -861,7 +831,7 @@ uint8_t BulkOnly::ClearEpHalt(uint8_t index) {
*
*/
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
*/
void BulkOnly::ClearAllEP() {
for(uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].bmSndToggle = 0;
epInfo[i].bmRcvToggle = 0;
epInfo[i].bmNakPower = USB_NAK_DEFAULT;
}
for (uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].bmSndToggle = 0;
epInfo[i].bmRcvToggle = 0;
epInfo[i].bmNakPower = USB_NAK_DEFAULT;
}
for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) {
LUNOk[i] = false;
WriteOk[i] = false;
CurrentCapacity[i] = 0lu;
CurrentSectorSize[i] = 0;
}
for (uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) {
LUNOk[i] = false;
WriteOk[i] = false;
CurrentCapacity[i] = 0UL;
CurrentSectorSize[i] = 0;
}
bIface = 0;
bNumEP = 1;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
bLastUsbError = 0;
bMaxLUN = 0;
bTheLUN = 0;
bIface = 0;
bNumEP = 1;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
bLastUsbError = 0;
bMaxLUN = 0;
bTheLUN = 0;
}
/**
@ -922,15 +892,15 @@ void BulkOnly::ClearAllEP() {
* @return
*/
bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) {
if(pcsw->dCSWSignature != MASS_CSW_SIGNATURE) {
Notify(PSTR("CSW:Sig error\r\n"), 0x80);
return false;
}
if(pcsw->dCSWTag != pcbw->dCBWTag) {
Notify(PSTR("CSW:Wrong tag\r\n"), 0x80);
return false;
}
return true;
if (pcsw->dCSWSignature != MASS_CSW_SIGNATURE) {
Notify(PSTR("CSW:Sig error\r\n"), 0x80);
return false;
}
if (pcsw->dCSWTag != pcbw->dCBWTag) {
Notify(PSTR("CSW:Wrong tag\r\n"), 0x80);
return false;
}
return true;
}
/**
@ -941,65 +911,56 @@ bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *p
* @return
*/
uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) {
uint8_t count = 3;
uint8_t count = 3;
bLastUsbError = error;
//if (error)
//ClearEpHalt(index);
while(error && count) {
if(error != hrSUCCESS) {
ErrorMessage<uint8_t > (PSTR("USB Error"), error);
ErrorMessage<uint8_t > (PSTR("Index"), index);
}
switch(error) {
// case hrWRONGPID:
case hrSUCCESS:
return MASS_ERR_SUCCESS;
case hrBUSY:
// SIE is busy, just hang out and try again.
return MASS_ERR_UNIT_BUSY;
case hrTIMEOUT:
case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED;
case hrSTALL:
if(index == 0)
return MASS_ERR_STALL;
ClearEpHalt(index);
if(index != epDataInIndex)
return MASS_ERR_WRITE_STALL;
return MASS_ERR_STALL;
bLastUsbError = error;
//if (error)
//ClearEpHalt(index);
while (error && count) {
if (error != hrSUCCESS) {
ErrorMessage<uint8_t> (PSTR("USB Error"), error);
ErrorMessage<uint8_t> (PSTR("Index"), index);
}
switch (error) {
// case hrWRONGPID:
case hrSUCCESS: return MASS_ERR_SUCCESS;
case hrBUSY: return MASS_ERR_UNIT_BUSY; // SIE is busy, just hang out and try again.
case hrTIMEOUT:
case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED;
case hrSTALL:
if (index) {
ClearEpHalt(index);
return (index == epDataInIndex) ? MASS_ERR_STALL : MASS_ERR_WRITE_STALL;
}
return MASS_ERR_STALL;
case hrNAK:
if(index == 0)
return MASS_ERR_UNIT_BUSY;
return MASS_ERR_UNIT_BUSY;
case hrNAK:
return index ? MASS_ERR_UNIT_BUSY : MASS_ERR_UNIT_BUSY;
case hrTOGERR:
// Handle a very super rare corner case, where toggles become de-synched.
// I have only ran 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.
// --AJK
if(bAddress && bConfNum) {
error = pUsb->setConf(bAddress, 0, bConfNum);
case hrTOGERR:
// Handle a super rare corner case, where toggles become de-synced.
// 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.
// --AJK
if (bAddress && 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)
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);
return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS);
}
#if MS_WANT_PARSER
uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) {
return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0);
}
uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) {
return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0);
}
#endif
/**
@ -1012,101 +973,100 @@ uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void
* @return
*/
uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf
#if MS_WANT_PARSER
, uint8_t flags
#endif
) {
#if MS_WANT_PARSER
, uint8_t flags
#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
uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength;
printf("Transfersize %i\r\n", bytes);
delay(1000);
bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK;
#else
uint16_t bytes = buf_size;
#endif
bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK;
#else
uint16_t bytes = buf_size;
#endif
bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN;
uint8_t ret = 0;
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);
bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN;
uint8_t ret = 0;
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(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);
#if MS_WANT_PARSER
}
if (ret) ErrorMessage<uint8_t> (PSTR("============================ DAT"), ret);
}
}
}
#endif
ret = HandleUsbError(usberr, epDataInIndex);
} else {
while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) delay(1);
ret = HandleUsbError(usberr, epDataOutIndex);
}
if(ret) {
ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret);
}
}
}
bytes = sizeof (CommandStatusWrapper);
int tries = 2;
while (tries--) {
while ((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) delay(1);
if (!usberr) break;
ClearEpHalt(epDataInIndex);
if (tries) ResetRecovery();
}
{
bytes = sizeof (CommandStatusWrapper);
int tries = 2;
while(tries--) {
while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) delay(1);
if(!usberr) break;
ClearEpHalt(epDataInIndex);
if(tries) ResetRecovery();
}
if(!ret) {
Notify(PSTR("CBW:\t\tOK\r\n"), 0x80);
Notify(PSTR("Data Stage:\tOK\r\n"), 0x80);
} else {
// Throw away csw, IT IS NOT OF ANY USE.
ResetRecovery();
return ret;
}
ret = HandleUsbError(usberr, epDataInIndex);
if(ret) {
ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret);
}
if(usberr == hrSUCCESS) {
if(IsValidCSW(&csw, pcbw)) {
//ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag);
//ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus);
//ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
return csw.bCSWStatus;
} else {
// NOTE! Sometimes this is caused by the reported residue being wrong.
// Get a different device. It isn't compliant, and should have never passed Q&A.
// 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
Notify(PSTR("Invalid CSW\r\n"), 0x80);
ResetRecovery();
//return MASS_ERR_SUCCESS;
return MASS_ERR_INVALID_CSW;
}
}
}
return ret;
if (!ret) {
Notify(PSTR("CBW:\t\tOK\r\n"), 0x80);
Notify(PSTR("Data Stage:\tOK\r\n"), 0x80);
}
else {
// Throw away csw, IT IS NOT OF ANY USE.
ResetRecovery();
return ret;
}
ret = HandleUsbError(usberr, epDataInIndex);
if (ret) ErrorMessage<uint8_t> (PSTR("============================ CSW"), ret);
if (usberr == hrSUCCESS) {
if (IsValidCSW(&csw, pcbw)) {
//ErrorMessage<uint32_t> (PSTR("CSW.dCBWTag"), csw.dCSWTag);
//ErrorMessage<uint8_t> (PSTR("bCSWStatus"), csw.bCSWStatus);
//ErrorMessage<uint32_t> (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
return csw.bCSWStatus;
}
else {
// NOTE! Sometimes this is caused by the reported residue being wrong.
// Get a different device. It isn't compliant, and should have never passed Q&A.
// 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
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
*/
uint8_t BulkOnly::SetCurLUN(uint8_t lun) {
if(lun > bMaxLUN)
return MASS_ERR_INVALID_LUN;
bTheLUN = lun;
return MASS_ERR_SUCCESS;
};
if (lun > bMaxLUN) return MASS_ERR_INVALID_LUN;
bTheLUN = lun;
return MASS_ERR_SUCCESS;
}
/**
* For driver use only.
@ -1129,83 +1088,78 @@ uint8_t BulkOnly::SetCurLUN(uint8_t lun) {
* @return
*/
uint8_t BulkOnly::HandleSCSIError(uint8_t status) {
uint8_t ret = 0;
uint8_t ret = 0;
switch(status) {
case 0: return MASS_ERR_SUCCESS;
switch (status) {
case 0: return MASS_ERR_SUCCESS;
case 2:
ErrorMessage<uint8_t > (PSTR("Phase Error"), status);
ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
ResetRecovery();
return MASS_ERR_GENERAL_SCSI_ERROR;
case 2:
ErrorMessage<uint8_t> (PSTR("Phase Error"), status);
ErrorMessage<uint8_t> (PSTR("LUN"), bTheLUN);
ResetRecovery();
return MASS_ERR_GENERAL_SCSI_ERROR;
case 1:
ErrorMessage<uint8_t > (PSTR("SCSI Error"), status);
ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
RequestSenseResponce rsp;
case 1:
ErrorMessage<uint8_t> (PSTR("SCSI Error"), status);
ErrorMessage<uint8_t> (PSTR("LUN"), bTheLUN);
RequestSenseResponce rsp;
ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp);
ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp);
if(ret) {
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;
}
if (ret) 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
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.
// 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
////////////////////////////////////////////////////////////////////////////////
/**
@ -1213,20 +1167,20 @@ uint8_t BulkOnly::HandleSCSIError(uint8_t status) {
* @param ep_ptr
*/
void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
D_PrintHex<uint8_t> (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
D_PrintHex<uint8_t> (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
D_PrintHex<uint8_t> (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
D_PrintHex<uint8_t> (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
D_PrintHex<uint16_t> (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
D_PrintHex<uint8_t> (ep_ptr->bInterval, 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... */
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(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80);
Notify(PSTR("---------\r\n"), 0x80);
#if MS_WANT_PARSER
if (!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80);
Notify(PSTR("---------\r\n"), 0x80);
CommandBlockWrapper cbw = CommandBlockWrapper();
CommandBlockWrapper cbw = CommandBlockWrapper();
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
cbw.dCBWTag = ++dCBWTag;
cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks);
cbw.bmCBWFlags = MASS_CMD_DIR_IN,
cbw.bmCBWLUN = lun;
cbw.bmCBWCBLength = 10;
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
cbw.dCBWTag = ++dCBWTag;
cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks);
cbw.bmCBWFlags = MASS_CMD_DIR_IN,
cbw.bmCBWLUN = lun;
cbw.bmCBWCBLength = 10;
cbw.CBWCB[0] = SCSI_CMD_READ_10;
cbw.CBWCB[8] = blocks;
cbw.CBWCB[2] = ((addr >> 24) & 0xff);
cbw.CBWCB[3] = ((addr >> 16) & 0xff);
cbw.CBWCB[4] = ((addr >> 8) & 0xff);
cbw.CBWCB[5] = (addr & 0xff);
cbw.CBWCB[0] = SCSI_CMD_READ_10;
cbw.CBWCB[8] = blocks;
cbw.CBWCB[2] = ((addr >> 24) & 0xff);
cbw.CBWCB[3] = ((addr >> 16) & 0xff);
cbw.CBWCB[4] = ((addr >> 8) & 0xff);
cbw.CBWCB[5] = (addr & 0xff);
return HandleSCSIError(Transaction(&cbw, bsize, prs, 1));
#else
return MASS_ERR_NOT_IMPLEMENTED;
#endif
return HandleSCSIError(Transaction(&cbw, bsize, prs, 1));
#else
return MASS_ERR_NOT_IMPLEMENTED;
#endif
}
#endif // USB_FLASH_DRIVE_SUPPORT

View file

@ -408,7 +408,7 @@ public:
CommandBlockWrapper() :
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.
@ -416,7 +416,7 @@ public:
CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
CommandBlockWrapperBase(tag, xflen, flgs),
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.
// Using reinterpret_cast to a dreinterpretifferent object is the proper way to do this.
//(((BASICCDB_t *) CBWCB)->LUN) = cmd;
@ -493,27 +493,17 @@ protected:
bool WriteOk[MASS_MAX_SUPPORTED_LUN];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
// Additional Initialization Method for Subclasses
virtual uint8_t OnInit() {
return 0;
};
virtual uint8_t OnInit() { return 0; }
public:
BulkOnly(USB *p);
uint8_t GetLastUsbError() {
return bLastUsbError;
};
uint8_t GetLastUsbError() { return bLastUsbError; };
uint8_t GetbMaxLUN() {
return bMaxLUN; // Max LUN
}
uint8_t GetbTheLUN() {
return bTheLUN; // Active LUN
}
uint8_t GetbMaxLUN() { return bMaxLUN; } // Max LUN
uint8_t GetbTheLUN() { return bTheLUN; } // Active LUN
bool WriteProtected(uint8_t lun);
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
@ -533,16 +523,12 @@ public:
uint8_t Release();
uint8_t Poll();
virtual uint8_t GetAddress() {
return bAddress;
};
virtual uint8_t GetAddress() { return bAddress; }
// UsbConfigXtracter implementation
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) {
return (klass == USB_CLASS_MASS_STORAGE);
}
virtual bool DEVCLASSOK(uint8_t klass) { return klass == USB_CLASS_MASS_STORAGE; }
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);
@ -573,5 +559,4 @@ private:
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf);
uint8_t HandleUsbError(uint8_t error, uint8_t index);
uint8_t HandleSCSIError(uint8_t status);
};

View file

@ -22,11 +22,11 @@
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(_max3421e_h_)
#error "Never include max3421e.h directly; include Usb.h instead"
#else
#pragma once
#define _max3421e_h_
#ifndef _usb_h_
#error "Never include max3421e.h directly; include Usb.h instead"
#endif
/* MAX3421E register/bit names and bitmasks */
@ -231,6 +231,3 @@
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
#endif //_max3421e_h_

View file

@ -35,97 +35,94 @@
int UsbDEBUGlvl = 0x80;
void E_Notifyc(char c, int lvl) {
if(UsbDEBUGlvl < lvl) return;
#if defined(ARDUINO) && ARDUINO >=100
USB_HOST_SERIAL.print(c);
#else
USB_HOST_SERIAL.print(c, BYTE);
#endif
//USB_HOST_SERIAL.flush();
if (UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(c
#if !defined(ARDUINO) || ARDUINO < 100
, BYTE
#endif
);
//USB_HOST_SERIAL.flush();
}
void E_Notify(char const * msg, int lvl) {
if(UsbDEBUGlvl < lvl) return;
if(!msg) return;
char c;
while((c = pgm_read_byte(msg++))) E_Notifyc(c, lvl);
if (UsbDEBUGlvl < lvl) return;
if (!msg) return;
while (const char c = pgm_read_byte(msg++)) E_Notifyc(c, lvl);
}
void E_NotifyStr(char const * msg, int lvl) {
if(UsbDEBUGlvl < lvl) return;
if(!msg) return;
char c;
while((c = *msg++)) E_Notifyc(c, lvl);
if (UsbDEBUGlvl < lvl) return;
if (!msg) return;
while (const char c = *msg++) E_Notifyc(c, lvl);
}
void E_Notify(uint8_t b, int lvl) {
if(UsbDEBUGlvl < lvl) return;
#if defined(ARDUINO) && ARDUINO >=100
USB_HOST_SERIAL.print(b);
#else
USB_HOST_SERIAL.print(b, DEC);
#endif
//USB_HOST_SERIAL.flush();
if (UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(b
#if !defined(ARDUINO) || ARDUINO < 100
, DEC
#endif
);
//USB_HOST_SERIAL.flush();
}
void E_Notify(double d, int lvl) {
if(UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(d);
//USB_HOST_SERIAL.flush();
if (UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(d);
//USB_HOST_SERIAL.flush();
}
#ifdef DEBUG_USB_HOST
void NotifyFailGetDevDescr(void) {
Notify(PSTR("\r\ngetDevDescr "), 0x80);
}
void NotifyFailGetDevDescr(void) {
Notify(PSTR("\r\ngetDevDescr "), 0x80);
}
void NotifyFailSetDevTblEntry(void) {
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
}
void NotifyFailSetDevTblEntry(void) {
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
}
void NotifyFailGetConfDescr(void) {
Notify(PSTR("\r\ngetConf "), 0x80);
}
void NotifyFailGetConfDescr(void) {
Notify(PSTR("\r\ngetConf "), 0x80);
}
void NotifyFailSetConfDescr(void) {
Notify(PSTR("\r\nsetConf "), 0x80);
}
void NotifyFailSetConfDescr(void) {
Notify(PSTR("\r\nsetConf "), 0x80);
}
void NotifyFailGetDevDescr(uint8_t reason) {
NotifyFailGetDevDescr();
NotifyFail(reason);
}
void NotifyFailGetDevDescr(uint8_t reason) {
NotifyFailGetDevDescr();
NotifyFail(reason);
}
void NotifyFailSetDevTblEntry(uint8_t reason) {
NotifyFailSetDevTblEntry();
NotifyFail(reason);
void NotifyFailSetDevTblEntry(uint8_t reason) {
NotifyFailSetDevTblEntry();
NotifyFail(reason);
}
}
void NotifyFailGetConfDescr(uint8_t reason) {
NotifyFailGetConfDescr();
NotifyFail(reason);
}
void NotifyFailGetConfDescr(uint8_t reason) {
NotifyFailGetConfDescr();
NotifyFail(reason);
}
void NotifyFailSetConfDescr(uint8_t reason) {
NotifyFailSetConfDescr();
NotifyFail(reason);
}
void NotifyFailSetConfDescr(uint8_t reason) {
NotifyFailSetConfDescr();
NotifyFail(reason);
}
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
D_PrintHex<uint16_t > (VID, 0x80);
Notify(PSTR(" PID: "), 0x80);
D_PrintHex<uint16_t > (PID, 0x80);
}
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
D_PrintHex<uint16_t > (VID, 0x80);
Notify(PSTR(" 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 // USB_FLASH_DRIVE_SUPPORT

View file

@ -22,10 +22,11 @@
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__MESSAGE_H__)
#error "Never include message.h directly; include Usb.h instead"
#else
#define __MESSAGE_H__
#pragma once
#ifndef _usb_h_
#error "Never include message.h directly; include Usb.h instead"
#endif
extern int UsbDEBUGlvl;
@ -35,52 +36,50 @@ void E_NotifyStr(char const * msg, int lvl);
void E_Notifyc(char c, int lvl);
#ifdef DEBUG_USB_HOST
#define Notify E_Notify
#define NotifyStr E_NotifyStr
#define Notifyc E_Notifyc
void NotifyFailGetDevDescr(uint8_t reason);
void NotifyFailSetDevTblEntry(uint8_t reason);
void NotifyFailGetConfDescr(uint8_t reason);
void NotifyFailSetConfDescr(uint8_t reason);
void NotifyFailGetDevDescr(void);
void NotifyFailSetDevTblEntry(void);
void NotifyFailGetConfDescr(void);
void NotifyFailSetConfDescr(void);
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
void NotifyFail(uint8_t rcode);
#define Notify E_Notify
#define NotifyStr E_NotifyStr
#define Notifyc E_Notifyc
void NotifyFailGetDevDescr(uint8_t reason);
void NotifyFailSetDevTblEntry(uint8_t reason);
void NotifyFailGetConfDescr(uint8_t reason);
void NotifyFailSetConfDescr(uint8_t reason);
void NotifyFailGetDevDescr(void);
void NotifyFailSetDevTblEntry(void);
void NotifyFailGetConfDescr(void);
void NotifyFailSetConfDescr(void);
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
void NotifyFail(uint8_t rcode);
#else
#define Notify(...) ((void)0)
#define NotifyStr(...) ((void)0)
#define Notifyc(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailSetConfDescr(...) ((void)0)
#define NotifyFailUnknownDevice(...) ((void)0)
#define NotifyFail(...) ((void)0)
#define Notify(...) ((void)0)
#define NotifyStr(...) ((void)0)
#define Notifyc(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailSetConfDescr(...) ((void)0)
#define NotifyFailUnknownDevice(...) ((void)0)
#define NotifyFail(...) ((void)0)
#endif
template <class ERROR_TYPE>
void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
#ifdef DEBUG_USB_HOST
Notify(msg, level);
Notify(PSTR(": "), level);
D_PrintHex<ERROR_TYPE > (rcode, level);
Notify(PSTR("\r\n"), level);
#endif
#ifdef DEBUG_USB_HOST
Notify(msg, level);
Notify(PSTR(": "), level);
D_PrintHex<ERROR_TYPE > (rcode, level);
Notify(PSTR("\r\n"), level);
#endif
}
template <class ERROR_TYPE>
void ErrorMessage(char const * msg __attribute__((unused)), ERROR_TYPE rcode __attribute__((unused)) = 0) {
#ifdef DEBUG_USB_HOST
Notify(msg, 0x80);
Notify(PSTR(": "), 0x80);
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
#endif
#ifdef DEBUG_USB_HOST
Notify(msg, 0x80);
Notify(PSTR(": "), 0x80);
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
#endif
}
#endif // __MESSAGE_H__

View file

@ -30,53 +30,48 @@
#include "Usb.h"
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
if(!pBuf) {
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
return false;
}
for(; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
pBuf[valueSize - countDown] = (**pp);
if (!pBuf) {
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
return false;
}
for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
pBuf[valueSize - countDown] = (**pp);
if(countDown)
return false;
if (countDown) return false;
countDown = valueSize;
return true;
countDown = valueSize;
return true;
}
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
switch(nStage) {
case 0:
pBuf->valueSize = lenSize;
theParser.Initialize(pBuf);
nStage = 1;
switch (nStage) {
case 0:
pBuf->valueSize = lenSize;
theParser.Initialize(pBuf);
nStage = 1;
case 1:
if(!theParser.Parse(pp, pcntdn))
return false;
case 1:
if (!theParser.Parse(pp, pcntdn)) return false;
arLen = 0;
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
arLenCntdn = arLen;
nStage = 2;
arLen = 0;
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
arLenCntdn = arLen;
nStage = 2;
case 2:
pBuf->valueSize = valSize;
theParser.Initialize(pBuf);
nStage = 3;
case 2:
pBuf->valueSize = valSize;
theParser.Initialize(pBuf);
nStage = 3;
case 3:
for(; arLenCntdn; arLenCntdn--) {
if(!theParser.Parse(pp, pcntdn))
return false;
case 3:
for (; arLenCntdn; arLenCntdn--) {
if (!theParser.Parse(pp, pcntdn)) return false;
if (pf) pf(pBuf, (arLen - arLenCntdn), me);
}
if(pf)
pf(pBuf, (arLen - arLenCntdn), me);
}
nStage = 0;
}
return true;
nStage = 0;
}
return true;
}
#endif // USB_FLASH_DRIVE_SUPPORT

View file

@ -22,67 +22,65 @@
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#if !defined(_usb_h_) || defined(__PARSETOOLS_H__)
#error "Never include parsetools.h directly; include Usb.h instead"
#else
#define __PARSETOOLS_H__
#ifndef _usb_h_
#error "Never include parsetools.h directly; include Usb.h instead"
#endif
struct MultiValueBuffer {
uint8_t valueSize;
void *pValue;
uint8_t valueSize;
void *pValue;
} __attribute__((packed));
class MultiByteValueParser {
uint8_t * pBuf;
uint8_t countDown;
uint8_t valueSize;
uint8_t * pBuf;
uint8_t countDown;
uint8_t valueSize;
public:
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
};
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
};
const uint8_t* GetBuffer() {
return pBuf;
};
const uint8_t* GetBuffer() { return pBuf; }
void Initialize(MultiValueBuffer * const pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = valueSize = pbuf->valueSize;
};
void Initialize(MultiValueBuffer * const pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = valueSize = pbuf->valueSize;
}
bool Parse(uint8_t **pp, uint16_t *pcntdn);
bool Parse(uint8_t **pp, uint16_t *pcntdn);
};
class ByteSkipper {
uint8_t *pBuf;
uint8_t nStage;
uint16_t countDown;
uint8_t *pBuf;
uint8_t nStage;
uint16_t countDown;
public:
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
};
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
}
void Initialize(MultiValueBuffer *pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = 0;
};
void Initialize(MultiValueBuffer *pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = 0;
}
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
switch(nStage) {
case 0:
countDown = bytes_to_skip;
nStage++;
case 1:
for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
switch (nStage) {
case 0:
countDown = bytes_to_skip;
nStage++;
case 1:
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
if(!countDown)
nStage = 0;
};
return (!countDown);
};
if (!countDown)
nStage = 0;
}
return (!countDown);
}
};
// 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 {
public:
enum ParseMode {
modeArray, modeRange/*, modeEnum*/
};
enum ParseMode {
modeArray, modeRange/*, modeEnum*/
};
private:
uint8_t nStage;
uint8_t enStage;
uint8_t nStage;
uint8_t enStage;
uint32_t arLen;
uint32_t arLenCntdn;
uint32_t arLen;
uint32_t arLenCntdn;
uint8_t lenSize; // size of the array length field in bytes
uint8_t valSize; // size of the array element in bytes
uint8_t lenSize; // size of the array length field 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
MultiByteValueParser theParser;
// The only parser for both size and array element parsing
MultiByteValueParser theParser;
uint8_t /*ParseMode*/ prsMode;
uint8_t /*ParseMode*/ prsMode;
public:
PTPListParser() :
nStage(0),
enStage(0),
arLen(0),
arLenCntdn(0),
lenSize(0),
valSize(0),
pBuf(NULL),
prsMode(modeArray) {
};
PTPListParser() :
nStage(0),
enStage(0),
arLen(0),
arLenCntdn(0),
lenSize(0),
valSize(0),
pBuf(NULL),
prsMode(modeArray) { }
;
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
pBuf = p;
lenSize = len_size;
valSize = val_size;
prsMode = mode;
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
pBuf = p;
lenSize = len_size;
valSize = val_size;
prsMode = mode;
if(prsMode == modeRange) {
arLenCntdn = arLen = 3;
nStage = 2;
} else {
arLenCntdn = arLen = 0;
nStage = 0;
}
enStage = 0;
theParser.Initialize(p);
};
if (prsMode == modeRange) {
arLenCntdn = arLen = 3;
nStage = 2;
}
else {
arLenCntdn = arLen = 0;
nStage = 0;
}
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
* e-mail : support@circuitsathome.com
*/
#pragma once
#if !defined(_usb_h_) || defined(__PRINTHEX_H__)
#error "Never include printhex.h directly; include Usb.h instead"
#else
#define __PRINTHEX_H__
#ifndef _usb_h_
#error "Never include printhex.h directly; include Usb.h instead"
#endif
void E_Notifyc(char c, int lvl);
template <class T>
void PrintHex(T val, int lvl) {
int num_nibbles = sizeof (T) * 2;
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if(v > 57) v += 7;
E_Notifyc(v, lvl);
} while(--num_nibbles);
int num_nibbles = sizeof (T) * 2;
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if (v > 57) v += 7;
E_Notifyc(v, lvl);
} while (--num_nibbles);
}
template <class T>
void PrintBin(T val, int lvl) {
for(T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
if(val & mask)
E_Notifyc('1', lvl);
else
E_Notifyc('0', lvl);
for (T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
E_Notifyc(val & mask ? '1' : '0', lvl);
}
template <class T>
void SerialPrintHex(T val) {
int num_nibbles = sizeof (T) * 2;
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if(v > 57) v += 7;
USB_HOST_SERIAL.print(v);
} while(--num_nibbles);
int num_nibbles = sizeof (T) * 2;
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if (v > 57) v += 7;
USB_HOST_SERIAL.print(v);
} while (--num_nibbles);
}
template <class T>
void PrintHex2(Print *prn, T val) {
T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2));
while(mask > 1) {
if(val < mask)
prn->print("0");
mask >>= 4;
}
prn->print((T)val, HEX);
T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2));
while (mask > 1) {
if (val < mask) prn->print("0");
mask >>= 4;
}
prn->print((T)val, HEX);
}
template <class T> void D_PrintHex(T val __attribute__((unused)), int lvl __attribute__((unused))) {
#ifdef DEBUG_USB_HOST
PrintHex<T > (val, lvl);
#endif
#ifdef DEBUG_USB_HOST
PrintHex<T > (val, lvl);
#endif
}
template <class T>
void D_PrintBin(T val, int lvl) {
#ifdef DEBUG_USB_HOST
PrintBin<T > (val, lvl);
#endif
#ifdef DEBUG_USB_HOST
PrintBin<T > (val, lvl);
#endif
}
#endif // __PRINTHEX_H__

View file

@ -35,7 +35,7 @@
* flash drives and simple USB hard drives.
* 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
* 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.

View file

@ -23,12 +23,11 @@
* e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(_ch9_h_)
#error "Never include usb_ch9.h directly; include Usb.h instead"
#else
#ifndef _usb_h_
#error "Never include usb_ch9.h directly; include Usb.h instead"
#endif
/* USB chapter 9 structures */
#define _ch9_h_
/* Misc.USB constants */
#define DEV_DESCR_LEN 18 //device descriptor length
@ -81,7 +80,6 @@
#define HID_DESCRIPTOR_HID 0x21
/* OTG SET FEATURE Constants */
#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
@ -170,5 +168,3 @@ typedef struct {
uint8_t bDescrType; // Type of class descriptor
uint16_t wDescriptorLength; // Total size of the Report descriptor
} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
#endif // _ch9_h_