1/*
2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <autoconf.h>
8#include <camkes.h>
9#include <stdio.h>
10#include <virtqueue.h>
11#include <camkes/virtqueue.h>
12#include <utils/util.h>
13#include <string.h>
14
15virtqueue_driver_t read_virtqueue;
16virtqueue_driver_t write_virtqueue;
17
18void handle_read_callback(virtqueue_driver_t *vq);
19void handle_write_callback(virtqueue_driver_t *vq);
20
21void write_output(char *write_data, size_t write_data_size)
22{
23    if (camkes_virtqueue_driver_scatter_send_buffer(&write_virtqueue, write_data, write_data_size)) {
24        ZF_LOGE("Client write enqueue failed");
25        return;
26    }
27    write_virtqueue.notify();
28}
29
30void loopback_test(void)
31{
32    size_t buffer_size = 4000;
33
34
35    if (camkes_virtqueue_driver_scatter_send_buffer(&read_virtqueue, NULL, buffer_size)) {
36        ZF_LOGE("Client read enqueue failed");
37        return;
38    }
39
40    fflush(stdout);
41    read_virtqueue.notify();
42}
43
44void handle_read_callback(virtqueue_driver_t *vq)
45{
46    void *buf = NULL;
47    unsigned len = 0;
48    virtqueue_ring_object_t handle;
49    vq_flags_t flags;
50
51    if (!virtqueue_get_used_buf(vq, &handle, &len)) {
52        ZF_LOGE("Client virtqueue dequeue failed");
53        return;
54    }
55    if (!(buf = calloc(len, sizeof(char)))) {
56        ZF_LOGE("Could not allocate memory");
57        return;
58    }
59    if (camkes_virtqueue_driver_gather_copy_buffer(vq, &handle, buf, len) != 0) {
60        free(buf);
61    }
62    write_output(buf, len);
63}
64
65void handle_write_callback(virtqueue_driver_t *vq)
66{
67    void *buf = NULL;
68    unsigned len = 0;
69    virtqueue_ring_object_t handle;
70    vq_flags_t flags;
71
72
73    if (!virtqueue_get_used_buf(vq, &handle, &len)) {
74        ZF_LOGE("Client virtqueue dequeue failed");
75        return;
76    }
77    while (camkes_virtqueue_driver_gather_buffer(vq, &handle, &buf, &len, &flags) == 0) {
78        /* Clean up and free the buffer we allocated */
79        camkes_virtqueue_buffer_free(vq, buf);
80    }
81    /* Moving the call here forces synchronicity but makes it a bit slower */
82    /* TODO: make it more asynchronous */
83    loopback_test();
84}
85
86/*
87void serial_wait_callback(void)
88{
89    if (VQ_DRV_POLL(&read_virtqueue)) {
90        handle_read_callback(&read_virtqueue);
91    }
92    if (VQ_DRV_POLL(&write_virtqueue)) {
93        handle_write_callback(&write_virtqueue);
94    }
95}
96*/
97
98void serial_read_wait_callback(void)
99{
100    if (VQ_DRV_POLL(&read_virtqueue)) {
101        handle_read_callback(&read_virtqueue);
102    }
103}
104
105void serial_write_wait_callback(void)
106{
107    if (VQ_DRV_POLL(&write_virtqueue)) {
108        handle_write_callback(&write_virtqueue);
109    }
110}
111
112void pre_init(void)
113{
114    set_putchar(serial_putchar_putchar);
115}
116
117int run(void)
118{
119    ZF_LOGE("Starting loopback serial test");
120
121    /* Initialise read virtqueue */
122    int err = camkes_virtqueue_driver_init(&read_virtqueue, 0);
123    if (err) {
124        ZF_LOGE("Unable to initialise read virtqueue");
125        return 1;
126    }
127
128    /* Initialise write virtqueue */
129    err = camkes_virtqueue_driver_init(&write_virtqueue, 1);
130    if (err) {
131        ZF_LOGE("Unable to initialise write virtqueue");
132        return 1;
133    }
134
135    loopback_test();
136
137    return 0;
138}
139