1/**
2 * \file
3 * \brief Serial port driver.
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2012, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, CAB F.78, Universitaetstrasse 6, CH-8092 Zurich,
13 * Attn: Systems Group.
14 */
15
16#include <stdlib.h>
17#include <stdio.h>
18#include <string.h>
19#include <barrelfish/barrelfish.h>
20#include <barrelfish/waitset.h>
21#include "serial.h"
22#include "serial_debug.h"
23
24
25void serial_input(struct serial_common *main, char *data, size_t length)
26{
27    if (main->input_consumer != NULL) {
28        // There is a consumer (client) attached to either the basic service
29        // interface or the terminal service interface. Direct input directly
30        // to service.
31        main->input_consumer(main->input_consumer_arg, data, length);
32    } else {
33        // No consumer (client) attached. Buffer input.
34        if (main->buffer.buf == NULL) {
35            // Allocate a new buffer.
36            main->buffer.buf = (char *) malloc(length);
37            assert(main->buffer.buf != NULL);
38            memcpy(main->buffer.buf, data, length);
39            main->buffer.len = length;
40        } else {
41            // Append new data to existing buffer.
42            main->buffer.buf = realloc(main->buffer.buf, main->buffer.len + length);
43            assert(main->buffer.buf != NULL);
44            memcpy(main->buffer.buf + main->buffer.len, data, length);
45            main->buffer.len += length;
46        }
47    }
48}
49
50void serial_set_new_input_consumer(struct serial_common *main,
51                                   serial_input_fn_t fn, void *fn_arg)
52{
53    SERIAL_DEBUG("New input consumer set. main=%p\n", main);
54    main->input_consumer = fn;
55    main->input_consumer_arg = fn_arg;
56
57    // Send previously buffered input to newly attached consumer.
58    if (main->buffer.buf != NULL) {
59        SERIAL_DEBUG("Previously buffered input sent to newly attached "
60                     "consumer.\n");
61        main->input_consumer(main->input_consumer_arg, main->buffer.buf,
62                main->buffer.len);
63        free(main->buffer.buf);
64        main->buffer.buf = NULL;
65    }
66}
67
68void start_service(struct serial_common *m)
69{
70    SERIAL_DEBUG("Starting services.\n");
71    start_terminal_service(m);
72    start_basic_service(m);
73}
74
75errval_t init_serial_common(struct serial_common *m)
76{
77    // defaults
78    m->driver_name = "serial0";
79    m->input_consumer = NULL;
80    m->input_consumer_arg = NULL;
81    m->buffer.buf = NULL;
82    m->buffer.len = 0;
83    m->irq            = SERIAL_IRQ_INVALID;
84    m->membase        = SERIAL_MEMBASE_INVALID;
85
86    return SYS_ERR_OK;
87
88    // Parse args
89    /*
90    for (int i = 1; i < argc; i++) {
91        if (strncmp(argv[i], "irq=", sizeof("irq=") - 1) == 0) {
92             uint32_t x=
93                 strtoul(argv[i] + sizeof("irq=") - 1, NULL, 0);
94             if (x == 0) {
95                fprintf(stderr, "Error: invalid IRQ %"PRIu32"\n", x);
96                goto usage;
97            }
98            m->irq = x;
99        } else if (strncmp(argv[i], "membase=", sizeof("membase=") - 1) == 0) {
100            uint64_t x=
101                strtoull(argv[i] + sizeof("membase=") - 1, NULL, 0);
102            m->membase = x;
103        } else if (strncmp(argv[i], "name=", sizeof("name=") - 1) == 0) {
104             m->driver_name = argv[i] + sizeof("name=") - 1;
105        } else if (strncmp(argv[i], "auto", 4) == 0) {
106            // do nothing, means we are being started through kaluga
107        } else if (strncmp(argv[i], "int_model=", sizeof("int_model=") - 1) == 0) {
108            // ignore. x86 just assumes that legacy interrupts are used.
109        } else {
110            fprintf(stderr, "Error: unknown option %s\n", argv[i]);
111            goto usage;
112        }
113    }
114
115    return SYS_ERR_OK;
116
117usage:
118    fprintf(stderr, "Usage: %s [irq=IRQ] [name=NAME]\n"
119                    "    [membase=ADDR] [kernel]\n", argv[0]);
120    return SYS_ERR_IRQ_INVALID;
121    */
122}
123