+/*
+ * ----------------------------------------------------------------
+ * Routines to access and control daughterboard specific i/o
+ * ----------------------------------------------------------------
+ */
+static int
+slot_id_to_oe_reg (int slot_id)
+{
+ static int reg[4] = { FR_OE_0, FR_OE_1, FR_OE_2, FR_OE_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_io_reg (int slot_id)
+{
+ static int reg[4] = { FR_IO_0, FR_IO_1, FR_IO_2, FR_IO_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_refclk_reg(int slot_id)
+{
+ static int reg[4] = { FR_TX_A_REFCLK, FR_RX_A_REFCLK, FR_TX_B_REFCLK, FR_RX_B_REFCLK };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_atr_mask_reg(int slot_id)
+{
+ static int reg[4] = { FR_ATR_MASK_0, FR_ATR_MASK_1, FR_ATR_MASK_2, FR_ATR_MASK_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_atr_txval_reg(int slot_id)
+{
+ static int reg[4] = { FR_ATR_TXVAL_0, FR_ATR_TXVAL_1, FR_ATR_TXVAL_2, FR_ATR_TXVAL_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+slot_id_to_atr_rxval_reg(int slot_id)
+{
+ static int reg[4] = { FR_ATR_RXVAL_0, FR_ATR_RXVAL_1, FR_ATR_RXVAL_2, FR_ATR_RXVAL_3 };
+ assert (0 <= slot_id && slot_id < 4);
+ return reg[slot_id];
+}
+
+static int
+to_slot(txrx_t txrx, int which_side)
+{
+ // TX_A = 0
+ // RX_A = 1
+ // TX_B = 2
+ // RX_B = 3
+ return ((which_side & 0x1) << 1) | ((txrx & 0x1) == C_RX);
+}
+
+bool
+usrp_basic::common_set_pga(txrx_t txrx, int which_amp, double gain)
+{
+ if (which_amp < 0 || which_amp > 3)
+ return false;
+
+ gain = std::min(common_pga_max(txrx),
+ std::max(common_pga_min(txrx), gain));
+
+ int codec = which_amp >> 1;
+ int int_gain = (int) rint((gain - common_pga_min(txrx)) / common_pga_db_per_step(txrx));
+
+ if (txrx == C_TX){ // 0 and 1 are same, as are 2 and 3
+ return _write_9862(codec, REG_TX_PGA, int_gain);
+ }
+ else {
+ int reg = (which_amp & 1) == 0 ? REG_RX_A : REG_RX_B;
+
+ // read current value to get input buffer bypass flag.
+ unsigned char cur_rx;
+ if (!_read_9862(codec, reg, &cur_rx))
+ return false;
+
+ cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f);
+ return _write_9862(codec, reg, cur_rx);
+ }
+}
+
+double
+usrp_basic::common_pga(txrx_t txrx, int which_amp) const
+{
+ if (which_amp < 0 || which_amp > 3)
+ return READ_FAILED;
+
+ if (txrx == C_TX){
+ int codec = which_amp >> 1;
+ unsigned char v;
+ bool ok = _read_9862 (codec, REG_TX_PGA, &v);
+ if (!ok)
+ return READ_FAILED;
+
+ return (pga_db_per_step() * v) + pga_min();
+ }
+ else {
+ int codec = which_amp >> 1;
+ int reg = (which_amp & 1) == 0 ? REG_RX_A : REG_RX_B;
+ unsigned char v;
+ bool ok = _read_9862 (codec, reg, &v);
+ if (!ok)
+ return READ_FAILED;
+
+ return (pga_db_per_step() * (v & 0x1f)) + pga_min();
+ }
+}
+
+double
+usrp_basic::common_pga_min(txrx_t txrx) const
+{
+ if (txrx == C_TX)
+ return -20.0;
+ else
+ return 0.0;
+}
+
+double
+usrp_basic::common_pga_max(txrx_t txrx) const
+{
+ if (txrx == C_TX)
+ return 0.0;
+ else
+ return 20.0;
+}
+
+double
+usrp_basic::common_pga_db_per_step(txrx_t txrx) const
+{
+ if (txrx == C_TX)
+ return 20.0 / 255;
+ else
+ return 20.0 / 20;
+}
+
+bool
+usrp_basic::_common_write_oe(txrx_t txrx, int which_side, int value, int mask)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_oe_reg(to_slot(txrx, which_side)),
+ (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic::common_write_io(txrx_t txrx, int which_side, int value, int mask)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_io_reg(to_slot(txrx, which_side)),
+ (mask << 16) | (value & 0xffff));
+}
+
+bool
+usrp_basic::common_read_io(txrx_t txrx, int which_side, int *value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ int t;
+ int reg = which_side + 1; // FIXME, *very* magic number (fix in serial_io.v)
+ bool ok = _read_fpga_reg(reg, &t);
+ if (!ok)
+ return false;
+
+ if (txrx == C_TX){
+ *value = t & 0xffff; // FIXME, more magic
+ return true;
+ }
+ else {
+ *value = (t >> 16) & 0xffff; // FIXME, more magic
+ return true;
+ }
+}
+
+int
+usrp_basic::common_read_io(txrx_t txrx, int which_side)
+{
+ int value;
+ if (!common_read_io(txrx, which_side, &value))
+ return READ_FAILED;
+ return value;
+}
+
+bool
+usrp_basic::common_write_refclk(txrx_t txrx, int which_side, int value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_refclk_reg(to_slot(txrx, which_side)),
+ value);
+}
+
+bool
+usrp_basic::common_write_atr_mask(txrx_t txrx, int which_side, int value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_atr_mask_reg(to_slot(txrx, which_side)),
+ value);
+}
+
+bool
+usrp_basic::common_write_atr_txval(txrx_t txrx, int which_side, int value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_atr_txval_reg(to_slot(txrx, which_side)),
+ value);
+}
+
+bool
+usrp_basic::common_write_atr_rxval(txrx_t txrx, int which_side, int value)
+{
+ if (! (0 <= which_side && which_side <= 1))
+ return false;
+
+ return _write_fpga_reg(slot_id_to_atr_rxval_reg(to_slot(txrx, which_side)),
+ value);
+}
+
+bool
+usrp_basic::common_write_aux_dac(txrx_t txrx, int which_side, int which_dac, int value)
+{
+ return _write_aux_dac(to_slot(txrx, which_side), which_dac, value);
+}
+
+bool
+usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc, int *value)
+{
+ return _read_aux_adc(to_slot(txrx, which_side), which_adc, value);
+}
+
+int
+usrp_basic::common_read_aux_adc(txrx_t txrx, int which_side, int which_adc)
+{
+ return _read_aux_adc(to_slot(txrx, which_side), which_adc);
+}
+
+