18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * printf.c:  Internal prom library printf facility.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
68c2ecf20Sopenharmony_ci * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
78c2ecf20Sopenharmony_ci * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * We used to warn all over the code: DO NOT USE prom_printf(),
108c2ecf20Sopenharmony_ci * and yet people do. Anton's banking code was outputting banks
118c2ecf20Sopenharmony_ci * with prom_printf for most of the 2.4 lifetime. Since an effective
128c2ecf20Sopenharmony_ci * stick is not available, we deployed a carrot: an early printk
138c2ecf20Sopenharmony_ci * through PROM by means of -p boot option. This ought to fix it.
148c2ecf20Sopenharmony_ci * USE printk; if you need, deploy -p.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/kernel.h>
188c2ecf20Sopenharmony_ci#include <linux/compiler.h>
198c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <asm/openprom.h>
228c2ecf20Sopenharmony_ci#include <asm/oplib.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define CONSOLE_WRITE_BUF_SIZE	1024
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic char ppbuf[1024];
278c2ecf20Sopenharmony_cistatic char console_write_buf[CONSOLE_WRITE_BUF_SIZE];
288c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(console_write_lock);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_civoid notrace prom_write(const char *buf, unsigned int n)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	unsigned int dest_len;
338c2ecf20Sopenharmony_ci	unsigned long flags;
348c2ecf20Sopenharmony_ci	char *dest;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	dest = console_write_buf;
378c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&console_write_lock, flags);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	dest_len = 0;
408c2ecf20Sopenharmony_ci	while (n-- != 0) {
418c2ecf20Sopenharmony_ci		char ch = *buf++;
428c2ecf20Sopenharmony_ci		if (ch == '\n') {
438c2ecf20Sopenharmony_ci			*dest++ = '\r';
448c2ecf20Sopenharmony_ci			dest_len++;
458c2ecf20Sopenharmony_ci		}
468c2ecf20Sopenharmony_ci		*dest++ = ch;
478c2ecf20Sopenharmony_ci		dest_len++;
488c2ecf20Sopenharmony_ci		if (dest_len >= CONSOLE_WRITE_BUF_SIZE - 1) {
498c2ecf20Sopenharmony_ci			prom_console_write_buf(console_write_buf, dest_len);
508c2ecf20Sopenharmony_ci			dest = console_write_buf;
518c2ecf20Sopenharmony_ci			dest_len = 0;
528c2ecf20Sopenharmony_ci		}
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci	if (dest_len)
558c2ecf20Sopenharmony_ci		prom_console_write_buf(console_write_buf, dest_len);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&console_write_lock, flags);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_civoid notrace prom_printf(const char *fmt, ...)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	va_list args;
638c2ecf20Sopenharmony_ci	int i;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	va_start(args, fmt);
668c2ecf20Sopenharmony_ci	i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args);
678c2ecf20Sopenharmony_ci	va_end(args);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	prom_write(ppbuf, i);
708c2ecf20Sopenharmony_ci}
71