162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * printf.c:  Internal prom library printf facility.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
662306a36Sopenharmony_ci * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
762306a36Sopenharmony_ci * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * We used to warn all over the code: DO NOT USE prom_printf(),
1062306a36Sopenharmony_ci * and yet people do. Anton's banking code was outputting banks
1162306a36Sopenharmony_ci * with prom_printf for most of the 2.4 lifetime. Since an effective
1262306a36Sopenharmony_ci * stick is not available, we deployed a carrot: an early printk
1362306a36Sopenharmony_ci * through PROM by means of -p boot option. This ought to fix it.
1462306a36Sopenharmony_ci * USE printk; if you need, deploy -p.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/compiler.h>
1962306a36Sopenharmony_ci#include <linux/spinlock.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <asm/openprom.h>
2262306a36Sopenharmony_ci#include <asm/oplib.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define CONSOLE_WRITE_BUF_SIZE	1024
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic char ppbuf[1024];
2762306a36Sopenharmony_cistatic char console_write_buf[CONSOLE_WRITE_BUF_SIZE];
2862306a36Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(console_write_lock);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_civoid notrace prom_write(const char *buf, unsigned int n)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	unsigned int dest_len;
3362306a36Sopenharmony_ci	unsigned long flags;
3462306a36Sopenharmony_ci	char *dest;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	dest = console_write_buf;
3762306a36Sopenharmony_ci	raw_spin_lock_irqsave(&console_write_lock, flags);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	dest_len = 0;
4062306a36Sopenharmony_ci	while (n-- != 0) {
4162306a36Sopenharmony_ci		char ch = *buf++;
4262306a36Sopenharmony_ci		if (ch == '\n') {
4362306a36Sopenharmony_ci			*dest++ = '\r';
4462306a36Sopenharmony_ci			dest_len++;
4562306a36Sopenharmony_ci		}
4662306a36Sopenharmony_ci		*dest++ = ch;
4762306a36Sopenharmony_ci		dest_len++;
4862306a36Sopenharmony_ci		if (dest_len >= CONSOLE_WRITE_BUF_SIZE - 1) {
4962306a36Sopenharmony_ci			prom_console_write_buf(console_write_buf, dest_len);
5062306a36Sopenharmony_ci			dest = console_write_buf;
5162306a36Sopenharmony_ci			dest_len = 0;
5262306a36Sopenharmony_ci		}
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci	if (dest_len)
5562306a36Sopenharmony_ci		prom_console_write_buf(console_write_buf, dest_len);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&console_write_lock, flags);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_civoid notrace prom_printf(const char *fmt, ...)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	va_list args;
6362306a36Sopenharmony_ci	int i;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	va_start(args, fmt);
6662306a36Sopenharmony_ci	i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args);
6762306a36Sopenharmony_ci	va_end(args);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	prom_write(ppbuf, i);
7062306a36Sopenharmony_ci}
71