aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <maz@kernel.org>2023-10-22 14:02:06 +0100
committerMarc Zyngier <maz@kernel.org>2023-10-22 14:13:00 +0100
commitc8a9d9619c510490a4d9470491af5ab2a0e9e99a (patch)
tree597dcc002c8d3ba6954044afcd5a082cfb738081
parent9a1c099ce9d7eb62c3c7259c5cca09ede84a0d44 (diff)
downloadcs-sw-c8a9d9619c510490a4d9470491af5ab2a0e9e99a.tar.gz
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>
-rw-r--r--README17
-rw-r--r--m1-pd-bmc.h2
-rw-r--r--start.c55
-rw-r--r--usb_descriptors.c29
-rw-r--r--vdmtool.c10
5 files changed, 81 insertions, 32 deletions
diff --git a/README b/README
index 14ec93d..11bf50c 100644
--- a/README
+++ b/README
@@ -143,8 +143,8 @@ contraption. It should be obvious, but maybe it is better stating it.
** 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 @@ and you should see something like:
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 @@ extern const struct upstream_ops *upstream_ops;
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 @@ static void m1_pd_bmc_gpio_setup_one(const struct gpio_pin_config *pin)
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 bool apply_waveshare_2ch_rs232_overrides(void)
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 @@ static int32_t usb_rx_byte(int32_t port)
{
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 @@ bool upstream_is_serial(void)
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 @@ static int wait_for_usb_connection(void)
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 @@ int main(void)
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 @@ int main(void)
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 @@ int main(void)
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 @@ static const tusb_desc_device_t usbd_desc_device = {
#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 @@ enum {
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 @@ static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
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_device_cb(void)
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 @@ void m1_pd_bmc_fusb_setup(unsigned int port,
.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 */