Home | History | Annotate | Line # | Download | only in fdt
      1 /* $NetBSD: fdt_console.c,v 1.1 2025/09/06 22:53:48 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2015 Jared D. McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: fdt_console.c,v 1.1 2025/09/06 22:53:48 thorpej Exp $");
     31 
     32 #include "opt_fdt.h"
     33 
     34 #include <sys/param.h>
     35 #include <sys/bus.h>
     36 
     37 #include <libfdt.h>
     38 #include <dev/fdt/fdtvar.h>
     39 #include <dev/fdt/fdt_console.h>
     40 
     41 #ifndef FDT_DEFAULT_STDOUT_PATH
     42 #define	FDT_DEFAULT_STDOUT_PATH		"serial0:115200n8"
     43 #endif
     44 
     45 const struct fdt_console *
     46 fdtbus_get_console(void)
     47 {
     48 	static const struct fdt_console_info *booted_console = NULL;
     49 
     50 	if (booted_console == NULL) {
     51 		__link_set_decl(fdt_consoles, struct fdt_console_info);
     52 		struct fdt_console_info * const *info;
     53 		const struct fdt_console_info *best_info = NULL;
     54 		const int phandle = fdtbus_get_stdout_phandle();
     55 		int best_match = 0;
     56 
     57 		if (phandle == -1) {
     58 			printf("WARNING: no console device\n");
     59 			return NULL;
     60 		}
     61 
     62 		__link_set_foreach(info, fdt_consoles) {
     63 			const int match = (*info)->ops->match(phandle);
     64 			if (match > best_match) {
     65 				best_match = match;
     66 				best_info = *info;
     67 			}
     68 		}
     69 
     70 		booted_console = best_info;
     71 	}
     72 
     73 	return booted_console == NULL ? NULL : booted_console->ops;
     74 }
     75 
     76 const char *
     77 fdtbus_get_stdout_path(void)
     78 {
     79 	const char *prop;
     80 
     81 	const int off = fdt_path_offset(fdtbus_get_data(), "/chosen");
     82 	if (off >= 0) {
     83 		prop = fdt_getprop(fdtbus_get_data(), off, "stdout-path", NULL);
     84 		if (prop != NULL)
     85 			return prop;
     86 	}
     87 
     88 	/* If the stdout-path property is not found, return the default */
     89 	return FDT_DEFAULT_STDOUT_PATH;
     90 }
     91 
     92 int
     93 fdtbus_get_stdout_phandle(void)
     94 {
     95 	const char *prop, *p;
     96 	int off, len;
     97 
     98 	prop = fdtbus_get_stdout_path();
     99 	if (prop == NULL)
    100 		return -1;
    101 
    102 	p = strchr(prop, ':');
    103 	len = p == NULL ? strlen(prop) : (p - prop);
    104 	if (*prop != '/') {
    105 		/* Alias */
    106 		prop = fdt_get_alias_namelen(fdtbus_get_data(), prop, len);
    107 		if (prop == NULL)
    108 			return -1;
    109 		len = strlen(prop);
    110 	}
    111 	off = fdt_path_offset_namelen(fdtbus_get_data(), prop, len);
    112 	if (off < 0)
    113 		return -1;
    114 
    115 	return fdtbus_offset2phandle(off);
    116 }
    117 
    118 int
    119 fdtbus_get_stdout_speed(void)
    120 {
    121 	const char *prop, *p;
    122 
    123 	prop = fdtbus_get_stdout_path();
    124 	if (prop == NULL)
    125 		return -1;
    126 
    127 	p = strchr(prop, ':');
    128 	if (p == NULL)
    129 		return -1;
    130 
    131 	return (int)strtoul(p + 1, NULL, 10);
    132 }
    133 
    134 tcflag_t
    135 fdtbus_get_stdout_flags(void)
    136 {
    137 	const char *prop, *p;
    138 	tcflag_t flags = TTYDEF_CFLAG;
    139 	char *ep;
    140 
    141 	prop = fdtbus_get_stdout_path();
    142 	if (prop == NULL)
    143 		return flags;
    144 
    145 	p = strchr(prop, ':');
    146 	if (p == NULL)
    147 		return flags;
    148 
    149 	ep = NULL;
    150 	(void)strtoul(p + 1, &ep, 10);
    151 	if (ep == NULL)
    152 		return flags;
    153 
    154 	/* <baud>{<parity>{<bits>{<flow>}}} */
    155 	while (*ep) {
    156 		switch (*ep) {
    157 		/* parity */
    158 		case 'n':	flags &= ~(PARENB|PARODD); break;
    159 		case 'e':	flags &= ~PARODD; flags |= PARENB; break;
    160 		case 'o':	flags |= (PARENB|PARODD); break;
    161 		/* bits */
    162 		case '5':	flags &= ~CSIZE; flags |= CS5; break;
    163 		case '6':	flags &= ~CSIZE; flags |= CS6; break;
    164 		case '7':	flags &= ~CSIZE; flags |= CS7; break;
    165 		case '8':	flags &= ~CSIZE; flags |= CS8; break;
    166 		/* flow */
    167 		case 'r':	flags |= CRTSCTS; break;
    168 		}
    169 		ep++;
    170 	}
    171 
    172 	return flags;
    173 }
    174