From 4a292ac0dacc6ebbfc05b95e8bce0091530028e2 Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Sun, 21 Jul 2019 23:02:45 +0200
Subject: [PATCH] workaround(cdcacm): Fix CDC-ACM lockup on host hangup

This patch is a workaround for #54.  A lockup is detected if more than
4096 attempts to write to the USB FIFO fail.  If this condition is
detected, CDC-ACM is disabled until the next reboot.

Signed-off-by: Rahix <rahix@rahix.de>
---
 epicardium/cdcacm.c                             | 12 ++++++++----
 lib/sdk/Libraries/MAXUSB/src/devclass/cdc_acm.c |  6 ++++++
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/epicardium/cdcacm.c b/epicardium/cdcacm.c
index 19b1dcfe..cead3780 100644
--- a/epicardium/cdcacm.c
+++ b/epicardium/cdcacm.c
@@ -199,10 +199,14 @@ uint8_t cdcacm_read(void)
 
 void cdcacm_write(uint8_t *data, int len)
 {
-    while (acm_present()) {
-        // TODO: This might fail horribly
-        if (acm_write(data, len) == len) {
-            break;
+    static int lockup_disable = 0;
+    if (acm_present() && !lockup_disable) {
+        int ret = acm_write(data, len);
+        if (ret < 0) {
+            LOG_ERR("cdcacm", "fifo lockup detected");
+            lockup_disable = 1;
+        } else if (ret != len) {
+            LOG_WARN("cdcacm", "write length mismatch, got %d", ret);
         }
     }
 }
diff --git a/lib/sdk/Libraries/MAXUSB/src/devclass/cdc_acm.c b/lib/sdk/Libraries/MAXUSB/src/devclass/cdc_acm.c
index 92bf8df2..c85ca2b8 100644
--- a/lib/sdk/Libraries/MAXUSB/src/devclass/cdc_acm.c
+++ b/lib/sdk/Libraries/MAXUSB/src/devclass/cdc_acm.c
@@ -329,10 +329,12 @@ int acm_read(uint8_t *buf, unsigned int len)
 int acm_write(uint8_t *buf, unsigned int len)
 {
   unsigned int i = 0;
+  unsigned int failcount = 0;
 
   /* Write data into the FIFO */
   while (len > 0) {
     if (fifo_put8(&wfifo, buf[i]) == 0) {
+      failcount = 0;
       /* Success */
       i++; len--;
     } else {
@@ -340,6 +342,10 @@ int acm_write(uint8_t *buf, unsigned int len)
       if (wreq.reqlen == 0) {
 	svc_in_to_host(&wreq);
       }
+
+      if (failcount++ > 4096) {
+        return -1;
+      }
     }
   }
 
-- 
GitLab