static void spiIRQHandler(uint32_t port) { if(port > (NUM_SPIPORTS - 1)) { return; } uint32_t status = GET_REG(SPIRegs[port].status); if(status & (1 << 3)) { spi_info[port].counter++; } if(status & (1 << 1)) { while(TRUE) { // take care of tx if(spi_info[port].txBuffer != NULL) { if(spi_info[port].txCurrentLen < spi_info[port].txTotalLen) { int toTX = spi_info[port].txTotalLen - spi_info[port].txCurrentLen; int canTX = (MAX_TX_BUFFER - TX_BUFFER_LEFT(status)) << spi_info[port].wordSize; if(toTX > canTX) toTX = canTX; spi_txdata(port, spi_info[port].txBuffer, spi_info[port].txCurrentLen, spi_info[port].txCurrentLen+toTX); spi_info[port].txCurrentLen += toTX; } else { spi_info[port].txDone = TRUE; spi_info[port].txBuffer = NULL; } } dorx: // take care of rx if(spi_info[port].rxBuffer == NULL) break; int toRX = spi_info[port].rxTotalLen - spi_info[port].rxCurrentLen; int canRX = GET_BITS(status, 8, 4) << spi_info[port].wordSize; if(toRX > canRX) toRX = canRX; spi_rxdata(port, spi_info[port].rxBuffer, spi_info[port].rxCurrentLen, spi_info[port].rxCurrentLen+toRX); spi_info[port].rxCurrentLen += toRX; if(spi_info[port].rxCurrentLen < spi_info[port].rxTotalLen) break; spi_info[port].rxDone = TRUE; spi_info[port].rxBuffer = NULL; } } else if(status & (1 << 0)) { // jump into middle of the loop to handle rx only, stupidly goto dorx; } // acknowledge interrupt handling complete SET_REG(SPIRegs[port].status, status); }
static void spi_irq_handler(uint32_t i) { SPIStruct *spi = &SPIData[i]; uint32_t status = GET_REG(spi->registers->status); if((status & 1) && !(status & 0x400002)) goto do_rx; else if(!(status & 0x400002)) goto complete; while(TRUE) { if(spi->txBuffer != NULL) { uint32_t avail = MAX_TX_BUFFER - TX_BUFFER_LEFT(status); uint32_t left = spi->txLength - spi->txDone; if(avail > left) avail = left; spi_txdata(spi, spi->txBuffer, spi->txDone, spi->txDone + avail); spi->txDone += avail; if(spi->txDone >= spi->txLength) { spi->txBuffer = NULL; spi->txLength = 0; spi->txDone = 0; spi->config &=~ 0x200000; SET_REG(spi->registers->config, spi->config); } } do_rx: if(spi->rxBuffer != NULL) { uint32_t avail = RX_BUFFER_LEFT(status); uint32_t left = spi->rxLength - spi->rxDone; if(avail > left) avail = left; if(avail > 0) { spi_rxdata(spi, spi->rxBuffer, spi->rxDone, spi->rxDone + avail); spi->rxDone += avail; } spi->rxDone += avail; if(spi->rxDone >= spi->rxLength) { spi->rxBuffer = NULL; spi->rxLength = 0; spi->rxDone = 0; spi->config &=~ 0x81; SET_REG(spi->registers->config, spi->config); } } complete: if(spi->txBuffer == NULL && spi->rxBuffer == NULL) { spi->config &=~ 0x200181; SET_REG(spi->registers->config, spi->config); break; } else break; } SET_REG(spi->registers->status, status); }