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