blob: 5bff9fdd5df7b3708739eb099475fa7915f102c7 [file] [log] [blame]
/*
* Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* Generic UARTs
*
*/
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <ipxe/uart.h>
/** List of registered UARTs */
LIST_HEAD ( uarts );
static void null_uart_transmit ( struct uart *uart __unused,
uint8_t byte __unused ) {
}
static int null_uart_data_ready ( struct uart *uart __unused ) {
return 0;
}
static uint8_t null_uart_receive ( struct uart *uart __unused ) {
return 0;
}
static int null_uart_init ( struct uart *uart __unused ) {
return 0;
}
static void null_uart_flush ( struct uart *uart __unused ) {
}
/** Null UART operations */
struct uart_operations null_uart_operations = {
.transmit = null_uart_transmit,
.data_ready = null_uart_data_ready,
.receive = null_uart_receive,
.init = null_uart_init,
.flush = null_uart_flush,
};
/**
* Allocate UART
*
* @v priv_len Length of private data
* @ret uart UART, or NULL on error
*/
struct uart * alloc_uart ( size_t priv_len ) {
struct uart *uart;
/* Allocate and initialise UART */
uart = zalloc ( sizeof ( *uart ) + priv_len );
if ( ! uart )
return NULL;
uart->priv = ( ( ( void * ) uart ) + sizeof ( *uart ) );
return uart;
}
/**
* Register fixed UARTs (when not provided by platform)
*
* @ret rc Return status code
*/
__weak int uart_register_fixed ( void ) {
return 0;
}
/**
* Register UART
*
* @v uart UART
* @ret rc Return status code
*/
int uart_register ( struct uart *uart ) {
/* Add to list of registered UARTs */
uart_get ( uart );
list_add_tail ( &uart->list, &uarts );
DBGC ( uart, "UART %s registered\n", uart->name );
return 0;
}
/**
* Unregister UART
*
* @v uart UART
*/
void uart_unregister ( struct uart *uart ) {
/* Remove from list of registered UARTs */
list_del ( &uart->list );
uart_put ( uart );
}
/**
* Find named UART
*
* @v name UART name
* @ret uart UART, or NULL if not found
*/
struct uart * uart_find ( const char *name ) {
struct uart *uart;
unsigned int index;
char *endp;
int rc;
/* Register fixed platform UARTs if not already registered */
if ( list_empty ( &uarts ) ) {
if ( ( rc = uart_register_fixed() ) != 0 ) {
DBGC ( &uarts, "UART could not register fixed UARTs: "
"%s\n", strerror ( rc ) );
/* Continue anyway */
}
}
/* Try parsing name as a numeric index */
index = strtoul ( name, &endp, 10 );
/* Find matching UART, if any */
list_for_each_entry ( uart, &uarts, list ) {
/* Check for a matching name */
if ( strcasecmp ( name, uart->name ) == 0 )
return uart;
/* Check for a matching numeric index */
if ( ( *endp == '\0' ) && ( index-- == 0 ) )
return uart;
}
DBGC ( &uarts, "UART %s not found\n", name );
return NULL;
}