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