2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
* PDC Console support - ie use firmware to dump text via boot console
*
* Copyright ( C ) 1999 - 2003 Matthew Wilcox < willy at parisc - linux . org >
* Copyright ( C ) 2000 Martin K Petersen < mkp at mkp . net >
* Copyright ( C ) 2000 John Marvin < jsm at parisc - linux . org >
* Copyright ( C ) 2000 - 2003 Paul Bame < bame at parisc - linux . org >
* Copyright ( C ) 2000 Philipp Rumpf < prumpf with tux . org >
* Copyright ( C ) 2000 Michael Ang < mang with subcarrier . org >
* Copyright ( C ) 2000 Grant Grundler < grundler with parisc - linux . org >
* Copyright ( C ) 2001 - 2002 Ryan Bradetich < rbrad at parisc - linux . org >
* Copyright ( C ) 2001 Helge Deller < deller at parisc - linux . org >
* Copyright ( C ) 2001 Thomas Bogendoerfer < tsbogend at parisc - linux . org >
* Copyright ( C ) 2002 Randolph Chung < tausq with parisc - linux . org >
2010-06-14 21:24:41 +04:00
* Copyright ( C ) 2010 Guy Martin < gmsoft at tuxicoman . be >
2005-04-17 02:20:36 +04:00
*/
/*
* The PDC console is a simple console , which can be used for debugging
2010-06-14 21:24:41 +04:00
* boot related problems on HP PA - RISC machines . It is also useful when no
* other console works .
2005-04-17 02:20:36 +04:00
*
* This code uses the ROM ( = PDC ) based functions to read and write characters
* from and to PDC ' s boot path .
*/
/* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems.
* On production kernels EARLY_BOOTUP_DEBUG should be undefined . */
2005-10-22 06:50:06 +04:00
# define EARLY_BOOTUP_DEBUG
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/console.h>
# include <linux/string.h>
# include <linux/init.h>
# include <linux/major.h>
# include <linux/tty.h>
parisc: move definition of PAGE0 to asm/page.h
This was defined in asm/pdc.h which needs to include asm/page.h for
__PAGE_OFFSET. This leads to an include loop so that page.h eventually will
include pdc.h again. While this is no problem because of header guards, it is
a problem because some symbols may be undefined. Such an error is this:
In file included from include/linux/bitops.h:35:0,
from include/asm-generic/getorder.h:7,
from arch/parisc/include/asm/page.h:162,
from arch/parisc/include/asm/pdc.h:346,
from arch/parisc/include/asm/processor.h:16,
from arch/parisc/include/asm/spinlock.h:6,
from arch/parisc/include/asm/atomic.h:20,
from include/linux/atomic.h:4,
from include/linux/sysfs.h:20,
from include/linux/kobject.h:21,
from include/linux/device.h:17,
from include/linux/eisa.h:5,
from arch/parisc/kernel/pci.c:11:
arch/parisc/include/asm/bitops.h: In function ‘set_bit’:
arch/parisc/include/asm/bitops.h:82:2: error: implicit declaration of function ‘_atomic_spin_lock_irqsave’ [-Werror=implicit-function-declaration]
arch/parisc/include/asm/bitops.h:84:2: error: implicit declaration of function ‘_atomic_spin_unlock_irqrestore’ [-Werror=implicit-function-declaration]
Signed-off-by: Rolf Eike Beer <eike-kernel@sf-tec.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-05-11 01:08:17 +04:00
# include <asm/page.h> /* for PAGE0 */
2005-04-17 02:20:36 +04:00
# include <asm/pdc.h> /* for iodc_call() proto and friends */
2008-12-25 22:33:11 +03:00
static DEFINE_SPINLOCK ( pdc_console_lock ) ;
2010-06-14 21:24:41 +04:00
static struct console pdc_cons ;
2005-04-17 02:20:36 +04:00
static void pdc_console_write ( struct console * co , const char * s , unsigned count )
{
2008-02-19 10:34:34 +03:00
int i = 0 ;
unsigned long flags ;
spin_lock_irqsave ( & pdc_console_lock , flags ) ;
do {
i + = pdc_iodc_print ( s + i , count - i ) ;
} while ( i < count ) ;
spin_unlock_irqrestore ( & pdc_console_lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
int pdc_console_poll_key ( struct console * co )
{
2008-02-19 10:34:34 +03:00
int c ;
unsigned long flags ;
spin_lock_irqsave ( & pdc_console_lock , flags ) ;
c = pdc_iodc_getc ( ) ;
spin_unlock_irqrestore ( & pdc_console_lock , flags ) ;
return c ;
2005-04-17 02:20:36 +04:00
}
static int pdc_console_setup ( struct console * co , char * options )
{
return 0 ;
}
# if defined(CONFIG_PDC_CONSOLE)
2006-07-10 15:44:12 +04:00
# include <linux/vt_kern.h>
2010-06-14 21:24:41 +04:00
# include <linux/tty_flip.h>
# define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
2017-08-28 21:28:21 +03:00
static void pdc_console_poll ( struct timer_list * unused ) ;
2017-10-05 02:27:04 +03:00
static DEFINE_TIMER ( pdc_console_timer , pdc_console_poll ) ;
2012-03-05 17:52:53 +04:00
static struct tty_port tty_port ;
2010-06-14 21:24:41 +04:00
static int pdc_console_tty_open ( struct tty_struct * tty , struct file * filp )
{
2012-03-05 17:52:53 +04:00
tty_port_tty_set ( & tty_port , tty ) ;
2010-06-14 21:24:41 +04:00
mod_timer ( & pdc_console_timer , jiffies + PDC_CONS_POLL_DELAY ) ;
return 0 ;
}
static void pdc_console_tty_close ( struct tty_struct * tty , struct file * filp )
{
2012-05-06 00:49:10 +04:00
if ( tty - > count = = 1 ) {
2012-03-05 17:52:50 +04:00
del_timer_sync ( & pdc_console_timer ) ;
2012-03-05 17:52:53 +04:00
tty_port_tty_set ( & tty_port , NULL ) ;
}
2010-06-14 21:24:41 +04:00
}
static int pdc_console_tty_write ( struct tty_struct * tty , const unsigned char * buf , int count )
{
pdc_console_write ( NULL , buf , count ) ;
return count ;
}
static int pdc_console_tty_write_room ( struct tty_struct * tty )
{
return 32768 ; /* no limit, no buffer used */
}
static int pdc_console_tty_chars_in_buffer ( struct tty_struct * tty )
{
return 0 ; /* no buffer */
}
static const struct tty_operations pdc_console_tty_ops = {
. open = pdc_console_tty_open ,
. close = pdc_console_tty_close ,
. write = pdc_console_tty_write ,
. write_room = pdc_console_tty_write_room ,
. chars_in_buffer = pdc_console_tty_chars_in_buffer ,
} ;
2017-08-28 21:28:21 +03:00
static void pdc_console_poll ( struct timer_list * unused )
2010-06-14 21:24:41 +04:00
{
int data , count = 0 ;
while ( 1 ) {
data = pdc_console_poll_key ( NULL ) ;
if ( data = = - 1 )
break ;
2013-01-03 18:53:03 +04:00
tty_insert_flip_char ( & tty_port , data & 0xFF , TTY_NORMAL ) ;
2010-06-14 21:24:41 +04:00
count + + ;
}
if ( count )
2013-01-03 18:53:06 +04:00
tty_flip_buffer_push ( & tty_port ) ;
2012-03-05 17:52:53 +04:00
2012-03-05 17:52:50 +04:00
if ( pdc_cons . flags & CON_ENABLED )
2010-06-14 21:24:41 +04:00
mod_timer ( & pdc_console_timer , jiffies + PDC_CONS_POLL_DELAY ) ;
}
2012-03-05 17:52:53 +04:00
static struct tty_driver * pdc_console_tty_driver ;
2010-06-14 21:24:41 +04:00
static int __init pdc_console_tty_driver_init ( void )
{
int err ;
/* Check if the console driver is still registered.
* It is unregistered if the pdc console was not selected as the
* primary console . */
2010-11-04 18:20:21 +03:00
struct console * tmp ;
2010-06-14 21:24:41 +04:00
2011-01-26 02:07:35 +03:00
console_lock ( ) ;
2010-11-04 18:20:21 +03:00
for_each_console ( tmp )
2010-06-14 21:24:41 +04:00
if ( tmp = = & pdc_cons )
break ;
2011-01-26 02:07:35 +03:00
console_unlock ( ) ;
2010-06-14 21:24:41 +04:00
if ( ! tmp ) {
printk ( KERN_INFO " PDC console driver not registered anymore, not creating %s \n " , pdc_cons . name ) ;
return - ENODEV ;
}
printk ( KERN_INFO " The PDC console driver is still registered, removing CON_BOOT flag \n " ) ;
pdc_cons . flags & = ~ CON_BOOT ;
2012-03-05 17:52:52 +04:00
pdc_console_tty_driver = alloc_tty_driver ( 1 ) ;
2010-06-14 21:24:41 +04:00
2012-03-05 17:52:52 +04:00
if ( ! pdc_console_tty_driver )
2010-06-14 21:24:41 +04:00
return - ENOMEM ;
2012-11-15 12:49:56 +04:00
tty_port_init ( & tty_port ) ;
2012-03-05 17:52:52 +04:00
pdc_console_tty_driver - > driver_name = " pdc_cons " ;
pdc_console_tty_driver - > name = " ttyB " ;
pdc_console_tty_driver - > major = MUX_MAJOR ;
pdc_console_tty_driver - > minor_start = 0 ;
pdc_console_tty_driver - > type = TTY_DRIVER_TYPE_SYSTEM ;
pdc_console_tty_driver - > init_termios = tty_std_termios ;
pdc_console_tty_driver - > flags = TTY_DRIVER_REAL_RAW |
TTY_DRIVER_RESET_TERMIOS ;
tty_set_operations ( pdc_console_tty_driver , & pdc_console_tty_ops ) ;
2012-08-07 23:47:51 +04:00
tty_port_link_device ( & tty_port , pdc_console_tty_driver , 0 ) ;
2012-03-05 17:52:52 +04:00
err = tty_register_driver ( pdc_console_tty_driver ) ;
2010-06-14 21:24:41 +04:00
if ( err ) {
printk ( KERN_ERR " Unable to register the PDC console TTY driver \n " ) ;
2012-11-15 12:49:56 +04:00
tty_port_destroy ( & tty_port ) ;
2010-06-14 21:24:41 +04:00
return err ;
}
return 0 ;
}
2015-05-02 03:05:50 +03:00
device_initcall ( pdc_console_tty_driver_init ) ;
2006-07-10 15:44:12 +04:00
2005-04-17 02:20:36 +04:00
static struct tty_driver * pdc_console_device ( struct console * c , int * index )
{
2010-06-14 21:24:41 +04:00
* index = c - > index ;
return pdc_console_tty_driver ;
2005-04-17 02:20:36 +04:00
}
# else
2005-10-22 06:50:06 +04:00
# define pdc_console_device NULL
2005-04-17 02:20:36 +04:00
# endif
static struct console pdc_cons = {
. name = " ttyB " ,
. write = pdc_console_write ,
2005-10-22 06:50:06 +04:00
. device = pdc_console_device ,
2005-04-17 02:20:36 +04:00
. setup = pdc_console_setup ,
2010-06-14 21:24:41 +04:00
. flags = CON_BOOT | CON_PRINTBUFFER ,
2005-04-17 02:20:36 +04:00
. index = - 1 ,
} ;
static int pdc_console_initialized ;
static void pdc_console_init_force ( void )
{
if ( pdc_console_initialized )
return ;
+ + pdc_console_initialized ;
/* If the console is duplex then copy the COUT parameters to CIN. */
if ( PAGE0 - > mem_cons . cl_class = = CL_DUPLEX )
memcpy ( & PAGE0 - > mem_kbd , & PAGE0 - > mem_cons , sizeof ( PAGE0 - > mem_cons ) ) ;
/* register the pdc console */
register_console ( & pdc_cons ) ;
}
void __init pdc_console_init ( void )
{
# if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
pdc_console_init_force ( ) ;
# endif
# ifdef EARLY_BOOTUP_DEBUG
printk ( KERN_INFO " Initialized PDC Console for debugging. \n " ) ;
# endif
}
/*
* Used for emergencies . Currently only used if an HPMC occurs . If an
* HPMC occurs , it is possible that the current console may not be
2005-10-22 06:50:06 +04:00
* properly initialised after the PDC IO reset . This routine unregisters
* all of the current consoles , reinitializes the pdc console and
2005-04-17 02:20:36 +04:00
* registers it .
*/
void pdc_console_restart ( void )
{
struct console * console ;
if ( pdc_console_initialized )
return ;
2005-10-22 06:50:06 +04:00
/* If we've already seen the output, don't bother to print it again */
if ( console_drivers ! = NULL )
pdc_cons . flags & = ~ CON_PRINTBUFFER ;
2005-04-17 02:20:36 +04:00
while ( ( console = console_drivers ) ! = NULL )
unregister_console ( console_drivers ) ;
/* force registering the pdc console */
pdc_console_init_force ( ) ;
}