Only advertise a single CDC for single board configurations
Advertising two CDC endpoints when a single CS board is present is
a bit silly, specially considering that connecting to the absent
port leads to undesirable effects...
Instead, account for the present ports early by immediately probing
for the I2C PUPs, and keep track of which ports are alive. Then
make sure that we only advertise a single CDC configuration when
only a single CS board is present.
Finally, map all single-board configurations to the first CDC port,
irrespective of the board being P0 or P1. This allows single boards
configured with the alternate configuration (for random reasons) to
be able to use ttyACM0.
Also update the README file.
Signed-off-by: Marc Zyngier <maz@kernel.org>
diff --git a/README b/README
index 14ec93d..11bf50c 100644
--- a/README
+++ b/README
@@ -143,8 +143,8 @@
** Use it
If you have correctly built and flashed the firmware, you will have
-the Pico led blinking at the rate of twice a second, and a couple of
-/dev/ttyACM* being advertised by your host:
+the Pico led blinking at the rate of twice a second, and one or two
+/dev/ttyACM* devices being advertised by your host:
[708023.097129] usb 1-4: new full-speed USB device number 72 using xhci_hcd
[708023.265195] usb 1-4: New USB device found, idVendor=2e8a, idProduct=000a, bcdDevice= 1.00
@@ -169,25 +169,22 @@
This is the Central Scrutinizer
Control character is ^_
Press ^_ + ? for help
+ P0: Probing port 0
P0: VBUS OFF
- P0: Device ID: 0x91
+ P0: Device ID: B_revB (0x91)
P0: Init
P0: STATUS0: 0x80
P0: VBUS OFF
P0: Disconnected
P0: S: DISCONNECTED
- P0: Empty debug message
- P0: IRQ=0 10 0
- P0: Connected: cc1=2 cc2=0
+ P0: Connected: cc1=2 cc2=1
P0: Polarity: CC1 (normal)
+ P0: VCONN on CC2
P0: VBUS ON
P0: S: DFP_VBUS_ON
- P0: Empty debug message
- P0: IRQ=71 4 0
P0: S: DFP_CONNECTED
P0: >VDM serial -> SBU1/2
- P0: IRQ=71 4 1
- P0: <VDM RX SOP"DEBUG (5) [504f] 5ac8052 91340000 306 0 0
+ P0: <VDM RX SOP"DEBUG (5) [508f] 5ac8052 44740000 306 0 0
If you see the ">VDM serial -> SBU1/2" line, the serial line should
now be connected and you can interact with the M1. Note that you can
diff --git a/m1-pd-bmc.h b/m1-pd-bmc.h
index 83abc9c..9e62316 100644
--- a/m1-pd-bmc.h
+++ b/m1-pd-bmc.h
@@ -59,6 +59,8 @@
void set_upstream_ops(bool serial);
bool upstream_is_serial(void);
+int get_valid_ports(void);
+
void upstream_tx_str(int32_t port, const char *ptr);
#define PRINTF_SIZE 512
diff --git a/start.c b/start.c
index 8bcc75e..383a5b5 100644
--- a/start.c
+++ b/start.c
@@ -7,6 +7,13 @@
#include "m1-pd-bmc.h"
#include "FUSB302.h"
+static uint8_t valid_ports = 0;
+
+static inline int __get_valid_ports(void)
+{
+ return (valid_ports == 3) + 1;
+}
+
static const struct gpio_pin_config m1_pd_bmc_pin_config0[] = {
[M1_BMC_PIN_START ... M1_BMC_PIN_END] = {
.skip = true,
@@ -229,12 +236,18 @@
gpio_pull_up(pin->pin);
}
-static void m1_pd_bmc_system_init(const struct hw_context *hw)
+static bool m1_pd_bmc_system_init(const struct hw_context *hw)
{
init_system(hw);
for (unsigned int i = 0; i < hw->nr_pins; i++)
m1_pd_bmc_gpio_setup_one(&hw->pins[i]);
+
+ /*
+ * If we can't infer pull-ups on the I2C, it is likely that
+ * nothing is connected and we'd better skip this port.
+ */
+ return gpio_get(hw->pins[I2C_SCL].pin) && gpio_get(hw->pins[I2C_SDA].pin);
}
static bool apply_waveshare_2ch_rs232_overrides(void)
@@ -259,6 +272,9 @@
static void usb_tx_bytes(int32_t port, const char *ptr, int len)
{
+ if (__get_valid_ports() != 2)
+ port = 0;
+
if (!tud_cdc_n_connected(port))
return;
@@ -283,6 +299,9 @@
{
uint8_t c;
+ if (__get_valid_ports() != 2)
+ port = 0;
+
if (!tud_cdc_n_connected(port) || !tud_cdc_n_available(port))
return -1;
@@ -372,6 +391,11 @@
static int wait_for_usb_connection(void)
{
+ bool connected;
+ int ports;
+
+ ports = __get_valid_ports();
+
do {
static bool state = false;
static int cnt = 0;
@@ -383,9 +407,18 @@
cnt %= 256;
if (!cnt)
state = !state;
- } while (!tud_cdc_n_connected(0) && !tud_cdc_n_connected(1));
- return !tud_cdc_n_connected(0);
+ connected = false;
+ connected |= tud_cdc_n_connected(0);
+ connected |= ports == 2 && tud_cdc_n_connected(1);
+ } while (!connected);
+
+ return ports == 2 && tud_cdc_n_connected(1);
+}
+
+int get_valid_ports(void)
+{
+ return __get_valid_ports();
}
int main(void)
@@ -398,10 +431,15 @@
success = set_sys_clock_khz(133000, false);
board_init();
+
+ if (m1_pd_bmc_system_init(&hw0))
+ valid_ports |= 1;
+ if (m1_pd_bmc_system_init(&hw1))
+ valid_ports |= 2;
+
tusb_init();
- m1_pd_bmc_system_init(&hw0);
- m1_pd_bmc_system_init(&hw1);
+ sleep_ms(200);
if (apply_waveshare_2ch_rs232_overrides()) {
set_upstream_ops(true);
@@ -411,6 +449,8 @@
port = wait_for_usb_connection();
}
+ upstream_ops->flush();
+
__printf(port, "This is the Central Scrutinizer\n");
__printf(port, "Control character is ^_\n");
__printf(port, "Press ^_ + ? for help\n");
@@ -418,8 +458,9 @@
if (!success)
__printf(port, "WARNING: Nominal frequency NOT reached\n");
- m1_pd_bmc_fusb_setup(0, &hw0);
- if (!upstream_is_serial())
+ if (valid_ports & 1)
+ m1_pd_bmc_fusb_setup(0, &hw0);
+ if ((valid_ports & 2) && !upstream_is_serial())
m1_pd_bmc_fusb_setup(1, &hw1);
m1_pd_bmc_run();
diff --git a/usb_descriptors.c b/usb_descriptors.c
index a084ae6..e63ffa6 100644
--- a/usb_descriptors.c
+++ b/usb_descriptors.c
@@ -44,8 +44,7 @@
#define USBD_MAX_POWER_MA (250)
-#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + \
- TUD_CDC_DESC_LEN * CFG_TUD_CDC)
+#define USBD_DESC_LEN(n) (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN * (n))
enum {
ITF_NUM_CDC_0,
@@ -55,11 +54,10 @@
ITF_NUM_TOTAL,
};
-static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
-
+static const uint8_t usbd_desc_cfg_dual[USBD_DESC_LEN(2)] = {
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL,
USBD_STR_LANGUAGE,
- USBD_DESC_LEN,
+ USBD_DESC_LEN(2),
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
USBD_MAX_POWER_MA),
@@ -80,6 +78,22 @@
USBD_CDC_DATA_SIZE),
};
+static const uint8_t usbd_desc_cfg_single[USBD_DESC_LEN(1)] = {
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL - 2,
+ USBD_STR_LANGUAGE,
+ USBD_DESC_LEN(1),
+ TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
+ USBD_MAX_POWER_MA),
+
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0,
+ USBD_STR_CDC_0_NAME,
+ EPNUM_CDC_0_CMD,
+ USBD_CDC_CMD_SIZE,
+ EPNUM_CDC_0_DATA & 0x7F,
+ EPNUM_CDC_0_DATA,
+ USBD_CDC_DATA_SIZE),
+};
+
const uint8_t *tud_descriptor_device_cb(void)
{
return (const uint8_t *)&usbd_desc_device;
@@ -88,7 +102,10 @@
const uint8_t *tud_descriptor_configuration_cb(uint8_t index)
{
(void)index;
- return usbd_desc_cfg;
+ if (get_valid_ports() == 2)
+ return usbd_desc_cfg_dual;
+
+ return usbd_desc_cfg_single;
}
#define DESC_STR_MAX_LENGTH 20
diff --git a/vdmtool.c b/vdmtool.c
index 29228ea..ae3abec 100644
--- a/vdmtool.c
+++ b/vdmtool.c
@@ -666,15 +666,7 @@
.serial_pin_set = 2, /* SBU1/2 */
};
- /*
- * If we can't infer pull-ups on the I2C, it is likely that
- * nothing is connected and we'd better skip this port.
- */
- if (!gpio_get(PIN(cxt, I2C_SCL)) || !gpio_get(PIN(cxt, I2C_SDA))) {
- cprintf(cxt, "I2C pins low while idling, skipping port\n");
- cxt->hw = NULL;
- return;
- }
+ cprintf(cxt, "Probing port %d\n", port);
gpio_put(PIN(cxt, LED_G), HIGH);
/* No swapping */