bool WEAK CDC_Setup(Setup& setup) { u8 r = setup.bRequest; u8 requestType = setup.bmRequestType; if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) { if (CDC_GET_LINE_CODING == r) { USB_SendControl(0,(void*)&_usbLineInfo,7); return true; } } if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) { if (CDC_SET_LINE_CODING == r) { USB_RecvControl((void*)&_usbLineInfo,7); return true; } if (CDC_SET_CONTROL_LINE_STATE == r) { _usbLineInfo.lineState = setup.wValueL; if(1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) { // auto-reset is triggered when the port, already open at 1200 bps, is closed Reboot(); } return true; } } return false; }
bool WEAK CDC_SendDeviceDescriptor(uint8_t nLen) { if(nLen < sizeof(_cdcDeviceDescriptor)) { nLen = sizeof(_cdcDeviceDescriptor); } return 0 != USB_SendControl(TRANSFER_PGM | TRANSFER_RELEASE, &_cdcDeviceDescriptor, nLen); }
bool CDC_Setup(USBSetup& setup) { u8 r = setup.bRequest; u8 requestType = setup.bmRequestType; if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) { if (CDC_GET_LINE_CODING == r) { USB_SendControl(0,(void*)&_usbLineInfo,7); return true; } } if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) { if (CDC_SET_LINE_CODING == r) { USB_RecvControl((void*)&_usbLineInfo,7); } if (CDC_SET_CONTROL_LINE_STATE == r) { _usbLineInfo.lineState = setup.wValueL; } if (CDC_SET_LINE_CODING == r || CDC_SET_CONTROL_LINE_STATE == r) { // auto-reset into the bootloader is triggered when the port, already // open at 1200 bps, is closed. this is the signal to start the watchdog // with a relatively long period so it can finish housekeeping tasks // like servicing endpoints before the sketch ends // We check DTR state to determine if host port is open (bit 0 of lineState). if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) { *(uint16_t *)(RAMEND-1) = *(uint16_t *)0x0800; *(uint16_t *)0x0800 = 0x7777; wdt_enable(WDTO_120MS); } else { // Most OSs do some intermediate steps when configuring ports and DTR can // twiggle more than once before stabilizing. // To avoid spurious resets we set the watchdog to 250ms and eventually // cancel if DTR goes back high. wdt_disable(); wdt_reset(); *(uint16_t *)0x0800 = *(uint16_t *)(RAMEND-1); } } return true; } return false; }
int SingleAbsoluteMouse_::getInterface(uint8_t* interfaceCount) { *interfaceCount += 1; // uses 1 HIDDescriptor hidInterface = { D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), D_HIDREPORT(sizeof(_hidSingleReportDescriptorAbsoluteMouse)), D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) }; return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); }
static bool SendConfiguration(int maxlen) { InitControl(0); uint8_t interfaces = SendInterfaces(); ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor), interfaces); InitControl(maxlen); USB_SendControl(0,&config,sizeof(ConfigDescriptor)); SendInterfaces(); return (true); }
static bool SendDescriptor(USBSetup& setup) { int ret; u8 t = setup.wValueH; if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) return SendConfiguration(setup.wLength); InitControl(setup.wLength); #ifdef PLUGGABLE_USB_ENABLED ret = PluggableUSB().getDescriptor(setup); if (ret != 0) { return (ret > 0 ? true : false); } #endif const u8* desc_addr = 0; if (USB_DEVICE_DESCRIPTOR_TYPE == t) { if (setup.wLength == 8) _cdcComposite = 1; desc_addr = _cdcComposite ? (const u8*)&USB_DeviceDescriptorB : (const u8*)&USB_DeviceDescriptor; } else if (USB_STRING_DESCRIPTOR_TYPE == t) { if (setup.wValueL == 0) { desc_addr = (const u8*)&STRING_LANGUAGE; } else if (setup.wValueL == IPRODUCT) { return USB_SendStringDescriptor(STRING_PRODUCT, strlen(USB_PRODUCT), TRANSFER_PGM); } else if (setup.wValueL == IMANUFACTURER) { return USB_SendStringDescriptor(STRING_MANUFACTURER, strlen(USB_MANUFACTURER), TRANSFER_PGM); } else if (setup.wValueL == ISERIAL) { #ifdef PLUGGABLE_USB_ENABLED char name[ISERIAL_MAX_LEN]; PluggableUSB().getShortName(name); return USB_SendStringDescriptor((uint8_t*)name, strlen(name), 0); #endif } else return false; } if (desc_addr == 0) return false; u8 desc_length = pgm_read_byte(desc_addr); USB_SendControl(TRANSFER_PGM,desc_addr,desc_length); return true; }
// Construct a dynamic configuration descriptor // This really needs dynamic endpoint allocation etc // TODO static bool SendConfiguration(int maxlen) { // Count and measure interfaces InitControl(0); int interfaces = SendInterfaces(); ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); // Now send them InitControl(maxlen); USB_SendControl(0,&config,sizeof(ConfigDescriptor)); SendInterfaces(); return true; }
int SingleAbsoluteMouse_::getDescriptor(USBSetup& setup) { // Check if this is a HID Class Descriptor request if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } // In a HID Class Descriptor wIndex cointains the interface number if (setup.wIndex != pluggedInterface) { return 0; } // Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol // due to the USB specs, but Windows and Linux just assumes its in report mode. protocol = HID_REPORT_PROTOCOL; return USB_SendControl(TRANSFER_PGM, _hidSingleReportDescriptorAbsoluteMouse, sizeof(_hidSingleReportDescriptorAbsoluteMouse)); }
static bool SendDescriptor(Setup& setup) { // DEBUG_OUT(F("USB SendDescriptor\r\n")); #ifdef LED_SIGNAL1 digitalWrite(LED_SIGNAL1,digitalRead(LED_SIGNAL1) == LOW ? HIGH : LOW); #endif // LED_SIGNAL1 u8 t = setup.wValueH; if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) return SendConfiguration(setup.wLength); InitControl(setup.wLength); #ifdef HID_ENABLED if (HID_REPORT_DESCRIPTOR_TYPE == t) return HID_GetDescriptor(t); #endif u8 desc_length = 0; const u8* desc_addr = 0; if (USB_DEVICE_DESCRIPTOR_TYPE == t) { if (setup.wLength == 8) _cdcComposite = 1; desc_addr = _cdcComposite ? (const u8*)&USB_DeviceDescriptorA : (const u8*)&USB_DeviceDescriptor; } else if (USB_STRING_DESCRIPTOR_TYPE == t) { if (setup.wValueL == 0) desc_addr = (const u8*)&STRING_LANGUAGE; else if (setup.wValueL == IPRODUCT) desc_addr = (const u8*)&STRING_IPRODUCT; else if (setup.wValueL == IMANUFACTURER) desc_addr = (const u8*)&STRING_IMANUFACTURER; else return false; } if (desc_addr == 0) return false; if (desc_length == 0) desc_length = pgm_read_byte(desc_addr); USB_SendControl(TRANSFER_PGM,desc_addr,desc_length); return true; }
static bool SendDescriptor(Setup& setup) { u8 t = setup.wValueH; if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) return SendConfiguration(setup.wLength); InitControl(setup.wLength); #ifdef HID_ENABLED if (HID_REPORT_DESCRIPTOR_TYPE == t) return HID_GetDescriptor(t); #endif const u8* desc_addr = 0; if (USB_DEVICE_DESCRIPTOR_TYPE == t) { if (setup.wLength == 8) _cdcComposite = 1; desc_addr = _cdcComposite ? (const u8*)&USB_DeviceDescriptorA : (const u8*)&USB_DeviceDescriptor; } else if (USB_STRING_DESCRIPTOR_TYPE == t) { if (setup.wValueL == 0) { desc_addr = (const u8*)&STRING_LANGUAGE; } else if (setup.wValueL == IPRODUCT) { return USB_SendStringDescriptor(STRING_PRODUCT, strlen(USB_PRODUCT)); } else if (setup.wValueL == IMANUFACTURER) { return USB_SendStringDescriptor(STRING_MANUFACTURER, strlen(USB_MANUFACTURER)); } else return false; } if (desc_addr == 0) return false; u8 desc_length = pgm_read_byte(desc_addr); USB_SendControl(TRANSFER_PGM,desc_addr,desc_length); return true; }
int UsbMidiModule::getInterface(uint8_t *interfaceCount) { *interfaceCount += 2; u8 desc[] = { D_AUDIO_CONTROL_INTERFACE(pluggedInterface), D_AUDIO_CONTROL_INTERFACE_SPC(0x03), D_AUDIO_STREAM_INTERFACE(pluggedInterface + 1), D_AUDIO_STREAM_INTERFACE_SPC(0x41), D_MIDI_IN_JACK(D_JACK_TYPE_EMBEDDED, 0x01), D_MIDI_IN_JACK(D_JACK_TYPE_EXTERNAL, 0x02), D_MIDI_OUT_JACK(D_JACK_TYPE_EMBEDDED, 0x03, 0x02, 0x01), D_MIDI_OUT_JACK(D_JACK_TYPE_EXTERNAL, 0x04, 0x01, 0x01), D_MIDI_JACK_EP(D_ENDPOINT_OUT | getOutEndpointId()), D_MIDI_JACK_EP_SPC(0x01), D_MIDI_JACK_EP(D_ENDPOINT_IN | getInEndpointId()), D_MIDI_JACK_EP_SPC(0x03), }; return USB_SendControl(0, desc, sizeof(desc)); }
static bool SendDescriptor(Setup& setup) { uint8_t t = setup.wValueH; if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) return (SendConfiguration(setup.wLength)); InitControl(setup.wLength); #ifdef HID_ENABLED if (HID_REPORT_DESCRIPTOR_TYPE == t) return (HID_GetDescriptor(t)); #endif uint8_t desc_length = 0; const uint8_t* desc_addr = 0; if (USB_DEVICE_DESCRIPTOR_TYPE == t) { if (setup.wLength == 8) _cdcComposite = 1; desc_addr = _cdcComposite ? (const uint8_t*)&USB_DeviceDescriptorA : (const uint8_t*)&USB_DeviceDescriptor; } else if (USB_STRING_DESCRIPTOR_TYPE == t) { if (setup.wValueL == 0) desc_addr = (const uint8_t*)&STRING_LANGUAGE; else if (setup.wValueL == IPRODUCT) desc_addr = (const uint8_t*)&STRING_IPRODUCT; else if (setup.wValueL == IMANUFACTURER) desc_addr = (const uint8_t*)&STRING_IMANUFACTURER; else return (false); } if (desc_addr == 0) return (false); if (desc_length == 0) desc_length = pgm_read_byte(desc_addr); USB_SendControl(TRANSFER_PGM,desc_addr,desc_length); return (true); }
int HID_::getDescriptor(USBSetup& setup) { // Check if this is a HID Class Descriptor request if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } // In a HID Class Descriptor wIndex cointains the interface number if (setup.wIndex != pluggedInterface) { return 0; } int total = 0; HIDSubDescriptor* node; for (node = rootNode; node; node = node->next) { int res = USB_SendControl(TRANSFER_PGM, node->data, node->length); if (res == -1) return -1; total += res; } // Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol // due to the USB specs, but Windows and Linux just assumes its in report mode. protocol = HID_REPORT_PROTOCOL; return total; }
bool WEAK CDC_SendIAD(void) { return USB_SendControl(TRANSFER_PGM, &_cdcIADDesc, sizeof(_cdcIADDesc)) != 0; }
int WEAK MIDI_GetInterface(u8* interfaceNum) { interfaceNum[0] += 1; // uses 1 return USB_SendControl(TRANSFER_PGM,&_midiInterface,sizeof(_midiInterface)); }
int WEAK HID_GetInterface(u8* interfaceNum) { interfaceNum[0] += 1; // uses 1 return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface)); }
int WEAK HID_GetDescriptor(int i) { return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor)); }
bool CDC_Setup(USBSetup& setup) { u8 r = setup.bRequest; u8 requestType = setup.bmRequestType; if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) { if (CDC_GET_LINE_CODING == r) { USB_SendControl(0,(void*)&_usbLineInfo,7); return true; } } if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) { if (CDC_SEND_BREAK == r) { breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; } if (CDC_SET_LINE_CODING == r) { USB_RecvControl((void*)&_usbLineInfo,7); } if (CDC_SET_CONTROL_LINE_STATE == r) { _usbLineInfo.lineState = setup.wValueL; } if (CDC_SET_LINE_CODING == r || CDC_SET_CONTROL_LINE_STATE == r) { // auto-reset into the bootloader is triggered when the port, already // open at 1200 bps, is closed. this is the signal to start the watchdog // with a relatively long period so it can finish housekeeping tasks // like servicing endpoints before the sketch ends uint16_t magic_key_pos = MAGIC_KEY_POS; // If we don't use the new RAMEND directly, check manually if we have a newer bootloader. // This is used to keep compatible with the old leonardo bootloaders. // You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check. #if MAGIC_KEY_POS != (RAMEND-1) // For future boards save the key in the inproblematic RAMEND // Which is reserved for the main() return value (which will never return) if (_updatedLUFAbootloader) { // horray, we got a new bootloader! magic_key_pos = (RAMEND-1); } #endif // We check DTR state to determine if host port is open (bit 0 of lineState). if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) { #if MAGIC_KEY_POS != (RAMEND-1) // Backup ram value if its not a newer bootloader. // This should avoid memory corruption at least a bit, not fully if (magic_key_pos != (RAMEND-1)) { *(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos; } #endif // Store boot key *(uint16_t *)magic_key_pos = MAGIC_KEY; wdt_enable(WDTO_120MS); } else { // Most OSs do some intermediate steps when configuring ports and DTR can // twiggle more than once before stabilizing. // To avoid spurious resets we set the watchdog to 250ms and eventually // cancel if DTR goes back high. wdt_disable(); wdt_reset(); #if MAGIC_KEY_POS != (RAMEND-1) // Restore backed up (old bootloader) magic key data if (magic_key_pos != (RAMEND-1)) { *(uint16_t *)magic_key_pos = *(uint16_t *)(RAMEND-1); } else #endif { // Clean up RAMEND key *(uint16_t *)magic_key_pos = 0x0000; } } } return true; } return false; }
bool CDC_Setup(USBSetup& setup) { u8 r = setup.bRequest; u8 requestType = setup.bmRequestType; if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) { if (CDC_GET_LINE_CODING == r) { USB_SendControl(0,(void*)&_usbLineInfo,7); return true; } } if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) { if (CDC_SEND_BREAK == r) { breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; } if (CDC_SET_LINE_CODING == r) { USB_RecvControl((void*)&_usbLineInfo,7); } if (CDC_SET_CONTROL_LINE_STATE == r) { _usbLineInfo.lineState = setup.wValueL; } if (CDC_SET_LINE_CODING == r || CDC_SET_CONTROL_LINE_STATE == r) { // auto-reset into the bootloader is triggered when the port, already // open at 1200 bps, is closed. this is the signal to start the watchdog // with a relatively long period so it can finish housekeeping tasks // like servicing endpoints before the sketch ends #ifndef MAGIC_KEY #define MAGIC_KEY 0x7777 #endif #ifndef MAGIC_KEY_POS #define MAGIC_KEY_POS 0x0800 #endif // We check DTR state to determine if host port is open (bit 0 of lineState). if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) { #if MAGIC_KEY_POS != (RAMEND-1) *(uint16_t *)(RAMEND-1) = *(uint16_t *)MAGIC_KEY_POS; *(uint16_t *)MAGIC_KEY_POS = MAGIC_KEY; #else // for future boards save the key in the inproblematic RAMEND // which is reserved for the main() return value (which will never return) *(uint16_t *)MAGIC_KEY_POS = MAGIC_KEY; #endif wdt_enable(WDTO_120MS); } else { // Most OSs do some intermediate steps when configuring ports and DTR can // twiggle more than once before stabilizing. // To avoid spurious resets we set the watchdog to 250ms and eventually // cancel if DTR goes back high. wdt_disable(); wdt_reset(); #if MAGIC_KEY_POS != (RAMEND-1) *(uint16_t *)MAGIC_KEY_POS = *(uint16_t *)(RAMEND-1); #else *(uint16_t *)MAGIC_KEY_POS = 0x0000; #endif } } return true; } return false; }
bool WEAK CDC_Setup(Setup& setup) { u8 r = setup.bRequest; u8 requestType = setup.bmRequestType; if(REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) { if (CDC_GET_LINE_CODING == r) { error_printP(F("Get Line Coding")); #if 1 USB_SendControl(0,(void*)&_usbLineInfo, sizeof(_usbLineInfo)/*7*/); #endif // 0 return true; } } else if(REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) { if(CDC_SET_LINE_CODING == r) { error_printP_(F("CDC_SET_LINE_CODING")); // setup packet is followed by data? memcpy((void *)&_usbLineInfo, (char *)&(setup) + sizeof(Setup), sizeof(_usbLineInfo)); error_printP_(F(" rate:")); error_printL_(_usbLineInfo.dwDTERate); error_printP_(F(" fmt:")); error_printL_(_usbLineInfo.bCharFormat); error_printP_(F(" par:")); error_printL_(_usbLineInfo.bParityType); error_printP_(F(" bit:")); error_printL(_usbLineInfo.bDataBits); USB_SendControl(0, NULL, 0); // send a ZLP _cdcLineState = CONTROL_LINE_STATE_DTR; // for now... assume "this" // now set up the ACM interrupt info in '_cdcSerialState' and send it back _cdcSerialState = SERIAL_STATE_TX_CARRIER_DSR; // to tell host "I have data" (always) return true; } else if(CDC_SET_CONTROL_LINE_STATE == r) { error_printP_(F("Set Control Line State: ")); error_printL(setup.wValueL); _cdcLineState = setup.wValueL; // NOTE: this next part is for the 'caterina' CDC bootloader, arduino/bootloaders/caterina/Caterina.c // it has some "special" code in it, like using 0x0800 in RAM as an address for a 'key' (7777H) // to indicate it was soft-booted. XMEGA has better ways of handling this, like a CPU flag that // indicates "I was soft-booted" as one example, and a 'WDT' timeout flag on top of that. // auto-reset into the bootloader is triggered when the port, already // open at 1200 bps, is closed. this is the signal to start the watchdog // with a relatively long period so it can finish housekeeping tasks // like servicing endpoints before the sketch ends if (1200 == _usbLineInfo.dwDTERate) { // We check DTR state to determine if host port is open (bit 0 of _cdcLineState). if ((_cdcLineState & 0x01) == 0) { // This section of code is support for the 'caterina' bootloader, which allows USB flashing (apparently) // // *(uint16_t *)0x0800 = 0x7777; note that on XMEGA this is a VERY bad thing // wdt_enable(WDTO_120MS); // // on the atmega, address 800H is the start of the final 256-byte page in RAM space for 2k RAM // // atmega328(p) RAM goes from 0x100 through 0x8ff - see datasheet for atmega 328 [etc.] section 8.3 // 32U4 RAM goes through 0xaff - see datasheet for U4 processors, section 5.2 // 8/16/32U2 RAM goes through 4FFH so this won't even work - see datasheet for U2 processors, section 7.2 // basically it's a 'hack' and needs to be re-evaluated // TODO: would it be safe to enable interrupts, NOT return from this function, // and simply wait until the appropriate time has elapsed? Or, as is // handled in the section below, this 'wait period' is canceled // TODO: if I use a function that's part of the USB driver to trigger a soft boot, I can detect // that a soft boot has taken place using the bits in the 'RESET' status register. If all // I have to do is detect this, it's not a problem, and I won't need "magic memory locations" // TODO: timeout-based reboot } else { // Most OSs do some intermediate steps when configuring ports and DTR can // twiggle more than once before stabilizing. // To avoid spurious resets we set the watchdog to 250ms and eventually // cancel if DTR goes back high. // This section of code is support for the 'caterina' bootloader, which allows USB flashing (apparently) // // TODO: reset whatever boot timeout I did // wdt_disable(); // wdt_reset(); // *(uint16_t *)0x0800 = 0x0; note that on XMEGA this is a VERY bad thing } } USB_SendControl(0, NULL, 0); // send a ZLP return true; } } // unrecognized request - report it error_printP_(F("CDC request: type=")); error_printL_(requestType); error_printP_(F(" request=")); error_printL(r); return false; }
bool WEAK CDC_SendDeviceDescriptor(void) { return 0 != USB_SendControl(TRANSFER_PGM, &_cdcDeviceDescriptor, sizeof(_cdcDeviceDescriptor)); }
int CDC_GetInterface(uint8_t* interfaceNum) { interfaceNum[0] += 2; return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface)); }
int WEAK CDC_GetInterface(u8* interfaceNum) { interfaceNum[0] += 2; // uses 2 return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface)); }
int WEAK CDC_SendInterfaceData(void) { return USB_SendControl(TRANSFER_PGM, &_cdcInterface, sizeof(_cdcInterface)); }