Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*	$NetBSD: unixcons.c,v 1.3 2014/03/26 08:02:38 christos Exp $	*/

/*
 * Copyright (c) 2009 NONAKA Kimihiro <nonaka@netbsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "boot.h"
#include "bootinfo.h"
#include "unixdev.h"

#include "compat_linux.h"
#include "termios.h"

struct btinfo_console bi_cons;

static int iodev = CONSDEV_GLASS;
static int infd = 0;
static int outfd = 1;

static const char *comdevname[] = {
	"/dev/ttyS0",
};

static void common_putc(int fd, int c);
static int common_getc(int fd, int timo);

void
consinit(int dev, int speed)
{
	struct linux_termios termios;
	int fd;

	switch (dev) {
	case CONSDEV_COM0:
		iodev = dev;
		break;

	case CONSDEV_GLASS:
	default:
 glass_console:
		iodev = CONSDEV_GLASS;
		break;
	}

	if (infd >= 0 && infd == outfd) {
		uclose(infd);
		infd = 0;
		outfd = 1;
	}

	if (iodev == CONSDEV_GLASS) {
		infd = 0;
		outfd = 1;

		strlcpy(bi_cons.devname, "glass", sizeof(bi_cons.devname));
		bi_cons.addr = -1;
		bi_cons.speed = -1;
	} else {
		fd = uopen(comdevname[iodev - CONSDEV_COM0], LINUX_O_RDWR);
		if (fd < 0)
			goto glass_console;
		infd = outfd = fd;

		/* set speed */
		linux_tcgetattr(fd, &termios);
		if (linux_cfsetspeed(&termios, speed) < 0) {
			speed = 9600;
			if (linux_cfsetspeed(&termios, speed) < 0)
				goto glass_console;
		}
		if (linux_tcsetattr(fd, LINUX_TCSETS, &termios) < 0)
			goto glass_console;

		snprintf(bi_cons.devname, sizeof(bi_cons.devname), "com%d",
		    iodev - CONSDEV_COM0);
		bi_cons.addr = -1;
		bi_cons.speed = speed;
	}
	BI_ADD(&bi_cons, BTINFO_CONSDEV, sizeof(bi_cons));
}

void
putchar(int c)
{

	common_putc(outfd, c);
}

int
getchar(void)
{

	return common_getc(infd, 1);
}

static void
common_putc(int fd, int c)
{

	(void)uwrite(fd, &c, 1);
}

static int
common_getc(int fd, int timo)
{
	struct linux_timeval tv;
	fd_set fdset;
	int nfds, n;
	char c;

	for (; timo < 0 || timo > 0; --timo) {
		tv.tv_sec = 1;
		tv.tv_usec = 0;
		FD_ZERO(&fdset);

		nfds = 1;
		FD_SET(fd, &fdset);

		n = uselect(nfds, &fdset, NULL, NULL, &tv);
		if (n > 0)
			break;
	}

	if (timo > 0) {
		for (fd = 0; fd < nfds; fd++) {
			if (FD_ISSET(fd, &fdset)) {
				return (uread(fd, &c, 1) < 1 ? -1 : c);
			}
		}
	}
	return -1;
}

int
awaitkey(int timeout, int tell)
{
	struct linux_termios orig_termios, raw_termios;
	int c = 0;
	int i;

	/* set raw mode */
	linux_tcgetattr(infd, &orig_termios);
	raw_termios = orig_termios;
	linux_cfmakeraw(&raw_termios);
	linux_tcsetattr(infd, LINUX_TCSETS, &raw_termios);

	for (i = timeout; i > 0; i--) {
		if (tell) {
			char numbuf[20];
			int len, j;

			len = snprintf(numbuf, sizeof(numbuf), "%d ", i);
			for (j = 0; j < len; j++)
				numbuf[len + j] = '\b';
			numbuf[len + j] = '\0';
			printf("%s", numbuf);
		}
		c = common_getc(infd, 1);
		if (c == 0)
			c = -1;
		if (c >= 0)
			break;
	}
	if (i == 0)
		c = '\0';

	/* set original mode */
	linux_tcsetattr(infd, LINUX_TCSETS, &orig_termios);

	if (tell)
		printf("0 \n");

	return c;
}

void dummycall2(void);
void
dummycall2(void)
{

	(void)linux_termio_to_bsd_termios;
	(void)bsd_termios_to_linux_termio;
	(void)linux_termios_to_bsd_termios;
	(void)bsd_termios_to_linux_termios;
}