blob: 3ce3f8d09af254bbdb90c201262227f2a0ea5b3a [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
Miguel Young de la Sotaf225d992019-12-17 10:19:22 -06005#include "sw/device/lib/usb_simpleserial.h"
lowRISC Contributors802543a2019-08-31 12:12:56 +01006
Miguel Osorioae67f6b2019-10-18 18:56:08 -07007#include "sw/device/lib/common.h"
Miguel Young de la Sotaf225d992019-12-17 10:19:22 -06008#include "sw/device/lib/usbdev.h"
lowRISC Contributors802543a2019-08-31 12:12:56 +01009
10#define MAX_GATHER 16
11
12static void ss_rx(void *ssctx_v, usbbufid_t buf, int size, int setup) {
13 usb_ss_ctx_t *ssctx = (usb_ss_ctx_t *)ssctx_v;
14 void *ctx = ssctx->ctx;
15 volatile uint8_t *bp = (volatile uint8_t *)usbdev_buf_idtoaddr(ctx, buf);
16
17 if (size > BUF_LENGTH) {
18 size = BUF_LENGTH;
19 }
20
21 while (size--) {
22 ssctx->got_byte(*bp++);
23 }
24}
25
26// Called periodically by the main loop to ensure characters don't
27// stick around too long
28static void ss_flush(void *ssctx_v) {
29 usb_ss_ctx_t *ssctx = (usb_ss_ctx_t *)ssctx_v;
30 void *ctx = ssctx->ctx;
31 volatile uint32_t *bp_w;
32 if ((ssctx->cur_buf == -1) || (ssctx->cur_cpos <= 0)) {
33 return;
34 }
35 if ((ssctx->cur_cpos & 0x3) != 0) {
36 // unwritten data to copy over
37 bp_w = usbdev_buf_idtoaddr(ctx, ssctx->cur_buf);
38 // no -1 here because cpos is in the word we are writing
39 bp_w[(ssctx->cur_cpos / 4)] = ssctx->chold.data_w;
40 }
41 usbdev_sendbuf_byid(ctx, ssctx->cur_buf, ssctx->cur_cpos, ssctx->ep);
42 ssctx->cur_buf = -1; // given it to the hardware
43}
44
45// Simple send byte will gather data for a while and send
46void usb_simpleserial_send_byte(usb_ss_ctx_t *ssctx, uint8_t c) {
47 volatile uint32_t *bp_w;
48 if (ssctx->cur_buf == -1) {
49 ssctx->cur_buf = usbdev_buf_allocate_byid(ssctx->ctx);
50 ssctx->cur_cpos = 0;
51 }
52 // Abort if completely out of buffers and allocation returned -1
53 if (ssctx->cur_buf < 0) {
54 return;
55 }
56 ssctx->chold.data_b[ssctx->cur_cpos++ & 0x3] = c;
57 if ((ssctx->cur_cpos & 0x3) == 0) {
58 // just wrote last byte in word
59 bp_w = usbdev_buf_idtoaddr(ssctx->ctx, ssctx->cur_buf);
60 // -1 here because cpos already incremented to next word
61 bp_w[(ssctx->cur_cpos / 4) - 1] = ssctx->chold.data_w;
62 if (ssctx->cur_cpos >= MAX_GATHER) {
63 usbdev_sendbuf_byid(ssctx->ctx, ssctx->cur_buf, ssctx->cur_cpos,
64 ssctx->ep);
65 ssctx->cur_buf = -1; // given it to the hardware
66 }
67 }
68}
69
70void usb_simpleserial_init(usb_ss_ctx_t *ssctx, usbdev_ctx_t *ctx, int ep,
71 void (*got_byte)(uint8_t)) {
72 usbdev_endpoint_setup(ctx, ep, 1, ssctx, NULL, ss_rx, ss_flush);
73 ssctx->ctx = ctx;
74 ssctx->ep = ep;
75 ssctx->got_byte = got_byte;
76 ssctx->cur_buf = -1;
77}