-#ifdef DOCKFIFO_UART
-
-
-// Allow a 30ms stall of wall clock time before DockFIFO starts dropping characters
-#define DOCKFIFO_WR_MAX_STALL_US (30*1000)
-
-static uint64_t prev_dockfifo_drained_time; // Last time we've seen the DockFIFO drained by an external agent
-static uint64_t prev_dockfifo_spaces; // Previous w_stat level of the DockFIFO.
-static uint32_t dockfifo_capacity;
-static uint64_t dockfifo_stall_grace;
-
-static vm_offset_t dockfifo_uart_base = 0;
-
-//=======================
-// Local funtions
-//=======================
-
-static int
-dockfifo_drain_on_stall()
-{
- // Called when DockFIFO runs out of spaces.
- // Check if the DockFIFO reader has stalled. If so, empty the DockFIFO ourselves.
- // Return number of bytes drained.
-
- if (mach_absolute_time() - prev_dockfifo_drained_time >= dockfifo_stall_grace) {
- // It's been more than DOCKFIFO_WR_MAX_STALL_US and nobody read from the FIFO
- // Drop a character.
- (void)rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ, 1);
- os_atomic_inc(&prev_dockfifo_spaces, relaxed);
- return 1;
- }
- return 0;
-}
-
-
-static int
-dockfifo_uart_tr0(void)
-{
- uint32_t spaces = rDOCKFIFO_W_STAT(DOCKFIFO_UART_WRITE) & 0xffff;
- if (spaces >= dockfifo_capacity || spaces > prev_dockfifo_spaces) {
- // More spaces showed up. That can only mean someone read the FIFO.
- // Note that if the DockFIFO is empty we cannot tell if someone is listening,
- // we can only give them the benefit of the doubt.
-
- prev_dockfifo_drained_time = mach_absolute_time();
- }
- prev_dockfifo_spaces = spaces;
-
- return spaces || dockfifo_drain_on_stall();
-}
-
-static void
-dockfifo_uart_td0(int c)
-{
- rDOCKFIFO_W_DATA(DOCKFIFO_UART_WRITE, 1) = (unsigned)(c & 0xff);
- os_atomic_dec(&prev_dockfifo_spaces, relaxed); // After writing a byte we have one fewer space than previously expected.
-}
-
-static int
-dockfifo_uart_rr0(void)
-{
- return rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ, 0) & 0x7f;
-}
-
-static int
-dockfifo_uart_rd0(void)
-{
- return (int)((rDOCKFIFO_R_DATA(DOCKFIFO_UART_READ, 1) >> 8) & 0xff);
-}
-
-static void
-dockfifo_uart_init(void)
-{
- nanoseconds_to_absolutetime(DOCKFIFO_WR_MAX_STALL_US * 1000, &dockfifo_stall_grace);
-
- // Disable autodraining of the FIFO. We now purely manage it in software.
- rDOCKFIFO_DRAIN(DOCKFIFO_UART_WRITE) = 0;
-
- // Empty the DockFIFO by draining it until OCCUPANCY is 0, then measure its capacity
- while (rDOCKFIFO_R_DATA(DOCKFIFO_UART_WRITE, 3) & 0x7F) {
- ;
- }
- dockfifo_capacity = rDOCKFIFO_W_STAT(DOCKFIFO_UART_WRITE) & 0xffff;
-}
-
-SECURITY_READ_ONLY_LATE(static struct pe_serial_functions) dockfifo_uart_serial_functions =
-{
- .uart_init = dockfifo_uart_init,
- .uart_set_baud_rate = NULL,
- .tr0 = dockfifo_uart_tr0,
- .td0 = dockfifo_uart_td0,
- .rr0 = dockfifo_uart_rr0,
- .rd0 = dockfifo_uart_rd0
-};
-
-#endif /* DOCKFIFO_UART */
-
-/*****************************************************************************/
-