X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/05b6b117850e7d60a0fb0609550f3c029d98201c..b8ed9975e55c91abfd274e17d3414a31d53fab08:/common/usb_cdc.c diff --git a/common/usb_cdc.c b/common/usb_cdc.c index 91a63cf3..fa26ea7d 100644 --- a/common/usb_cdc.c +++ b/common/usb_cdc.c @@ -33,10 +33,15 @@ */ #include "usb_cdc.h" + +#include +#include +#include + +#include "common.h" #include "at91sam7s512.h" #include "config_gpio.h" - #define AT91C_EP_CONTROL 0 #define AT91C_EP_OUT 1 #define AT91C_EP_IN 2 @@ -49,6 +54,7 @@ #define STR_MANUFACTURER 0x01 #define STR_PRODUCT 0x02 + static const char devDescriptor[] = { /* Device descriptor */ 0x12, // bLength @@ -67,6 +73,7 @@ static const char devDescriptor[] = { 0x01 // bNumConfigs }; + static const char cfgDescriptor[] = { /* ============== CONFIGURATION 1 =========== */ /* Configuration 1 descriptor */ @@ -77,8 +84,8 @@ static const char cfgDescriptor[] = { 0x02, // CbNumInterfaces 0x01, // CbConfigurationValue 0x00, // CiConfiguration - 0xC0, // CbmAttributes 0xA0 - 0xFA, // CMaxPower + 0x80, // CbmAttributes (Bus Powered) + 0x4B, // CMaxPower (150mA max current drawn from bus) /* Interface 0 Descriptor: Communication Class Interface */ 0x09, // bLength @@ -157,41 +164,50 @@ static const char cfgDescriptor[] = { 0x00 // bInterval }; + static const char StrDescLanguageCodes[] = { - 4, // Length - 0x03, // Type is string - 0x09, 0x04 // supported language Code 0 = 0x0409 (English) + 4, // Length + 0x03, // Type is string + 0x09, 0x04 // supported language Code 0 = 0x0409 (English) }; + // Note: ModemManager (Linux) ignores Proxmark3 devices by matching the // manufacturer string "proxmark.org". Don't change this. static const char StrDescManufacturer[] = { - 26, // Length - 0x03, // Type is string - 'p', 0x00, - 'r', 0x00, - 'o', 0x00, - 'x', 0x00, - 'm', 0x00, - 'a', 0x00, - 'r', 0x00, - 'k', 0x00, - '.', 0x00, - 'o', 0x00, - 'r', 0x00, - 'g', 0x00 + 26, // Length + 0x03, // Type is string + 'p', 0x00, + 'r', 0x00, + 'o', 0x00, + 'x', 0x00, + 'm', 0x00, + 'a', 0x00, + 'r', 0x00, + 'k', 0x00, + '.', 0x00, + 'o', 0x00, + 'r', 0x00, + 'g', 0x00 }; + static const char StrDescProduct[] = { - 8, // Length - 0x03, // Type is string - 'P', 0x00, - 'M', 0x00, - '3', 0x00 + 20, // Length + 0x03, // Type is string + 'p', 0x00, + 'r', 0x00, + 'o', 0x00, + 'x', 0x00, + 'm', 0x00, + 'a', 0x00, + 'r', 0x00, + 'k', 0x00, + '3', 0x00 }; -const char* getStringDescriptor(uint8_t idx) -{ + +static const char* getStringDescriptor(uint8_t idx) { switch (idx) { case STR_LANGUAGE_CODES: return StrDescLanguageCodes; @@ -204,10 +220,12 @@ const char* getStringDescriptor(uint8_t idx) } } + // Bitmap for all status bits in CSR which must be written as 1 to cause no effect #define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \ - |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \ - |AT91C_UDP_TXCOMP + |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \ + |AT91C_UDP_TXCOMP + // Clear flags in the UDP_CSR register #define UDP_CLEAR_EP_FLAGS(endpoint, flags) { \ @@ -216,7 +234,8 @@ const char* getStringDescriptor(uint8_t idx) reg |= REG_NO_EFFECT_1_ALL; \ reg &= ~(flags); \ pUdp->UDP_CSR[(endpoint)] = reg; \ -} +} + // Set flags in the UDP_CSR register #define UDP_SET_EP_FLAGS(endpoint, flags) { \ @@ -227,6 +246,7 @@ const char* getStringDescriptor(uint8_t idx) pUdp->UDP_CSR[(endpoint)] = reg; \ } + /* USB standard request codes */ #define STD_GET_STATUS_ZERO 0x0080 #define STD_GET_STATUS_INTERFACE 0x0081 @@ -254,6 +274,7 @@ const char* getStringDescriptor(uint8_t idx) #define SET_LINE_CODING 0x2021 #define SET_CONTROL_LINE_STATE 0x2221 + typedef struct { unsigned int dwDTERRate; char bCharFormat; @@ -261,6 +282,7 @@ typedef struct { char bDataBits; } AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING; + AT91S_CDC_LINE_CODING line = { 115200, // baudrate 0, // 1 Stop Bit @@ -268,12 +290,12 @@ AT91S_CDC_LINE_CODING line = { 8}; // 8 Data bits -void AT91F_CDC_Enumerate(); +static void AT91F_CDC_Enumerate(); AT91PS_UDP pUdp = AT91C_BASE_UDP; -byte_t btConfiguration = 0; -byte_t btConnection = 0; -byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0; +uint8_t btConfiguration = 0; +uint8_t btConnection = 0; +uint8_t btReceiveBank = AT91C_UDP_RX_DATA_BK0; //*---------------------------------------------------------------------------- @@ -285,7 +307,7 @@ void usb_disable() { AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU; // Clear all lingering interrupts - if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) { + if (pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) { pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES; } } @@ -316,7 +338,7 @@ void usb_enable() { usb_disable(); // Wait for a short while - for (volatile size_t i=0; i<0x100000; i++); + for (volatile size_t i = 0; i < 0x100000; i++); // Reconnect USB reconnect AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU; @@ -328,7 +350,7 @@ void usb_enable() { //* \fn usb_check //* \brief Test if the device is configured and handle enumeration //*---------------------------------------------------------------------------- -bool usb_check() { +static bool usb_check() { AT91_REG isr = pUdp->UDP_ISR; if (isr & AT91C_UDP_ENDBUSRES) { @@ -348,8 +370,7 @@ bool usb_check() { } -bool usb_poll() -{ +bool usb_poll() { if (!usb_check()) return false; return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank); } @@ -363,29 +384,29 @@ bool usb_poll() that the length available to read is non-zero, thus hopefully fixes the bug. **/ -bool usb_poll_validate_length() -{ +bool usb_poll_validate_length() { if (!usb_check()) return false; if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false; return (pUdp->UDP_CSR[AT91C_EP_OUT] >> 16) > 0; } + //*---------------------------------------------------------------------------- //* \fn usb_read //* \brief Read available data from Endpoint OUT //*---------------------------------------------------------------------------- -uint32_t usb_read(byte_t* data, size_t len) { - byte_t bank = btReceiveBank; +static uint32_t usb_read(uint8_t* data, size_t len) { + uint8_t bank = btReceiveBank; uint32_t packetSize, nbBytesRcv = 0; uint32_t time_out = 0; - + while (len) { if (!usb_check()) break; if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) { packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len); len -= packetSize; - while(packetSize--) + while (packetSize--) data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT]; UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank); if (bank == AT91C_UDP_RX_DATA_BK0) { @@ -406,7 +427,7 @@ uint32_t usb_read(byte_t* data, size_t len) { //* \fn usb_write //* \brief Send through endpoint 2 //*---------------------------------------------------------------------------- -uint32_t usb_write(const byte_t* data, const size_t len) { +static uint32_t usb_write(const uint8_t* data, const size_t len) { size_t length = len; uint32_t cpt = 0; @@ -433,7 +454,8 @@ uint32_t usb_write(const byte_t* data, const size_t len) { if (!usb_check()) return length; } UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) + /* wait */; UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY); } @@ -443,7 +465,8 @@ uint32_t usb_write(const byte_t* data, const size_t len) { } UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) + /* wait */; return length; } @@ -453,9 +476,6 @@ uint32_t usb_write(const byte_t* data, const size_t len) { //* \fn AT91F_USB_SendData //* \brief Send Data through the control endpoint //*---------------------------------------------------------------------------- -unsigned int csrTab[100] = {0x00}; -unsigned char csrIdx = 0; - static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) { uint32_t cpt = 0; AT91_REG csr; @@ -469,7 +489,8 @@ static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t leng if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) { UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) + /* wait */; } UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY); @@ -481,13 +502,14 @@ static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t leng UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0); return; } - } while ( !(csr & AT91C_UDP_TXCOMP) ); + } while (!(csr & AT91C_UDP_TXCOMP)); } while (length); if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) { UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) + /* wait */; } } @@ -496,11 +518,13 @@ static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t leng //* \fn AT91F_USB_SendZlp //* \brief Send zero length packet through the control endpoint //*---------------------------------------------------------------------------- -void AT91F_USB_SendZlp(AT91PS_UDP pUdp) { +static void AT91F_USB_SendZlp(AT91PS_UDP pUdp) { UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY); - while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) ); + while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP)) + /* wait */; UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) + /* wait */; } @@ -508,11 +532,13 @@ void AT91F_USB_SendZlp(AT91PS_UDP pUdp) { //* \fn AT91F_USB_SendStall //* \brief Stall the control endpoint //*---------------------------------------------------------------------------- -void AT91F_USB_SendStall(AT91PS_UDP pUdp) { +static void AT91F_USB_SendStall(AT91PS_UDP pUdp) { UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL); - while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR) ); + while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR)) + /* wait */; UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR); - while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)); + while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)) + /* wait */; } @@ -520,11 +546,11 @@ void AT91F_USB_SendStall(AT91PS_UDP pUdp) { //* \fn AT91F_CDC_Enumerate //* \brief This function is a callback invoked when a SETUP packet is received //*---------------------------------------------------------------------------- -void AT91F_CDC_Enumerate() { - byte_t bmRequestType, bRequest; +static void AT91F_CDC_Enumerate() { + uint8_t bmRequestType, bRequest; uint16_t wValue, wIndex, wLength, wStatus; - if ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) ) + if (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP)) return; bmRequestType = pUdp->UDP_FDR[AT91C_EP_CONTROL]; @@ -536,12 +562,14 @@ void AT91F_CDC_Enumerate() { wLength = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF); wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8); - if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host + if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR); - while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR) ); + while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR)) + /* wait */; } UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP); - while ( (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) ); + while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) + /* wait */; // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1 switch ((bRequest << 8) | bmRequestType) { @@ -578,11 +606,11 @@ void AT91F_CDC_Enumerate() { AT91F_USB_SendData(pUdp, (char *) &(btConfiguration), sizeof(btConfiguration)); break; case STD_GET_STATUS_ZERO: - wStatus = 0; // Device is Bus powered, remote wakeup disabled + wStatus = 0; // Device is Bus powered, remote wakeup disabled AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus)); break; case STD_GET_STATUS_INTERFACE: - wStatus = 0; // reserved for future use + wStatus = 0; // reserved for future use AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus)); break; case STD_GET_STATUS_ENDPOINT: @@ -591,17 +619,15 @@ void AT91F_CDC_Enumerate() { if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) { wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus)); - } - else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) { + } else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) { wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus)); - } - else + } else AT91F_USB_SendStall(pUdp); break; case STD_SET_FEATURE_ZERO: AT91F_USB_SendStall(pUdp); - break; + break; case STD_SET_FEATURE_INTERFACE: AT91F_USB_SendZlp(pUdp); break; @@ -610,13 +636,12 @@ void AT91F_CDC_Enumerate() { if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) { pUdp->UDP_CSR[wIndex] = 0; AT91F_USB_SendZlp(pUdp); - } - else + } else AT91F_USB_SendStall(pUdp); break; case STD_CLEAR_FEATURE_ZERO: AT91F_USB_SendStall(pUdp); - break; + break; case STD_CLEAR_FEATURE_INTERFACE: AT91F_USB_SendZlp(pUdp); break; @@ -637,7 +662,8 @@ void AT91F_CDC_Enumerate() { // handle CDC class requests case SET_LINE_CODING: - while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0) ); + while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0)) + /* wait */; UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0); AT91F_USB_SendZlp(pUdp); break; @@ -650,6 +676,86 @@ void AT91F_CDC_Enumerate() { break; default: AT91F_USB_SendStall(pUdp); - break; + break; } } + + +//*************************************************************************** +// Interface to the main program +//*************************************************************************** + +// The function to receive a command from the client via USB +bool cmd_receive(UsbCommand* cmd) { + + // Check if there is a usb packet available + if (!usb_poll()) + return false; + + // Try to retrieve the available command frame + size_t rxlen = usb_read((uint8_t*)cmd, sizeof(UsbCommand)); + + // Check if the transfer was complete + if (rxlen != sizeof(UsbCommand)) + return false; + + // Received command successfully + return true; +} + + +// The function to send a response to the client via USB +bool cmd_send(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen) { + + UsbResponse txcmd; + + // Compose the outgoing response frame + txcmd.cmd = cmd | CMD_VARIABLE_SIZE_FLAG; + txcmd.arg[0] = arg0; + txcmd.arg[1] = arg1; + txcmd.arg[2] = arg2; + + // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE + if (data) { + datalen = MIN(datalen, USB_CMD_DATA_SIZE); + for (uint16_t i = 0; i < datalen; i++) { + txcmd.d.asBytes[i] = ((uint8_t*)data)[i]; + } + txcmd.datalen = datalen; + } else { + txcmd.datalen = 0; + } + + // Send frame and make sure all bytes are transmitted + size_t tx_size = offsetof(UsbResponse, d) + datalen; + if (usb_write((uint8_t*)&txcmd, tx_size) != 0) return false; + + return true; +} + + +// For compatibility only: legacy function to send a response with fixed size to the client via USB +bool cmd_send_old(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen) { + + UsbCommand txcmd; + + // Compose the outgoing response frame + txcmd.cmd = cmd; + txcmd.arg[0] = arg0; + txcmd.arg[1] = arg1; + txcmd.arg[2] = arg2; + + // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE + if (data) { + datalen = MIN(datalen, USB_CMD_DATA_SIZE); + for (uint16_t i = 0; i < datalen; i++) { + txcmd.d.asBytes[i] = ((uint8_t*)data)[i]; + } + } + + // Send frame and make sure all bytes are transmitted + if (usb_write((uint8_t*)&txcmd, sizeof(UsbCommand)) != 0) return false; + + return true; +} +