+#endif
+
+#if AO_USB_HAS_IN2
+/* Queue the current IN buffer for transmission */
+static void
+_ao_usb_in2_send(void)
+{
+ _tx_dbg0("in2_send start");
+ debug ("send2 %d\n", ao_usb_tx_count);
+ while (ao_usb_in2_pending)
+ ao_sleep(&ao_usb_in2_pending);
+ ao_usb_in2_pending = 1;
+ if (ao_usb_tx2_count != AO_USB_IN_SIZE)
+ ao_usb_in2_flushed = 1;
+ ao_usb_copy_tx(ao_usb_tx2_buffer, ao_usb_in2_tx_buffer, ao_usb_tx2_count);
+ ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_in_tx_offset;
+ ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = ao_usb_tx_count;
+ ao_usb_tx2_count = 0;
+ _ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID);
+ _tx_dbg0("in2_send end");
+}
+
+/* Wait for a free IN buffer. Interrupts are blocked */
+static void
+_ao_usb_in2_wait(void)
+{
+ for (;;) {
+ /* Check if the current buffer is writable */
+ if (ao_usb_tx2_count < AO_USB_IN_SIZE)
+ break;
+
+ _tx_dbg0("in2_wait top");
+ /* Wait for an IN buffer to be ready */
+ while (ao_usb_in2_pending)
+ ao_sleep(&ao_usb_in2_pending);
+ _tx_dbg0("in_wait bottom");
+ }
+}
+
+void
+ao_usb_flush2(void)
+{
+ if (!ao_usb_running)
+ return;
+
+ /* Anytime we've sent a character since
+ * the last time we flushed, we'll need
+ * to send a packet -- the only other time
+ * we would send a packet is when that
+ * packet was full, in which case we now
+ * want to send an empty packet
+ */
+ ao_arch_block_interrupts();
+ while (!ao_usb_in2_flushed) {
+ _tx_dbg0("flush2 top");
+ _ao_usb_in2_send();
+ _tx_dbg0("flush2 end");
+ }
+ ao_arch_release_interrupts();
+}
+
+void
+ao_usb_putchar2(char c)
+{
+ if (!ao_usb_running)
+ return;
+
+ ao_arch_block_interrupts();
+ _ao_usb_in2_wait();
+
+ ao_usb_in2_flushed = 0;
+ ao_usb_tx2_buffer[ao_usb_tx2_count++] = (uint8_t) c;
+
+ /* Send the packet when full */
+ if (ao_usb_tx2_count == AO_USB_IN_SIZE) {
+ _tx_dbg0("putchar2 full");
+ _ao_usb_in2_send();
+ _tx_dbg0("putchar2 flushed");
+ }
+ ao_arch_release_interrupts();
+}
+#endif