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, Universitaetstr. 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 24static char *driver_name = "serial0"; // default driver name 25 26static struct serial_buffer buffer; 27 28static serial_input_fn_t *consumer_serial_input = NULL; 29 30void serial_input(char *data, size_t length) 31{ 32 if (consumer_serial_input != NULL) { 33 // There is a consumer (client) attached to either the basic service 34 // interface or the terminal service interface. Direct input directly 35 // to service. 36 consumer_serial_input(data, length); 37 } else { 38 // No consumer (client) attached. Buffer input. 39 if (buffer.buf == NULL) { 40 // Allocate a new buffer. 41 buffer.buf = (char *) malloc(length); 42 assert(buffer.buf != NULL); 43 memcpy(buffer.buf, data, length); 44 buffer.len = length; 45 } else { 46 // Append new data to existing buffer. 47 buffer.buf = realloc(buffer.buf, buffer.len + length); 48 assert(buffer.buf != NULL); 49 memcpy(buffer.buf + buffer.len, data, length); 50 buffer.len += length; 51 } 52 } 53} 54 55void set_new_input_consumer(serial_input_fn_t fn) 56{ 57 SERIAL_DEBUG("New input consumer set.\n"); 58 consumer_serial_input = fn; 59 60 // Send previously buffered input to newly attached consumer. 61 if (buffer.buf != NULL) { 62 SERIAL_DEBUG("Previously buffered input sent to newly attached " 63 "consumer.\n"); 64 consumer_serial_input(buffer.buf, buffer.len); 65 free(buffer.buf); 66 buffer.buf = NULL; 67 } 68} 69 70void start_service(void) 71{ 72 SERIAL_DEBUG("Starting services.\n"); 73 start_terminal_service(driver_name); 74 start_basic_service(driver_name); 75} 76 77int main(int argc, char *argv[]) 78{ 79 errval_t err; 80 81 struct serial_params params = { 82 .portbase = SERIAL_PORTBASE_INVALID, 83 .irq = SERIAL_IRQ_INVALID, 84 .membase = SERIAL_MEMBASE_INVALID, 85 }; 86 87 // Parse args 88 for (int i = 1; i < argc; i++) { 89 if (strncmp(argv[i], "portbase=", sizeof("portbase=") - 1) == 0) { 90 uint32_t x= 91 strtoul(argv[i] + sizeof("portbase=") - 1, NULL, 0); 92 if (x == 0 || x > 65535) { 93 fprintf(stderr, "Error: invalid portbase 0x%"PRIx32"\n", x); 94 goto usage; 95 } 96 params.portbase = x; 97 } else if (strncmp(argv[i], "irq=", sizeof("irq=") - 1) == 0) { 98 uint32_t x= 99 strtoul(argv[i] + sizeof("irq=") - 1, NULL, 0); 100 if (x == 0) { 101 fprintf(stderr, "Error: invalid IRQ %"PRIu32"\n", x); 102 goto usage; 103 } 104 params.irq = x; 105 } else if (strncmp(argv[i], "membase=", sizeof("membase=") - 1) == 0) { 106 uint64_t x= 107 strtoull(argv[i] + sizeof("membase=") - 1, NULL, 0); 108 params.membase = x; 109 } else if (strncmp(argv[i], "name=", sizeof("name=") - 1) == 0) { 110 driver_name = argv[i] + sizeof("name=") - 1; 111 } else if (strncmp(argv[i], "auto", 4) == 0) { 112 // do nothing, means we are being started through kaluga 113 } else if (strncmp(argv[i], "int_model=", sizeof("int_model=") - 1) == 0) { 114 // ignore. x86 just assumes that legacy interrupts are used. 115 } else { 116 fprintf(stderr, "Error: unknown option %s\n", argv[i]); 117 goto usage; 118 } 119 } 120 121 // Initialize serial driver 122 err = serial_init(¶ms); 123 if (err_is_fail(err)) { 124 USER_PANIC_ERR(err, "Error initializing serial driver."); 125 } 126 127 SERIAL_DEBUG("Serial driver initialized.\n" 128 "Using driver name %s.\n", driver_name); 129 130 // Stick around waiting for input 131 struct waitset *ws = get_default_waitset(); 132 while (1) { 133 err = event_dispatch(ws); 134 if (err_is_fail(err)) { 135 USER_PANIC_ERR(err, "Error dispatching events."); 136 } 137 } 138 139 return EXIT_SUCCESS; 140 141usage: 142 fprintf(stderr, "Usage: %s [portbase=PORT] [irq=IRQ] [name=NAME]\n" 143 " [membase=ADDR] [kernel]\n", argv[0]); 144 return 1; 145} 146