#include <stdint.h> | #include <stdint.h> | ||||
#if !defined(__MK66FX1M0__) | |||||
#if !defined(__MK66FX1M0__) && !defined(__IMXRT1052__) && !defined(__IMXRT1062__) | |||||
#error "USBHost_t36 only works with Teensy 3.6. Please select it in Tools > Boards" | #error "USBHost_t36 only works with Teensy 3.6. Please select it in Tools > Boards" | ||||
#endif | #endif | ||||
#include "utility/imxrt_usbhs.h" | |||||
// Dear inquisitive reader, USB is a complex protocol defined with | // Dear inquisitive reader, USB is a complex protocol defined with | ||||
// very specific terminology. To have any chance of understand this | // very specific terminology. To have any chance of understand this | ||||
KeyboardController(USBHost &host) { init(); } | KeyboardController(USBHost &host) { init(); } | ||||
KeyboardController(USBHost *host) { init(); } | KeyboardController(USBHost *host) { init(); } | ||||
// need their own versions as both USBDriver and USBHIDInput provide | |||||
uint16_t idVendor(); | |||||
uint16_t idProduct(); | |||||
const uint8_t *manufacturer(); | |||||
const uint8_t *product(); | |||||
const uint8_t *serialNumber(); | |||||
// Some methods are in both public classes so we need to figure out which one to use | // Some methods are in both public classes so we need to figure out which one to use | ||||
uint16_t idVendor(); | uint16_t idVendor(); | ||||
uint16_t idProduct(); | uint16_t idProduct(); | ||||
// Added for extras information. | // Added for extras information. | ||||
void attachExtrasPress(void (*f)(uint32_t top, uint16_t code)) { extrasKeyPressedFunction = f; } | void attachExtrasPress(void (*f)(uint32_t top, uint16_t code)) { extrasKeyPressedFunction = f; } | ||||
void attachExtrasRelease(void (*f)(uint32_t top, uint16_t code)) { extrasKeyReleasedFunction = f; } | void attachExtrasRelease(void (*f)(uint32_t top, uint16_t code)) { extrasKeyReleasedFunction = f; } | ||||
void forceBootProtocol(); | |||||
enum {MAX_KEYS_DOWN=4}; | enum {MAX_KEYS_DOWN=4}; | ||||
volatile bool hid_input_data_ = false; // did we receive any valid data with report? | volatile bool hid_input_data_ = false; // did we receive any valid data with report? | ||||
uint8_t count_keys_down_ = 0; | uint8_t count_keys_down_ = 0; | ||||
uint16_t keys_down[MAX_KEYS_DOWN]; | uint16_t keys_down[MAX_KEYS_DOWN]; | ||||
bool force_boot_protocol; // User or VID/PID said force boot protocol? | |||||
bool control_queued; | |||||
}; | }; | ||||
uint8_t pl2303_v1; // Which version do we have | uint8_t pl2303_v1; // Which version do we have | ||||
uint8_t pl2303_v2; | uint8_t pl2303_v2; | ||||
uint8_t interface; | uint8_t interface; | ||||
bool control_queued; | |||||
bool control_queued; // Is there already a queued control messaged | |||||
typedef enum { UNKNOWN=0, CDCACM, FTDI, PL2303, CH341, CP210X } sertype_t; | typedef enum { UNKNOWN=0, CDCACM, FTDI, PL2303, CH341, CP210X } sertype_t; | ||||
sertype_t sertype; | sertype_t sertype; | ||||
void USBHost::begin() | void USBHost::begin() | ||||
{ | { | ||||
#if defined(__MK66FX1M0__) | |||||
// Teensy 3.6 has USB host power controlled by PTE6 | // Teensy 3.6 has USB host power controlled by PTE6 | ||||
PORTE_PCR6 = PORT_PCR_MUX(1); | PORTE_PCR6 = PORT_PCR_MUX(1); | ||||
GPIOE_PDDR |= (1<<6); | GPIOE_PDDR |= (1<<6); | ||||
USBPHY_PLL_SIC = USBPHY_PLL_SIC_PLL_POWER | USBPHY_PLL_SIC_PLL_ENABLE | | USBPHY_PLL_SIC = USBPHY_PLL_SIC_PLL_POWER | USBPHY_PLL_SIC_PLL_ENABLE | | ||||
USBPHY_PLL_SIC_PLL_DIV_SEL(1) | USBPHY_PLL_SIC_PLL_EN_USB_CLKS; | USBPHY_PLL_SIC_PLL_DIV_SEL(1) | USBPHY_PLL_SIC_PLL_EN_USB_CLKS; | ||||
// wait for the PLL to lock | // wait for the PLL to lock | ||||
int count=0; | |||||
int pll_count=0; | |||||
while ((USBPHY_PLL_SIC & USBPHY_PLL_SIC_PLL_LOCK) == 0) { | while ((USBPHY_PLL_SIC & USBPHY_PLL_SIC_PLL_LOCK) == 0) { | ||||
count++; | |||||
pll_count++; | |||||
} | } | ||||
//println("PLL locked, waited ", count); | |||||
//println("PLL locked, waited ", pll_count); | |||||
// turn on power to PHY | // turn on power to PHY | ||||
USBPHY_PWD = 0; | USBPHY_PWD = 0; | ||||
delay(10); | |||||
// sanity check, connect 470K pullup & 100K pulldown and watch D+ voltage change | // sanity check, connect 470K pullup & 100K pulldown and watch D+ voltage change | ||||
//USBPHY_ANACTRL_CLR = (1<<10); // turn off both 15K pulldowns... works! :) | //USBPHY_ANACTRL_CLR = (1<<10); // turn off both 15K pulldowns... works! :) | ||||
//SIM_SOPT2 = SIM_SOPT2 & (~SIM_SOPT2_CLKOUTSEL(7)) | SIM_SOPT2_CLKOUTSEL(4); // MCGIRCLK | //SIM_SOPT2 = SIM_SOPT2 & (~SIM_SOPT2_CLKOUTSEL(7)) | SIM_SOPT2_CLKOUTSEL(4); // MCGIRCLK | ||||
//CORE_PIN9_CONFIG = PORT_PCR_MUX(5); // CLKOUT on PTC3 Alt5 (Arduino pin 9) | //CORE_PIN9_CONFIG = PORT_PCR_MUX(5); // CLKOUT on PTC3 Alt5 (Arduino pin 9) | ||||
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) | |||||
// Teensy 4.0 PLL & USB PHY powerup | |||||
while (1) { | |||||
uint32_t n = CCM_ANALOG_PLL_USB2; | |||||
if (n & CCM_ANALOG_PLL_USB2_DIV_SELECT) { | |||||
CCM_ANALOG_PLL_USB2_CLR = 0xC000; // get out of 528 MHz mode | |||||
CCM_ANALOG_PLL_USB2_SET = CCM_ANALOG_PLL_USB2_BYPASS; | |||||
CCM_ANALOG_PLL_USB2_CLR = CCM_ANALOG_PLL_USB2_POWER | | |||||
CCM_ANALOG_PLL_USB2_DIV_SELECT | | |||||
CCM_ANALOG_PLL_USB2_ENABLE | | |||||
CCM_ANALOG_PLL_USB2_EN_USB_CLKS; | |||||
continue; | |||||
} | |||||
if (!(n & CCM_ANALOG_PLL_USB2_ENABLE)) { | |||||
CCM_ANALOG_PLL_USB2_SET = CCM_ANALOG_PLL_USB2_ENABLE; // enable | |||||
continue; | |||||
} | |||||
if (!(n & CCM_ANALOG_PLL_USB2_POWER)) { | |||||
CCM_ANALOG_PLL_USB2_SET = CCM_ANALOG_PLL_USB2_POWER; // power up | |||||
continue; | |||||
} | |||||
if (!(n & CCM_ANALOG_PLL_USB2_LOCK)) { | |||||
continue; // wait for lock | |||||
} | |||||
if (n & CCM_ANALOG_PLL_USB2_BYPASS) { | |||||
CCM_ANALOG_PLL_USB2_CLR = CCM_ANALOG_PLL_USB2_BYPASS; // turn off bypass | |||||
continue; | |||||
} | |||||
if (!(n & CCM_ANALOG_PLL_USB2_EN_USB_CLKS)) { | |||||
CCM_ANALOG_PLL_USB2_SET = CCM_ANALOG_PLL_USB2_EN_USB_CLKS; // enable | |||||
continue; | |||||
} | |||||
println("USB2 PLL running"); | |||||
break; // USB2 PLL up and running | |||||
} | |||||
// turn on USB clocks (should already be on) | |||||
CCM_CCGR6 |= CCM_CCGR6_USBOH3(CCM_CCGR_ON); | |||||
// turn on USB2 PHY | |||||
USBPHY2_CTRL_CLR = USBPHY_CTRL_SFTRST | USBPHY_CTRL_CLKGATE; | |||||
USBPHY2_CTRL_SET = USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3; | |||||
USBPHY2_PWD = 0; | |||||
#endif | |||||
delay(10); | |||||
// now with the PHY up and running, start up USBHS | // now with the PHY up and running, start up USBHS | ||||
//print("begin ehci reset"); | //print("begin ehci reset"); | ||||
USBHS_USBCMD |= USBHS_USBCMD_RST; | USBHS_USBCMD |= USBHS_USBCMD_RST; | ||||
//count = 0; | |||||
int reset_count = 0; | |||||
while (USBHS_USBCMD & USBHS_USBCMD_RST) { | while (USBHS_USBCMD & USBHS_USBCMD_RST) { | ||||
//count++; | |||||
reset_count++; | |||||
} | } | ||||
//println(" reset waited ", count); | |||||
println(" reset waited ", reset_count); | |||||
init_Device_Pipe_Transfer_memory(); | init_Device_Pipe_Transfer_memory(); | ||||
for (int i=0; i < PERIODIC_LIST_SIZE; i++) { | for (int i=0; i < PERIODIC_LIST_SIZE; i++) { | ||||
//USBHS_PORTSC1 |= USBHS_PORTSC_PFSC; // force 12 Mbit/sec | //USBHS_PORTSC1 |= USBHS_PORTSC_PFSC; // force 12 Mbit/sec | ||||
//USBHS_PORTSC1 |= USBHS_PORTSC_PHCD; // phy off | //USBHS_PORTSC1 |= USBHS_PORTSC_PHCD; // phy off | ||||
//println("USBHS_ASYNCLISTADDR = ", USBHS_ASYNCLISTADDR, HEX); | |||||
//println("USBHS_PERIODICLISTBASE = ", USBHS_PERIODICLISTBASE, HEX); | |||||
//println("periodictable = ", (uint32_t)periodictable, HEX); | |||||
println("USBHS_ASYNCLISTADDR = ", USBHS_ASYNCLISTADDR, HEX); | |||||
println("USBHS_PERIODICLISTBASE = ", USBHS_PERIODICLISTBASE, HEX); | |||||
println("periodictable = ", (uint32_t)periodictable, HEX); | |||||
// enable interrupts, after this point interruts to all the work | // enable interrupts, after this point interruts to all the work | ||||
attachInterruptVector(IRQ_USBHS, isr); | attachInterruptVector(IRQ_USBHS, isr); |
// Lets also look at HID Input devices | // Lets also look at HID Input devices | ||||
USBHIDInput *hiddrivers[] = {&mouse1, &joystick1, &rawhid1, &rawhid2}; | USBHIDInput *hiddrivers[] = {&mouse1, &joystick1, &rawhid1, &rawhid2}; | ||||
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0])) | #define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0])) | ||||
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1", "RawHid1", "RawHid2"}; | |||||
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1", "Joystick1", "RawHid1", "RawHid2"}; | |||||
bool hid_driver_active[CNT_DEVICES] = {false, false}; | bool hid_driver_active[CNT_DEVICES] = {false, false}; | ||||
bool show_changed_only = false; | |||||
bool show_changed_only = false; | |||||
uint8_t joystick_left_trigger_value = 0; | uint8_t joystick_left_trigger_value = 0; | ||||
uint8_t joystick_right_trigger_value = 0; | uint8_t joystick_right_trigger_value = 0; | ||||
uint64_t joystick_full_notify_mask = (uint64_t)-1; | |||||
uint64_t joystick_full_notify_mask = (uint64_t) - 1; | |||||
void setup() | void setup() | ||||
{ | { | ||||
keyboard2.attachExtrasPress(OnHIDExtrasPress); | keyboard2.attachExtrasPress(OnHIDExtrasPress); | ||||
keyboard2.attachExtrasRelease(OnHIDExtrasRelease); | keyboard2.attachExtrasRelease(OnHIDExtrasRelease); | ||||
// The below forceBootProtocol will force which ever | |||||
// next keyboard that attaches to this device to be in boot protocol | |||||
// Only try this if you run into keyboard with issues. If this is a combined | |||||
// device like wireless mouse and keyboard this can cause mouse problems. | |||||
//keyboard1.forceBootProtocol(); | |||||
rawhid1.attachReceive(OnReceiveHidData); | rawhid1.attachReceive(OnReceiveHidData); | ||||
rawhid2.attachReceive(OnReceiveHidData); | rawhid2.attachReceive(OnReceiveHidData); | ||||
} | } | ||||
myusb.Task(); | myusb.Task(); | ||||
if (Serial.available()) { | if (Serial.available()) { | ||||
int ch = Serial.read(); // get the first char. | |||||
while (Serial.read() != -1) ; | |||||
int ch = Serial.read(); // get the first char. | |||||
while (Serial.read() != -1) ; | |||||
if ((ch == 'b') || (ch == 'B')) { | if ((ch == 'b') || (ch == 'B')) { | ||||
Serial.println("Only notify on Basic Axis changes"); | Serial.println("Only notify on Basic Axis changes"); | ||||
joystick1.axisChangeNotifyMask(0x3ff); | joystick1.axisChangeNotifyMask(0x3ff); | ||||
Serial.println("\n*** Show only changed fields mode ***"); | Serial.println("\n*** Show only changed fields mode ***"); | ||||
} | } | ||||
} | } | ||||
} | |||||
} | |||||
for (uint8_t i = 0; i < CNT_DEVICES; i++) { | for (uint8_t i = 0; i < CNT_DEVICES; i++) { | ||||
if (*drivers[i] != driver_active[i]) { | if (*drivers[i] != driver_active[i]) { | ||||
if (psz && *psz) Serial.printf(" product: %s\n", psz); | if (psz && *psz) Serial.printf(" product: %s\n", psz); | ||||
psz = drivers[i]->serialNumber(); | psz = drivers[i]->serialNumber(); | ||||
if (psz && *psz) Serial.printf(" Serial: %s\n", psz); | if (psz && *psz) Serial.printf(" Serial: %s\n", psz); | ||||
// Note: with some keyboards there is an issue that they don't output in boot protocol mode | |||||
// and may not work. The above code can try to force the keyboard into boot mode, but there | |||||
// are issues with doing this blindly with combo devices like wireless keyboard/mouse, which | |||||
// may cause the mouse to not work. Note: the above id is in the builtin list of | |||||
// vendor IDs that are already forced | |||||
if (drivers[i] == &keyboard1) { | |||||
if (keyboard1.idVendor() == 0x04D9) { | |||||
Serial.println("Gigabyte vendor: force boot protocol"); | |||||
// Gigabyte keyboard | |||||
keyboard1.forceBootProtocol(); | |||||
} | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
if(mouse1.available()) { | |||||
if (mouse1.available()) { | |||||
Serial.print("Mouse: buttons = "); | Serial.print("Mouse: buttons = "); | ||||
Serial.print(mouse1.getButtons()); | Serial.print(mouse1.getButtons()); | ||||
Serial.print(", mouseX = "); | Serial.print(", mouseX = "); | ||||
joystick_left_trigger_value = ltv; | joystick_left_trigger_value = ltv; | ||||
joystick_right_trigger_value = rtv; | joystick_right_trigger_value = rtv; | ||||
joystick1.setRumble(ltv, rtv); | joystick1.setRumble(ltv, rtv); | ||||
} | |||||
} | |||||
break; | break; | ||||
case JoystickController::PS3: | case JoystickController::PS3: | ||||
joystick_left_trigger_value = ltv; | joystick_left_trigger_value = ltv; | ||||
joystick_right_trigger_value = rtv; | joystick_right_trigger_value = rtv; | ||||
joystick1.setRumble(ltv, rtv, 50); | joystick1.setRumble(ltv, rtv, 50); | ||||
} | |||||
} | |||||
break; | break; | ||||
case JoystickController::XBOXONE: | |||||
case JoystickController::XBOX360: | |||||
case JoystickController::XBOXONE: | |||||
case JoystickController::XBOX360: | |||||
ltv = joystick1.getAxis(4); | ltv = joystick1.getAxis(4); | ||||
rtv = joystick1.getAxis(5); | rtv = joystick1.getAxis(5); | ||||
if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) { | if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) { | ||||
joystick_right_trigger_value = rtv; | joystick_right_trigger_value = rtv; | ||||
joystick1.setRumble(ltv, rtv); | joystick1.setRumble(ltv, rtv); | ||||
Serial.printf(" Set Rumble %d %d", ltv, rtv); | Serial.printf(" Set Rumble %d %d", ltv, rtv); | ||||
} | |||||
} | |||||
break; | break; | ||||
} | } | ||||
if (buttons != buttons_prev) { | if (buttons != buttons_prev) { | ||||
if (joystick1.joystickType == JoystickController::PS3) { | if (joystick1.joystickType == JoystickController::PS3) { | ||||
joystick1.setLEDs((buttons>>12) & 0xf); // try to get to TRI/CIR/X/SQuare | |||||
joystick1.setLEDs((buttons >> 12) & 0xf); // try to get to TRI/CIR/X/SQuare | |||||
} else { | } else { | ||||
uint8_t lr = (buttons & 1)? 0xff : 0; | |||||
uint8_t lg = (buttons & 2)? 0xff : 0; | |||||
uint8_t lb = (buttons & 4)? 0xff : 0; | |||||
uint8_t lr = (buttons & 1) ? 0xff : 0; | |||||
uint8_t lg = (buttons & 2) ? 0xff : 0; | |||||
uint8_t lb = (buttons & 4) ? 0xff : 0; | |||||
joystick1.setLEDs(lr, lg, lb); | joystick1.setLEDs(lr, lg, lb); | ||||
} | } | ||||
buttons_prev = buttons; | buttons_prev = buttons; | ||||
if (rawhid1) { | if (rawhid1) { | ||||
int ch; | int ch; | ||||
uint8_t buffer[64]; | uint8_t buffer[64]; | ||||
uint8_t count_chars = 0; | |||||
uint8_t count_chars = 0; | |||||
memset(buffer, 0, sizeof(buffer)); | memset(buffer, 0, sizeof(buffer)); | ||||
if (Serial.available()) { | if (Serial.available()) { | ||||
while (((ch = Serial.read()) != -1) && (count_chars < sizeof(buffer))) { | while (((ch = Serial.read()) != -1) && (count_chars < sizeof(buffer))) { | ||||
//Serial.print((char)keyboard2.getKey()); | //Serial.print((char)keyboard2.getKey()); | ||||
//Serial.println(); | //Serial.println(); | ||||
} | } | ||||
void OnHIDExtrasPress(uint32_t top, uint16_t key) | |||||
void OnHIDExtrasPress(uint32_t top, uint16_t key) | |||||
{ | { | ||||
Serial.print("HID ("); | Serial.print("HID ("); | ||||
Serial.print(top, HEX); | Serial.print(top, HEX); | ||||
Serial.println(); | Serial.println(); | ||||
} | } | ||||
void OnHIDExtrasRelease(uint32_t top, uint16_t key) | |||||
void OnHIDExtrasRelease(uint32_t top, uint16_t key) | |||||
{ | { | ||||
Serial.print("HID ("); | Serial.print("HID ("); | ||||
Serial.print(top, HEX); | Serial.print(top, HEX); | ||||
bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) { | bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) { | ||||
// Called for maybe both HIDS for rawhid basic test. One is for the Teensy | // Called for maybe both HIDS for rawhid basic test. One is for the Teensy | ||||
// to output to Serial. while still having Raw Hid... | |||||
// to output to Serial. while still having Raw Hid... | |||||
if (usage == 0xffc90004) { | if (usage == 0xffc90004) { | ||||
// Lets trim off trailing null characters. | // Lets trim off trailing null characters. | ||||
while ((len > 0) && (data[len-1] == 0)) { | |||||
while ((len > 0) && (data[len - 1] == 0)) { | |||||
len--; | len--; | ||||
} | } | ||||
if (len) { | if (len) { | ||||
Serial.print("RawHID data: "); | Serial.print("RawHID data: "); | ||||
Serial.println(usage, HEX); | Serial.println(usage, HEX); | ||||
while (len) { | while (len) { | ||||
uint8_t cb = (len > 16)? 16 : len; | |||||
uint8_t cb = (len > 16) ? 16 : len; | |||||
const uint8_t *p = data; | const uint8_t *p = data; | ||||
uint8_t i; | uint8_t i; | ||||
for (i = 0; i < cb; i++) { | for (i = 0; i < cb; i++) { | ||||
} | } | ||||
Serial.print(": "); | Serial.print(": "); | ||||
for (i = 0; i < cb; i++) { | for (i = 0; i < cb; i++) { | ||||
Serial.write(((*data >= ' ')&&(*data <= '~'))? *data : '.'); | |||||
Serial.write(((*data >= ' ') && (*data <= '~')) ? *data : '.'); | |||||
data++; | data++; | ||||
} | } | ||||
len -= cb; | len -= cb; | ||||
} | } | ||||
return true; | return true; | ||||
} | |||||
} |
uint8_t charNumlockOn; // We will assume when num lock is on we have all characters... | uint8_t charNumlockOn; // We will assume when num lock is on we have all characters... | ||||
} keycode_numlock_t; | } keycode_numlock_t; | ||||
typedef struct { | |||||
uint16_t idVendor; // vendor id of keyboard | |||||
uint16_t idProduct; // product id - 0 implies all of the ones from vendor; | |||||
} keyboard_force_boot_protocol_t; // list of products to force into boot protocol | |||||
#ifdef M | #ifdef M | ||||
#undef M | #undef M | ||||
#endif | #endif | ||||
#define M(n) ((n) & KEYCODE_MASK) | #define M(n) ((n) & KEYCODE_MASK) | ||||
keycode_extra_t keycode_extras[] = { | |||||
static const keycode_extra_t keycode_extras[] = { | |||||
{M(KEY_ENTER), '\n'}, | {M(KEY_ENTER), '\n'}, | ||||
{M(KEY_ESC), 0x1b}, | {M(KEY_ESC), 0x1b}, | ||||
{M(KEY_TAB), 0x9 }, | {M(KEY_TAB), 0x9 }, | ||||
}; | }; | ||||
// Some of these mapped to key + shift. | // Some of these mapped to key + shift. | ||||
keycode_numlock_t keycode_numlock[] = { | |||||
static const keycode_numlock_t keycode_numlock[] = { | |||||
{M(KEYPAD_SLASH), '/', '/'}, | {M(KEYPAD_SLASH), '/', '/'}, | ||||
{M(KEYPAD_ASTERIX), '*', '*'}, | {M(KEYPAD_ASTERIX), '*', '*'}, | ||||
{M(KEYPAD_MINUS), '-', '-'}, | {M(KEYPAD_MINUS), '-', '-'}, | ||||
{M(KEYPAD_PERIOD), 0x80 | M(KEY_DELETE), '.'} | {M(KEYPAD_PERIOD), 0x80 | M(KEY_DELETE), '.'} | ||||
}; | }; | ||||
static const keyboard_force_boot_protocol_t keyboard_forceBootMode[] = { | |||||
{0x04D9, 0} | |||||
}; | |||||
#define print USBHost::print_ | #define print USBHost::print_ | ||||
#define println USBHost::println_ | #define println USBHost::println_ | ||||
driver_ready_for_device(this); | driver_ready_for_device(this); | ||||
USBHIDParser::driver_ready_for_hid_collection(this); | USBHIDParser::driver_ready_for_hid_collection(this); | ||||
BluetoothController::driver_ready_for_bluetooth(this); | BluetoothController::driver_ready_for_bluetooth(this); | ||||
force_boot_protocol = false; // start off assuming not | |||||
} | } | ||||
bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) | bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) | ||||
// only claim at interface level | // only claim at interface level | ||||
if (type != 1) return false; | if (type != 1) return false; | ||||
if (len < 9+9+7) return false; | if (len < 9+9+7) return false; | ||||
print_hexbytes(descriptors, len); | |||||
uint32_t numendpoint = descriptors[4]; | uint32_t numendpoint = descriptors[4]; | ||||
if (numendpoint < 1) return false; | if (numendpoint < 1) return false; | ||||
datapipe->callback_function = callback; | datapipe->callback_function = callback; | ||||
queue_Data_Transfer(datapipe, report, 8, this); | queue_Data_Transfer(datapipe, report, 8, this); | ||||
mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT | |||||
// see if this device in list of devices that need to be set in | |||||
// boot protocol mode | |||||
bool in_forceBoot_mode_list = false; | |||||
for (uint8_t i = 0; i < sizeof(keyboard_forceBootMode)/sizeof(keyboard_forceBootMode[0]); i++) { | |||||
if (dev->idVendor == keyboard_forceBootMode[i].idVendor) { | |||||
if ((dev->idProduct == keyboard_forceBootMode[i].idProduct) || | |||||
(keyboard_forceBootMode[i].idProduct == 0)) { | |||||
in_forceBoot_mode_list = true; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
if (in_forceBoot_mode_list) { | |||||
println("SET_PROTOCOL Boot"); | |||||
mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT | |||||
} else { | |||||
mk_setup(setup, 0x21, 10, 0, 0, 0); // 10=SET_IDLE | |||||
} | |||||
queue_Control_Transfer(dev, &setup, NULL, this); | queue_Control_Transfer(dev, &setup, NULL, this); | ||||
control_queued = true; | |||||
return true; | return true; | ||||
} | } | ||||
void KeyboardController::control(const Transfer_t *transfer) | void KeyboardController::control(const Transfer_t *transfer) | ||||
{ | { | ||||
println("control callback (keyboard)"); | println("control callback (keyboard)"); | ||||
control_queued = false; | |||||
print_hexbytes(transfer->buffer, transfer->length); | print_hexbytes(transfer->buffer, transfer->length); | ||||
// To decode hex dump to human readable HID report summary: | // To decode hex dump to human readable HID report summary: | ||||
// http://eleccelerator.com/usbdescreqparser/ | // http://eleccelerator.com/usbdescreqparser/ | ||||
uint32_t mesg = transfer->setup.word1; | uint32_t mesg = transfer->setup.word1; | ||||
println(" mesg = ", mesg, HEX); | println(" mesg = ", mesg, HEX); | ||||
if (mesg == 0x001021 && transfer->length == 0) { // SET_PROTOCOL | |||||
if (mesg == 0x00B21 && transfer->length == 0) { // SET_PROTOCOL | |||||
mk_setup(setup, 0x21, 10, 0, 0, 0); // 10=SET_IDLE | mk_setup(setup, 0x21, 10, 0, 0, 0); // 10=SET_IDLE | ||||
control_queued = true; | |||||
queue_Control_Transfer(device, &setup, NULL, this); | queue_Control_Transfer(device, &setup, NULL, this); | ||||
} else if (force_boot_protocol) { | |||||
forceBootProtocol(); // lets setup to do the boot protocol | |||||
force_boot_protocol = false; // turn back off | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void KeyboardController::forceBootProtocol() | |||||
{ | |||||
if (device && !control_queued) { | |||||
mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT | |||||
control_queued = true; | |||||
queue_Control_Transfer(device, &setup, NULL, this); | |||||
} else { | |||||
force_boot_protocol = true; // let system know we want to force this. | |||||
} | |||||
} | |||||
void KeyboardController::disconnect() | void KeyboardController::disconnect() | ||||
{ | { | ||||
// TODO: free resources | // TODO: free resources | ||||
{ | { | ||||
//btdevice = nullptr; | //btdevice = nullptr; | ||||
//***************************************************************************** | |||||
// Some simple query functions depend on which interface we are using... | |||||
//***************************************************************************** | |||||
uint16_t KeyboardController::idVendor() | |||||
{ | |||||
if (device != nullptr) return device->idVendor; | |||||
if (mydevice != nullptr) return mydevice->idVendor; | |||||
return 0; | |||||
} | |||||
uint16_t KeyboardController::idProduct() | |||||
{ | |||||
if (device != nullptr) return device->idProduct; | |||||
if (mydevice != nullptr) return mydevice->idProduct; | |||||
return 0; | |||||
} | |||||
const uint8_t *KeyboardController::manufacturer() | |||||
{ | |||||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; | |||||
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; | |||||
return nullptr; | |||||
} | |||||
const uint8_t *KeyboardController::product() | |||||
{ | |||||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; | |||||
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; | |||||
return nullptr; | |||||
} | |||||
const uint8_t *KeyboardController::serialNumber() | |||||
{ | |||||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; | |||||
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; | |||||
return nullptr; | |||||
} | } | ||||
numLock KEYWORD2 | numLock KEYWORD2 | ||||
capsLock KEYWORD2 | capsLock KEYWORD2 | ||||
scrollLock KEYWORD2 | scrollLock KEYWORD2 | ||||
forceBootProtocol KEYWORD2 | |||||
# MIDIDevice | # MIDIDevice | ||||
getType KEYWORD2 | getType KEYWORD2 |
#ifndef IMXRT_USBHS_H_ | |||||
#define IMXRT_USBHS_H_ | |||||
#if defined(__IMXRT1052__) || defined(__IMXRT1062__) | |||||
// Allow USB host code written for "USBHS" on Teensy 3.6 to compile for "USB2" on Teensy 4.0 | |||||
#define IRQ_USBHS IRQ_USB2 | |||||
#define USBPHY_CTRL USBPHY2_CTRL | |||||
#define USBPHY_CTRL_CLR USBPHY2_CTRL_CLR | |||||
#define USBPHY_CTRL_SET USBPHY2_CTRL_SET | |||||
#define USBHS_USBCMD USB2_USBCMD | |||||
#define USBHS_USBSTS USB2_USBSTS | |||||
#define USBHS_USBINTR USB2_USBINTR | |||||
#define USBHS_FRINDEX USB2_FRINDEX | |||||
#define USBHS_PERIODICLISTBASE USB2_PERIODICLISTBASE | |||||
#define USBHS_ASYNCLISTADDR USB2_ASYNCLISTADDR | |||||
#define USBHS_PORTSC1 USB2_PORTSC1 | |||||
#define USBHS_USBMODE USB2_USBMODE | |||||
#define USBHS_GPTIMER0CTL USB2_GPTIMER0CTRL | |||||
#define USBHS_GPTIMER0LD USB2_GPTIMER0LD | |||||
#define USBHS_GPTIMER1CTL USB2_GPTIMER1CTRL | |||||
#define USBHS_GPTIMER1LD USB2_GPTIMER1LD | |||||
#define USBHS_USBCMD_ASE USB_USBCMD_ASE | |||||
#define USBHS_USBCMD_IAA USB_USBCMD_IAA | |||||
#define USBHS_USBCMD_RST USB_USBCMD_RST | |||||
#define USBHS_USBCMD_ITC(n) USB_USBCMD_ITC(n) | |||||
#define USBHS_USBCMD_RS USB_USBCMD_RS | |||||
#define USBHS_USBCMD_ASP(n) USB_USBCMD_ASP(n) | |||||
#define USBHS_USBCMD_ASPE USB_USBCMD_ASPE | |||||
#define USBHS_USBCMD_PSE USB_USBCMD_PSE | |||||
#define USBHS_USBCMD_FS2 USB_USBCMD_FS_2 | |||||
#define USBHS_USBCMD_FS(n) USB_USBCMD_FS_1(n) | |||||
#define USBHS_USBSTS_AAI USB_USBSTS_AAI | |||||
#define USBHS_USBSTS_AS USB_USBSTS_AS | |||||
// UAI & UPI bits are undocumented in IMXRT, K66 pg 1602, RT1050 pg 2374 | |||||
#define USBHS_USBSTS_UAI ((uint32_t)(1<<18)) | |||||
#define USBHS_USBSTS_UPI ((uint32_t)(1<<19)) | |||||
#define USBHS_USBSTS_UEI USB_USBSTS_UEI | |||||
#define USBHS_USBSTS_PCI USB_USBSTS_PCI | |||||
#define USBHS_USBSTS_TI0 USB_USBSTS_TI0 | |||||
#define USBHS_USBSTS_TI1 USB_USBSTS_TI1 | |||||
#define USBHS_USBSTS_SEI USB_USBSTS_SEI | |||||
#define USBHS_USBSTS_URI USB_USBSTS_URI | |||||
#define USBHS_USBSTS_SLI USB_USBSTS_SLI | |||||
#define USBHS_USBSTS_HCH USB_USBSTS_HCH | |||||
#define USBHS_USBSTS_NAKI USB_USBSTS_NAKI | |||||
#define USBHS_USBINTR_PCE USB_USBINTR_PCE | |||||
#define USBHS_USBINTR_TIE0 USB_USBINTR_TIE0 | |||||
#define USBHS_USBINTR_TIE1 USB_USBINTR_TIE1 | |||||
#define USBHS_USBINTR_UEE USB_USBINTR_UEE | |||||
#define USBHS_USBINTR_SEE USB_USBINTR_SEE | |||||
#define USBHS_USBINTR_UPIE USB_USBINTR_UPIE | |||||
#define USBHS_USBINTR_UAIE USB_USBINTR_UAIE | |||||
#define USBHS_PORTSC_PP USB_PORTSC1_PP | |||||
#define USBHS_PORTSC_OCC USB_PORTSC1_OCC | |||||
#define USBHS_PORTSC_PEC USB_PORTSC1_PEC | |||||
#define USBHS_PORTSC_CSC USB_PORTSC1_CSC | |||||
#define USBHS_PORTSC_CCS USB_PORTSC1_CCS | |||||
#define USBHS_PORTSC_PE USB_PORTSC1_PE | |||||
#define USBHS_PORTSC_HSP USB_PORTSC1_HSP | |||||
#define USBHS_PORTSC_FPR USB_PORTSC1_FPR | |||||
#define USBHS_PORTSC_PR USB_PORTSC1_PR | |||||
#define USBHS_GPTIMERCTL_RST USB_GPTIMERCTRL_GPTRST | |||||
#define USBHS_GPTIMERCTL_RUN USB_GPTIMERCTRL_GPTRUN | |||||
#define USBHS_USBMODE_CM(n) USB_USBMODE_CM(n) | |||||
// TODO: what is the best setting for this register on IMXRT ??? | |||||
#define USBHS_USB_SBUSCFG USB2_SBUSCFG | |||||
#endif // __IMXRT1052__ or __IMXRT1062__ | |||||
#endif // IMXRT_USBHS_H_ |