+/*
+ * Write these values to preserve register contents under HW changes
+ */
+
+#define STM_USB_EPR_INVARIANT ((1 << STM_USB_EPR_CTR_RX) | \
+ (STM_USB_EPR_DTOG_RX_WRITE_INVARIANT << STM_USB_EPR_DTOG_RX) | \
+ (STM_USB_EPR_STAT_RX_WRITE_INVARIANT << STM_USB_EPR_STAT_RX) | \
+ (1 << STM_USB_EPR_CTR_TX) | \
+ (STM_USB_EPR_DTOG_TX_WRITE_INVARIANT << STM_USB_EPR_DTOG_TX) | \
+ (STM_USB_EPR_STAT_TX_WRITE_INVARIANT << STM_USB_EPR_STAT_TX))
+
+#define STM_USB_EPR_INVARIANT_MASK ((1 << STM_USB_EPR_CTR_RX) | \
+ (STM_USB_EPR_DTOG_RX_MASK << STM_USB_EPR_DTOG_RX) | \
+ (STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX) | \
+ (1 << STM_USB_EPR_CTR_TX) | \
+ (STM_USB_EPR_DTOG_TX_MASK << STM_USB_EPR_DTOG_TX) | \
+ (STM_USB_EPR_STAT_TX_MASK << STM_USB_EPR_STAT_TX))
+
+/*
+ * These bits are purely under sw control, so preserve them in the
+ * register by re-writing what was read
+ */
+#define STM_USB_EPR_PRESERVE_MASK ((STM_USB_EPR_EP_TYPE_MASK << STM_USB_EPR_EP_TYPE) | \
+ (1 << STM_USB_EPR_EP_KIND) | \
+ (STM_USB_EPR_EA_MASK << STM_USB_EPR_EA))
+
+#define TX_DBG 0
+#define RX_DBG 0
+
+#if TX_DBG
+#define _tx_dbg0(msg) _dbg(__LINE__,msg,0)
+#define _tx_dbg1(msg,value) _dbg(__LINE__,msg,value)
+#else
+#define _tx_dbg0(msg)
+#define _tx_dbg1(msg,value)
+#endif
+
+#if RX_DBG
+#define _rx_dbg0(msg) _dbg(__LINE__,msg,0)
+#define _rx_dbg1(msg,value) _dbg(__LINE__,msg,value)
+#else
+#define _rx_dbg0(msg)
+#define _rx_dbg1(msg,value)
+#endif
+
+#if TX_DBG || RX_DBG
+static void _dbg(int line, char *msg, uint32_t value);
+#endif
+
+/*
+ * Set the state of the specified endpoint register to a new
+ * value. This is tricky because the bits toggle where the new
+ * value is one, and we need to write invariant values in other
+ * spots of the register. This hardware is strange...
+ */
+static void
+_ao_usb_set_stat_tx(int ep, uint32_t stat_tx)
+{
+ uint32_t epr_write, epr_old;
+
+ _tx_dbg1("set_stat_tx top", stat_tx);
+ epr_old = epr_write = stm_usb.epr[ep];
+ epr_write &= STM_USB_EPR_PRESERVE_MASK;
+ epr_write |= STM_USB_EPR_INVARIANT;
+ epr_write |= set_toggle(epr_old,
+ STM_USB_EPR_STAT_TX_MASK << STM_USB_EPR_STAT_TX,
+ stat_tx << STM_USB_EPR_STAT_TX);
+ stm_usb.epr[ep] = epr_write;
+ _tx_dbg1("set_stat_tx bottom", epr_write);
+}
+
+static void
+ao_usb_set_stat_tx(int ep, uint32_t stat_tx)
+{
+ ao_arch_block_interrupts();
+ _ao_usb_set_stat_tx(ep, stat_tx);
+ ao_arch_release_interrupts();
+}
+
+static void
+_ao_usb_set_stat_rx(int ep, uint32_t stat_rx) {
+ uint32_t epr_write, epr_old;
+
+ epr_write = epr_old = stm_usb.epr[ep];
+ epr_write &= STM_USB_EPR_PRESERVE_MASK;
+ epr_write |= STM_USB_EPR_INVARIANT;
+ epr_write |= set_toggle(epr_old,
+ STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX,
+ stat_rx << STM_USB_EPR_STAT_RX);
+ stm_usb.epr[ep] = epr_write;
+}
+
+static void
+ao_usb_set_stat_rx(int ep, uint32_t stat_rx) {
+ ao_arch_block_interrupts();
+ _ao_usb_set_stat_rx(ep, stat_rx);
+ ao_arch_release_interrupts();
+}
+