Start of public OpenTitan development history

Code contributors:
Alex Bradbury <asb@lowrisc.org>
Cindy Chen <chencindy@google.com>
Eunchan Kim <eunchan@google.com>
Gaurang Chitroda <gaurangg@google.com>
Mark Hayter <mark.hayter@gmail.com>
Michael Schaffner <msf@google.com>
Miguel Osorio <miguelosorio@google.com>
Nils Graf <nilsg@google.com>
Philipp Wagner <phw@lowrisc.org>
Pirmin Vogel <vogelpi@lowrisc.org>
Ram Babu Penugonda <rampenugonda@google.com>
Scott Johnson <scottdj@google.com>
Shail Kushwah <kushwahs@google.com>
Srikrishna Iyer <sriyer@google.com>
Steve Nelson <Steve.Nelson@wdc.com>
Tao Liu <taliu@google.com>
Timothy Chen <timothytim@google.com>
Tobias Wölfel <tobias.woelfel@mailbox.org>
Weicai Yang <weicai@google.com>
diff --git a/sw/lib/usb_simpleserial.c b/sw/lib/usb_simpleserial.c
new file mode 100644
index 0000000..0268768
--- /dev/null
+++ b/sw/lib/usb_simpleserial.c
@@ -0,0 +1,80 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Get NULL from here
+#include "usb_simpleserial.h"
+
+#include <stddef.h>
+
+#include "common.h"
+#include "usbdev.h"
+
+#define MAX_GATHER 16
+
+static void ss_rx(void *ssctx_v, usbbufid_t buf, int size, int setup) {
+  usb_ss_ctx_t *ssctx = (usb_ss_ctx_t *)ssctx_v;
+  void *ctx = ssctx->ctx;
+  volatile uint8_t *bp = (volatile uint8_t *)usbdev_buf_idtoaddr(ctx, buf);
+
+  if (size > BUF_LENGTH) {
+    size = BUF_LENGTH;
+  }
+
+  while (size--) {
+    ssctx->got_byte(*bp++);
+  }
+}
+
+// Called periodically by the main loop to ensure characters don't
+// stick around too long
+static void ss_flush(void *ssctx_v) {
+  usb_ss_ctx_t *ssctx = (usb_ss_ctx_t *)ssctx_v;
+  void *ctx = ssctx->ctx;
+  volatile uint32_t *bp_w;
+  if ((ssctx->cur_buf == -1) || (ssctx->cur_cpos <= 0)) {
+    return;
+  }
+  if ((ssctx->cur_cpos & 0x3) != 0) {
+    // unwritten data to copy over
+    bp_w = usbdev_buf_idtoaddr(ctx, ssctx->cur_buf);
+    // no -1 here because cpos is in the word we are writing
+    bp_w[(ssctx->cur_cpos / 4)] = ssctx->chold.data_w;
+  }
+  usbdev_sendbuf_byid(ctx, ssctx->cur_buf, ssctx->cur_cpos, ssctx->ep);
+  ssctx->cur_buf = -1;  // given it to the hardware
+}
+
+// Simple send byte will gather data for a while and send
+void usb_simpleserial_send_byte(usb_ss_ctx_t *ssctx, uint8_t c) {
+  volatile uint32_t *bp_w;
+  if (ssctx->cur_buf == -1) {
+    ssctx->cur_buf = usbdev_buf_allocate_byid(ssctx->ctx);
+    ssctx->cur_cpos = 0;
+  }
+  // Abort if completely out of buffers and allocation returned -1
+  if (ssctx->cur_buf < 0) {
+    return;
+  }
+  ssctx->chold.data_b[ssctx->cur_cpos++ & 0x3] = c;
+  if ((ssctx->cur_cpos & 0x3) == 0) {
+    // just wrote last byte in word
+    bp_w = usbdev_buf_idtoaddr(ssctx->ctx, ssctx->cur_buf);
+    // -1 here because cpos already incremented to next word
+    bp_w[(ssctx->cur_cpos / 4) - 1] = ssctx->chold.data_w;
+    if (ssctx->cur_cpos >= MAX_GATHER) {
+      usbdev_sendbuf_byid(ssctx->ctx, ssctx->cur_buf, ssctx->cur_cpos,
+                          ssctx->ep);
+      ssctx->cur_buf = -1;  // given it to the hardware
+    }
+  }
+}
+
+void usb_simpleserial_init(usb_ss_ctx_t *ssctx, usbdev_ctx_t *ctx, int ep,
+                           void (*got_byte)(uint8_t)) {
+  usbdev_endpoint_setup(ctx, ep, 1, ssctx, NULL, ss_rx, ss_flush);
+  ssctx->ctx = ctx;
+  ssctx->ep = ep;
+  ssctx->got_byte = got_byte;
+  ssctx->cur_buf = -1;
+}