From e1dc17df1ab0ae832c02464d5d170331af8bcfd9 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Tue, 14 Nov 2023 01:12:21 +0800 Subject: [PATCH] Add async_usb_write_XX() --- common_arm/usb_cdc.c | 122 +++++++++++++++++++++++++++++++++++++++++-- common_arm/usb_cdc.h | 5 ++ 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/common_arm/usb_cdc.c b/common_arm/usb_cdc.c index 4787ce112..a1fa96f5d 100644 --- a/common_arm/usb_cdc.c +++ b/common_arm/usb_cdc.c @@ -114,6 +114,7 @@ AT91SAM7S256 USB Device Port #define SET_LINE_CODING 0x2021 #define SET_CONTROL_LINE_STATE 0x2221 +static bool isAsyncRequestFinished = false; static AT91PS_UDP pUdp = AT91C_BASE_UDP; static uint8_t btConfiguration = 0; static uint8_t btConnection = 0; @@ -638,6 +639,10 @@ bool usb_poll(void) { return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank); } +inline uint16_t usb_available_length(void) { + return ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16); +} + /** In github PR #129, some users appears to get a false positive from usb_poll, which returns true, but the usb_read operation @@ -649,7 +654,7 @@ bool usb_poll(void) { bool usb_poll_validate_length(void) { if (!usb_check()) return false; if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false; - return ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16) > 0; + return ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16) > 0; } /* @@ -671,7 +676,7 @@ uint32_t usb_read(uint8_t *data, size_t len) { if (pUdp->UDP_CSR[AT91C_EP_OUT] & bank) { - packetSize = (pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16; + packetSize = ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16); packetSize = MIN(packetSize, len); len -= packetSize; while (packetSize--) @@ -727,7 +732,7 @@ uint32_t usb_read_ng(uint8_t *data, size_t len) { if ((pUdp->UDP_CSR[AT91C_EP_OUT] & bank)) { - uint32_t available = (pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16; + uint32_t available = ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16); packetSize = MIN(available, len); available -= packetSize; len -= packetSize; @@ -821,6 +826,117 @@ int usb_write(const uint8_t *data, const size_t len) { return PM3_SUCCESS; } +/* + *---------------------------------------------------------------------------- + * \fn async_usb_write_start + * \brief Start async write process + * \return PM3_EIO if USB is invalid, PM3_SUCCESS if it is ready for write + * + * This function checks if the USB is connected, and wait until the FIFO + * is ready to be filled. + * + * Warning: usb_write() should not be called between + * async_usb_write_start() and async_usb_write_stop(). + *---------------------------------------------------------------------------- +*/ +int async_usb_write_start(void) { + + if (!usb_check()) return PM3_EIO; + + while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) { + if (!usb_check()) return PM3_EIO; + } + + isAsyncRequestFinished = false; + return PM3_SUCCESS; +} + +/* + *---------------------------------------------------------------------------- + * \fn async_usb_write_pushByte + * \brief Push one byte to the FIFO of IN endpoint (time-critical) + * + * This function simply push a byte to the FIFO of IN endpoint. + * The FIFO size is AT91C_EP_IN_SIZE. Make sure this function is not called + * over AT91C_EP_IN_SIZE times between each async_usb_write_requestWrite(). + *---------------------------------------------------------------------------- +*/ +inline void async_usb_write_pushByte(uint8_t data) { + pUdp->UDP_FDR[AT91C_EP_IN] = data; + isAsyncRequestFinished = false; +} + +/* + *---------------------------------------------------------------------------- + * \fn async_usb_write_requestWrite + * \brief Request a write operation (time-critical) + * \return false if the last write request is not finished, true if success + * + * This function requests a write operation from FIFO to the USB bus, + * and switch the internal banks of FIFO. It doesn't wait for the end of + * transmission from FIFO to the USB bus. + * + * Note: This function doesn't check if the usb is valid, as it is + * time-critical. + *---------------------------------------------------------------------------- +*/ +inline bool async_usb_write_requestWrite(void) { + + // check if last request is finished + if (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) { + return false; + } + + // clear transmission completed flag + UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {}; + + // start of transmission + UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY); + + // hack: no need to wait if UDP_CSR and UDP_FDR are not used immediately. + // while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY)) {}; + isAsyncRequestFinished = true; + return true; +} + +/* + *---------------------------------------------------------------------------- + * \fn async_usb_write_stop + * \brief Stop async write process + * \return PM3_EIO if USB is invalid, PM3_SUCCESS if data is written + * + * This function makes sure the data left in the FIFO is written to the + * USB bus. + * + * Warning: usb_write() should not be called between + * async_usb_write_start() and async_usb_write_stop(). + *---------------------------------------------------------------------------- +*/ +int async_usb_write_stop(void) { + // Wait for the end of transfer + while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) { + if (!usb_check()) return PM3_EIO; + } + + // clear transmission completed flag + UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {}; + + // FIFO is not empty, request a write in non-ping-pong mode + if (isAsyncRequestFinished == false) { + UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY); + + while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) { + if (!usb_check()) return PM3_EIO; + } + + UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {}; + } + return PM3_SUCCESS; +} + /* *---------------------------------------------------------------------------- * \fn AT91F_USB_SendData diff --git a/common_arm/usb_cdc.h b/common_arm/usb_cdc.h index e7f6f3d09..aab8e2c5c 100644 --- a/common_arm/usb_cdc.h +++ b/common_arm/usb_cdc.h @@ -27,9 +27,14 @@ void usb_disable(void); void usb_enable(void); bool usb_check(void); bool usb_poll(void); +uint16_t usb_available_length(void); bool usb_poll_validate_length(void); uint32_t usb_read(uint8_t *data, size_t len); int usb_write(const uint8_t *data, const size_t len); +int async_usb_write_start(void); +void async_usb_write_pushByte(uint8_t data); +bool async_usb_write_requestWrite(void); +int async_usb_write_stop(void); uint32_t usb_read_ng(uint8_t *data, size_t len); void usb_update_serial(uint64_t newSerialNumber);