#include "usb.h" typedef union { uint32_t word; uint16_t halfwords[2]; uint8_t bytes[4]; } usb_data_t; void usb_generic_send(uint8_t* data, uint16_t size, uint32_t *fifo_tx_target) { usb_data_t tx_data; uint8_t subWordBytes = size % 4; uint8_t wordCount = size / 4; for (uint8_t i = 0; i < wordCount; i++) { tx_data.word = *((uint32_t*)data); *fifo_tx_target = tx_data.word; data += 4; } // TODO: check where to put it... beginning, end... if (subWordBytes != 0) { tx_data.word = 0; for (uint8_t i = 0; i < subWordBytes; i++) { tx_data.bytes[i] = *(data + i); } *fifo_tx_target = tx_data.word; } } void usb_generic_read(uint8_t *data, uint16_t size, uint32_t *fifo_rx_source) { usb_data_t rx_data; uint8_t subWordBytes = size % 4; uint8_t wordCount = size / 4; for (uint8_t i = 0; i < wordCount; i++) { rx_data.word = *fifo_rx_source; *((uint32_t*)data) = rx_data.word; data += 4; } // TODO: check where to put it... beginning, end... if (subWordBytes > 0) { rx_data.word = 0; for (uint8_t i = 0; i < subWordBytes; i++) { *(data + i) = rx_data.bytes[i]; } } } void usb_send_descriptor(usb_descriptor_t *descriptor, uint32_t *fifo_tx_target) { usb_generic_send((uint8_t*)descriptor, descriptor->bLength, fifo_tx_target); } void usb_send_configuration_descriptor( usb_configuration_descriptor_t *descriptor, uint32_t *fifo_tx_target) { descriptor->header.bDescriptorType = DESCRIPTOR_CONFIGURATION; descriptor->header.bLength = sizeof(usb_configuration_descriptor_t); usb_send_descriptor(&descriptor->header, fifo_tx_target); } void usb_send_interface_descriptor(usb_interface_descriptor_t *descriptor, uint32_t *fifo_tx_target) { descriptor->header.bDescriptorType = DESCRIPTOR_INTERFACE; descriptor->header.bLength = sizeof(usb_interface_descriptor_t); usb_send_descriptor(&descriptor->header, fifo_tx_target); } void usb_send_endpoint_descriptor(usb_endpoint_descriptor_t *descriptor, uint32_t *fifo_tx_target) { descriptor->header.bDescriptorType = DESCRIPTOR_ENDPOINT; descriptor->header.bLength = sizeof(usb_endpoint_descriptor_t); usb_send_descriptor(&descriptor->header, fifo_tx_target); } void usb_send_string_descriptor_zero(usb_string_descriptor_zero_t *string_descriptor, uint32_t *fifo_tx_target) { usb_data_t data; data.word = 0; data.bytes[0] = string_descriptor->header.bLength; data.bytes[1] = string_descriptor->header.bDescriptorType; if (string_descriptor->header.bLength == 2) { *fifo_tx_target = data.word; return; } data.halfwords[1] = string_descriptor->wLANGID[0]; *fifo_tx_target = data.word; // TODO: Now the rest only from wLANGID[1..] if (string_descriptor->header.bLength > 4) { usb_generic_send((uint8_t *)&string_descriptor->wLANGID[1], string_descriptor->header.bLength - 4, fifo_tx_target); } } void usb_send_unicode_string_descriptor( usb_unicode_string_descriptor_t *string_descriptor, uint32_t *fifo_tx_target) { usb_data_t data = { .word = 0 }; data.halfwords[0] = *((uint16_t*)string_descriptor); if (string_descriptor->bString != 0 && string_descriptor->header.bLength > 2) { // NOTE: if the string had length of just one, there would be two bytes // read here. That shouldn't usually matter much, so we don't care about // that here. data.halfwords[1] = *((uint16_t*)string_descriptor->bString); } *fifo_tx_target = data.word; if (string_descriptor->header.bLength > 4) { usb_generic_send(&string_descriptor->bString[2], string_descriptor->header.bLength - 4, fifo_tx_target); } }