static void set_error(uint8_t sra, SerialDriver *sdp) { flagsmask_t sts = 0; uint8_t dor = 0; uint8_t upe = 0; uint8_t fe = 0; #if USE_AVR_USART0 if (&SD1 == sdp) { dor = (1 << DOR0); upe = (1 << UPE0); fe = (1 << FE0); } #endif #if USE_AVR_USART1 if (&SD2 == sdp) { dor = (1 << DOR1); upe = (1 << UPE1); fe = (1 << FE1); } #endif if (sra & dor) sts |= SD_OVERRUN_ERROR; if (sra & upe) sts |= SD_PARITY_ERROR; if (sra & fe) sts |= SD_FRAMING_ERROR; chSysLockFromIsr(); chnAddFlagsI(sdp, sts); chSysUnlockFromIsr(); }
static bool_t outint(SerialDriver *sdp) { if (sdp->com_data != INVALID_SOCKET) { int n; uint8_t data[1]; /* * Input. */ chSysLockFromIsr(); n = sdRequestDataI(sdp); chSysUnlockFromIsr(); if (n < 0) return FALSE; data[0] = (uint8_t)n; n = send(sdp->com_data, data, sizeof(data), 0); switch (n) { case 0: close(sdp->com_data); sdp->com_data = INVALID_SOCKET; chSysLockFromIsr(); chnAddFlagsI(sdp, CHN_DISCONNECTED); chSysUnlockFromIsr(); return FALSE; case INVALID_SOCKET: if (errno == EWOULDBLOCK) return FALSE; close(sdp->com_data); sdp->com_data = INVALID_SOCKET; return FALSE; } return TRUE; } return FALSE; }
/** * @brief Default data received callback. * @details The application must use this function as callback for the OUT * data endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number */ void sduDataReceived(USBDriver *usbp, usbep_t ep) { size_t n, maxsize; SerialUSBDriver *sdup = usbp->out_params[ep - 1U]; if (sdup == NULL) { return; } osalSysLockFromISR(); chnAddFlagsI(sdup, CHN_INPUT_AVAILABLE); /* Writes to the input queue can only happen when there is enough space to hold at least one packet.*/ maxsize = usbp->epc[ep]->out_maxsize; if ((n = iqGetEmptyI(&sdup->iqueue)) >= maxsize) { /* The endpoint cannot be busy, we are in the context of the callback, so a packet is in the buffer for sure.*/ osalSysUnlockFromISR(); n = (n / maxsize) * maxsize; usbPrepareQueuedReceive(usbp, ep, &sdup->iqueue, n); osalSysLockFromISR(); (void) usbStartReceiveI(usbp, ep); } osalSysUnlockFromISR(); }
/** * @brief USB device disconnection handler. * @note If this function is not called from an ISR then an explicit call * to @p osalOsRescheduleS() in necessary afterward. * * @param[in] uhdp pointer to a @p USBHIDDriver object * * @iclass */ void hidDisconnectI(USBHIDDriver *uhdp) { /* Queues reset in order to signal the driver stop to the application.*/ chnAddFlagsI(uhdp, CHN_DISCONNECTED); ibqResetI(&uhdp->ibqueue); obqResetI(&uhdp->obqueue); }
static bool_t inint(SerialDriver *sdp) { if (sdp->com_data != INVALID_SOCKET) { int i; uint8_t data[32]; /* * Input. */ int n = recv(sdp->com_data, data, sizeof(data), 0); switch (n) { case 0: close(sdp->com_data); sdp->com_data = INVALID_SOCKET; chSysLockFromIsr(); chnAddFlagsI(sdp, CHN_DISCONNECTED); chSysUnlockFromIsr(); return FALSE; case INVALID_SOCKET: if (errno == EWOULDBLOCK) return FALSE; close(sdp->com_data); sdp->com_data = INVALID_SOCKET; return FALSE; } for (i = 0; i < n; i++) { chSysLockFromIsr(); sdIncomingDataI(sdp, data[i]); chSysUnlockFromIsr(); } return TRUE; } return FALSE; }
/** * @brief Default data received callback. * @details The application must use this function as callback for the OUT * data endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep OUT endpoint number */ void sduDataReceived(USBDriver *usbp, usbep_t ep) { uint8_t *buf; SerialUSBDriver *sdup = usbp->out_params[ep - 1U]; if (sdup == NULL) { return; } osalSysLockFromISR(); /* Signaling that data is available in the input queue.*/ chnAddFlagsI(sdup, CHN_INPUT_AVAILABLE); /* Posting the filled buffer in the queue.*/ ibqPostFullBufferI(&sdup->ibqueue, usbGetReceiveTransactionSizeX(sdup->config->usbp, sdup->config->bulk_out)); /* The endpoint cannot be busy, we are in the context of the callback, so a packet is in the buffer for sure. Trying to get a free buffer for the next transaction.*/ buf = ibqGetEmptyBufferI(&sdup->ibqueue); if (buf != NULL) { /* Buffer found, starting a new transaction.*/ usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out, buf, SERIAL_USB_BUFFERS_SIZE); } osalSysUnlockFromISR(); }
static bool connint(SerialDriver *sdp) { if (sdp->com_data == INVALID_SOCKET) { struct sockaddr addr; int addrlen = sizeof(addr); if ((sdp->com_data = accept(sdp->com_listen, &addr, &addrlen)) == INVALID_SOCKET) return false; if (ioctlsocket(sdp->com_data, FIONBIO, &nb) != 0) { printf("%s: Unable to setup non blocking mode on data socket\n", sdp->com_name); goto abort; } chSysLockFromISR(); chnAddFlagsI(sdp, CHN_CONNECTED); chSysUnlockFromISR(); return true; } return false; abort: if (sdp->com_listen != INVALID_SOCKET) closesocket(sdp->com_listen); if (sdp->com_data != INVALID_SOCKET) closesocket(sdp->com_data); WSACleanup(); exit(1); }
/** * @brief USB device disconnection handler. * @note If this function is not called from an ISR then an explicit call * to @p osalOsRescheduleS() in necessary afterward. * * @param[in] sdup pointer to a @p SerialUSBDriver object * * @iclass */ void sduDisconnectI(SerialUSBDriver *sdup) { /* Queues reset in order to signal the driver stop to the application.*/ chnAddFlagsI(sdup, CHN_DISCONNECTED); ibqResetI(&sdup->ibqueue); obqResetI(&sdup->obqueue); }
static bool outint(SerialDriver *sdp) { if (sdp->com_data != INVALID_SOCKET) { int n; uint8_t data[1]; /* * Input. */ chSysLockFromISR(); n = sdRequestDataI(sdp); chSysUnlockFromISR(); if (n < 0) return false; data[0] = (uint8_t)n; n = send(sdp->com_data, (char *)data, sizeof(data), 0); switch (n) { case 0: closesocket(sdp->com_data); sdp->com_data = INVALID_SOCKET; chSysLockFromISR(); chnAddFlagsI(sdp, CHN_DISCONNECTED); chSysUnlockFromISR(); return false; case SOCKET_ERROR: if (WSAGetLastError() == WSAEWOULDBLOCK) return false; closesocket(sdp->com_data); sdp->com_data = INVALID_SOCKET; return false; } return true; } return false; }
static bool inint(SerialDriver *sdp) { if (sdp->com_data != INVALID_SOCKET) { int i; uint8_t data[32]; /* * Input. */ int n = recv(sdp->com_data, (char *)data, sizeof(data), 0); switch (n) { case 0: closesocket(sdp->com_data); sdp->com_data = INVALID_SOCKET; chSysLockFromISR(); chnAddFlagsI(sdp, CHN_DISCONNECTED); chSysUnlockFromISR(); return false; case SOCKET_ERROR: if (WSAGetLastError() == WSAEWOULDBLOCK) return false; closesocket(sdp->com_data); sdp->com_data = INVALID_SOCKET; return false; } for (i = 0; i < n; i++) { chSysLockFromISR(); sdIncomingDataI(sdp, data[i]); chSysUnlockFromISR(); } return true; } return false; }
/** * @brief Common IRQ handler. * * @param[in] sdp communication channel associated to the USART */ static void serve_interrupt(SerialDriver *sdp) { USART_TypeDef *u = sdp->usart; uint16_t cr1 = u->CR1; uint16_t sr = u->SR; /* Special case, LIN break detection.*/ if (sr & USART_SR_LBD) { osalSysLockFromISR(); chnAddFlagsI(sdp, SD_BREAK_DETECTED); osalSysUnlockFromISR(); u->SR = ~USART_SR_LBD; } /* Data available.*/ osalSysLockFromISR(); while (sr & USART_SR_RXNE) { /* Error condition detection.*/ if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) set_error(sdp, sr); sdIncomingDataI(sdp, u->DR); sr = u->SR; } osalSysUnlockFromISR(); /* Transmission buffer empty.*/ if ((cr1 & USART_CR1_TXEIE) && (sr & USART_SR_TXE)) { msg_t b; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); u->CR1 = (cr1 & ~USART_CR1_TXEIE) | USART_CR1_TCIE; } else u->DR = b; osalSysUnlockFromISR(); } /* Physical transmission end.*/ if (sr & USART_SR_TC) { osalSysLockFromISR(); chnAddFlagsI(sdp, CHN_TRANSMISSION_END); osalSysUnlockFromISR(); u->CR1 = cr1 & ~(USART_CR1_TXEIE | USART_CR1_TCIE); u->SR = ~USART_SR_TC; } }
/** * @brief USB device configured handler. * * @param[in] usbp pointer to the @p USBDriver object * * @iclass */ void sduConfigureHookI(USBDriver *usbp) { SerialUSBDriver *sdup = usbp->param; sdup->flags = CHN_NO_ERROR; chIQResetI(&sdup->iqueue); chOQResetI(&sdup->oqueue); chnAddFlagsI(sdup, CHN_CONNECTED); }
/** * @brief Common IRQ handler. * * @param[in] sdp communication channel associated to the USART */ static void serve_interrupt(SerialDriver *sdp) { USART_TypeDef *u = sdp->usart; uint32_t cr1 = u->CR1; uint32_t isr; /* Reading and clearing status.*/ isr = u->ISR; u->ICR = isr; /* Error condition detection.*/ if (isr & (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE | USART_ISR_PE)) set_error(sdp, isr); /* Special case, LIN break detection.*/ if (isr & USART_ISR_LBD) { chSysLockFromIsr(); chnAddFlagsI(sdp, SD_BREAK_DETECTED); chSysUnlockFromIsr(); } /* Data available.*/ if (isr & USART_ISR_RXNE) { chSysLockFromIsr(); sdIncomingDataI(sdp, (uint8_t)u->RDR); chSysUnlockFromIsr(); } /* Transmission buffer empty.*/ if ((cr1 & USART_CR1_TXEIE) && (isr & USART_ISR_TXE)) { msg_t b; chSysLockFromIsr(); b = chOQGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); u->CR1 = (cr1 & ~USART_CR1_TXEIE) | USART_CR1_TCIE; } else u->TDR = b; chSysUnlockFromIsr(); } /* Physical transmission end.*/ if (isr & USART_ISR_TC) { chSysLockFromIsr(); chnAddFlagsI(sdp, CHN_TRANSMISSION_END); chSysUnlockFromIsr(); u->CR1 = cr1 & ~USART_CR1_TCIE; } }
/** * @brief Common IRQ handler. * @note Tries hard to clear all the pending interrupt sources, we don't * want to go through the whole ISR and have another interrupt soon * after. * * @param[in] u pointer to an UART I/O block * @param[in] sdp communication channel associated to the UART */ static void serial_serve_interrupt(SerialDriver *sdp) { uint32_t u = sdp->uart; uint16_t mis = HWREG(u + UART_O_MIS); HWREG(u + UART_O_ICR) = mis; /* clear interrupts */ if (mis & (UART_MIS_FEMIS | UART_MIS_PEMIS | UART_MIS_BEMIS | UART_MIS_OEMIS)) { set_error(sdp, mis); } if ((mis & UART_MIS_RXMIS) || (mis & UART_MIS_RTMIS)) { osalSysLockFromISR(); if (iqIsEmptyI(&sdp->iqueue)) { chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); } osalSysUnlockFromISR(); while ((HWREG(u + UART_O_FR) & UART_FR_RXFE) == 0) { osalSysLockFromISR(); if (iqPutI(&sdp->iqueue, HWREG(u + UART_O_DR)) < Q_OK) { chnAddFlagsI(sdp, SD_QUEUE_FULL_ERROR); } osalSysUnlockFromISR(); } } if (mis & UART_MIS_TXMIS) { while ((HWREG(u + UART_O_FR) & UART_FR_TXFF) == 0) { msg_t b; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); osalSysUnlockFromISR(); if (b < Q_OK) { HWREG(u + UART_O_IM) &= ~UART_IM_TXIM; osalSysLockFromISR(); chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); osalSysUnlockFromISR(); break; } HWREG(u + UART_O_DR) = b; } } /* TODO: Physical transmission end. */ }
/** * @brief Common IRQ handler. * @note Tries hard to clear all the pending interrupt sources, we don't * want to go through the whole ISR and have another interrupt soon * after. * * @param[in] u pointer to an UART I/O block * @param[in] sdp communication channel associated to the UART */ static void serial_serve_interrupt(SerialDriver *sdp) { UART_TypeDef *u = sdp->uart; uint16_t mis = u->MIS; u->ICR = mis; /* clear interrupts */ if (mis & (TIVA_MIS_FEMIS | TIVA_MIS_PEMIS | TIVA_MIS_BEMIS | TIVA_MIS_OEMIS)) { set_error(sdp, mis); } if ((mis & TIVA_MIS_RXMIS) || (mis & TIVA_MIS_RTMIS)) { osalSysLockFromISR(); if (iqIsEmptyI(&sdp->iqueue)) { chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); } osalSysUnlockFromISR(); while ((u->FR & TIVA_FR_RXFE) == 0) { osalSysLockFromISR(); if (iqPutI(&sdp->iqueue, u->DR) < Q_OK) { chnAddFlagsI(sdp, SD_OVERRUN_ERROR); } osalSysUnlockFromISR(); } } if (mis & TIVA_MIS_TXMIS) { while ((u->FR & TIVA_FR_TXFF) == 0) { msg_t b; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); osalSysUnlockFromISR(); if (b < Q_OK) { u->IM &= ~TIVA_IM_TXIM; osalSysLockFromISR(); chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); osalSysUnlockFromISR(); break; } u->DR = b; } } }
/** * @brief Common IRQ handler. * @note Tries hard to clear all the pending interrupt sources, we don't * want to go through the whole ISR and have another interrupt soon * after. * * @param[in] u pointer to an UART I/O block * @param[in] sdp communication channel associated to the UART */ static void serve_interrupt(SerialDriver *sdp) { LPC_USART_TypeDef *u = sdp->uart; while (u->INTSTAT) { if (u->INTSTAT & STAT_RXRDY) { chSysLockFromIsr(); if (chIQIsEmptyI(&sdp->iqueue)) chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); if (chIQPutI(&sdp->iqueue, u->RXDATA) < Q_OK) chnAddFlagsI(sdp, SD_OVERRUN_ERROR); chSysUnlockFromIsr(); } if (u->INTSTAT & STAT_TXRDY) { msg_t b; chSysLockFromIsr(); b = chOQGetI(&sdp->oqueue); chSysUnlockFromIsr(); if (b < Q_OK) { u->INTENCLR = STAT_TXRDY; chSysLockFromIsr(); chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); chSysUnlockFromIsr(); break; } else { u->TXDATA = b; } } if (u->INTSTAT & (STAT_OVERRUN | STAT_DELTARXBRK | STAT_FRAMERR | STAT_PARITYERR) ) { IOREG32 stat = u->STAT; set_error(sdp, stat); u->STAT = stat; } } }
/** * @brief Handles outgoing data. * @details Must be called from the output interrupt service routine in order * to get the next byte to be transmitted. * @note In order to gain some performance it is suggested to not use * this function directly but copy this code directly into the * interrupt service routine. * * @param[in] sdp pointer to a @p SerialDriver structure * @return The byte value read from the driver's output queue. * @retval Q_EMPTY if the queue is empty (the lower driver usually * disables the interrupt source when this happens). * * @iclass */ msg_t sdRequestDataI(SerialDriver *sdp) { msg_t b; chDbgCheckClassI(); chDbgCheck(sdp != NULL, "sdRequestDataI"); b = chOQGetI(&sdp->oqueue); if (b < Q_OK) chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return b; }
/** * @brief Handles outgoing data. * @details Must be called from the output interrupt service routine in order * to get the next byte to be transmitted. * @note In order to gain some performance it is suggested to not use * this function directly but copy this code directly into the * interrupt service routine. * * @param[in] sdp pointer to a @p SerialDriver structure * @return The byte value read from the driver's output queue. * @retval MSG_TIMEOUT if the queue is empty (the lower driver usually * disables the interrupt source when this happens). * * @iclass */ msg_t sdRequestDataI(SerialDriver *sdp) { msg_t b; osalDbgCheckClassI(); osalDbgCheck(sdp != NULL); b = oqGetI(&sdp->oqueue); if (b < MSG_OK) chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return b; }
/** * @brief Common TXI IRQ handler. * * @param[in] sdp pointer to a @p SerialDriver object */ static void spc5xx_serve_txi_interrupt(SerialDriver *sdp) { msg_t b; sdp->linflexp->UARTSR.R = SPC5_UARTSR_DTF; b = chOQGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); sdp->linflexp->UARTCR.B.TXEN = 0; } else sdp->linflexp->BDRL.B.DATA0 = b; }
/** * @brief USB device configured handler. * * @param[in] bdup pointer to a @p BulkUSBDriver object * * @iclass */ void bduConfigureHookI(BulkUSBDriver *bdup) { USBDriver *usbp = bdup->config->usbp; chIQResetI(&bdup->iqueue); chOQResetI(&bdup->oqueue); chnAddFlagsI(bdup, CHN_CONNECTED); /* Starts the first OUT transaction immediately.*/ usbPrepareQueuedReceive(usbp, bdup->config->bulk_out, &bdup->iqueue, usbp->epc[bdup->config->bulk_out]->out_maxsize); usbStartReceiveI(usbp, bdup->config->bulk_out); }
/** * @brief USB device configured handler. * * @param[in] sdup pointer to a @p SerialUSBDriver object * * @iclass */ void sduConfigureHookI(SerialUSBDriver *sdup) { USBDriver *usbp = sdup->config->usbp; iqResetI(&sdup->iqueue); oqResetI(&sdup->oqueue); chnAddFlagsI(sdup, CHN_CONNECTED); /* Starts the first OUT transaction immediately.*/ usbPrepareQueuedReceive(usbp, sdup->config->bulk_out, &sdup->iqueue, usbp->epc[sdup->config->bulk_out]->out_maxsize); (void) usbStartReceiveI(usbp, sdup->config->bulk_out); }
/** * @brief Attempts a TX preload */ static void preload(SerialDriver *sdp) { UART_TypeDef *u = sdp->uart; if (u->S1 & UARTx_S1_TDRE) { msg_t b = chOQGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return; } u->D = b; u->C2 |= UARTx_C2_TIE; } }
/** * @brief Error handling routine. * * @param[in] sra USCI status register containing errors * @param[in] sdp pointer to a @p SerialDriver object */ static void set_error(uint16_t sra, SerialDriver * sdp) { eventflags_t sts = 0; if (sra & UCOE) sts |= SD_OVERRUN_ERROR; if (sra & UCPE) sts |= SD_PARITY_ERROR; if (sra & UCFE) sts |= SD_FRAMING_ERROR; osalSysLockFromISR(); chnAddFlagsI(sdp, sts); osalSysUnlockFromISR(); }
/** * @brief Attempts a TX preload. */ static void preload(SerialDriver *sdp) { LPC_USART_TypeDef *u = sdp->uart; if (u->STAT & STAT_TXIDLE) { msg_t b = chOQGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return; } u->TXDATA = b; } u->INTENSET = STAT_TXRDY; }
/** * @brief Error handling routine. * * @param[in] sdp pointer to a @p SerialDriver object * @param[in] sr USART SR register value */ static void set_error(SerialDriver *sdp, uint16_t sr) { eventflags_t sts = 0; if (sr & USART_SR_ORE) sts |= SD_OVERRUN_ERROR; if (sr & USART_SR_PE) sts |= SD_PARITY_ERROR; if (sr & USART_SR_FE) sts |= SD_FRAMING_ERROR; if (sr & USART_SR_NE) sts |= SD_NOISE_ERROR; chnAddFlagsI(sdp, sts); }
/** * @brief */ static void fifo_load(SerialDriver *sdp) { UART_TypeDef *u = sdp->uart; while ((u->FR & TIVA_FR_TXFF) == 0) { msg_t b = oqGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return; } u->DR = b; } u->IM |= TIVA_IM_TXIM; /* transmit interrupt enable */ }
/** * @brief Error handling routine. * * @param[in] sdp communication channel associated to the UART * @param[in] err UART LSR register value */ static void set_error(SerialDriver *sdp, IOREG32 err) { flagsmask_t sts = 0; if (err & LSR_OVERRUN) sts |= SD_OVERRUN_ERROR; if (err & LSR_PARITY) sts |= SD_PARITY_ERROR; if (err & LSR_FRAMING) sts |= SD_FRAMING_ERROR; if (err & LSR_BREAK) sts |= SD_BREAK_DETECTED; chSysLockFromIsr(); chnAddFlagsI(sdp, sts); chSysUnlockFromIsr(); }
/** * @brief Error handling routine. * * @param[in] sdp pointer to a @p SerialDriver object * @param[in] sr USART SR register value */ static void set_error(SerialDriver *sdp, uint16_t sr) { flagsmask_t sts = 0; if (sr & USART_SR_ORE) sts |= SD_OVERRUN_ERROR; if (sr & USART_SR_PE) sts |= SD_PARITY_ERROR; if (sr & USART_SR_FE) sts |= SD_FRAMING_ERROR; if (sr & USART_SR_NE) sts |= SD_NOISE_ERROR; chSysLockFromIsr(); chnAddFlagsI(sdp, sts); chSysUnlockFromIsr(); }
/** * @brief Fill the hardware FIFO of a UART. */ static void fifo_load(SerialDriver *sdp) { uint32_t u = sdp->uart; while ((HWREG(u + UART_O_FR) & UART_FR_TXFF) == 0) { msg_t b = oqGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return; } HWREG(u + UART_O_DR) = b; } HWREG(u + UART_O_IM) |= UART_IM_TXIM; /* transmit interrupt enable */ }
/** * @brief Error handling routine. * * @param[in] err USART CSR register value * @param[in] sdp communication channel associated to the USART */ static void set_error(SerialDriver *sdp, AT91_REG csr) { flagsmask_t sts = 0; if (csr & AT91C_US_OVRE) sts |= SD_OVERRUN_ERROR; if (csr & AT91C_US_PARE) sts |= SD_PARITY_ERROR; if (csr & AT91C_US_FRAME) sts |= SD_FRAMING_ERROR; if (csr & AT91C_US_RXBRK) sts |= SD_BREAK_DETECTED; chSysLockFromIsr(); chnAddFlagsI(sdp, sts); chSysUnlockFromIsr(); }