Commit c73fcc84 authored by David S. Miller's avatar David S. Miller

[SPARC]: Fix serial console device detection.

The current scheme works on static interpretation of text names, which
is wrong.

The output-device setting, for example, must be resolved via an alias
or similar to a full path name to the console device.

Paths also contain an optional set of 'options', which starts with a
colon at the end of the path.  The option area is used to specify
which of two serial ports ('a' or 'b') the path refers to when a
device node drives multiple ports.  'a' is assumed if the option
specification is missing.

This was caught by the UltraSPARC-T1 simulator.  The 'output-device'
property was set to 'ttya' and we didn't pick upon the fact that this
is an OBP alias set to '/virtual-devices/console'.  Instead we saw it
as the first serial console device, instead of the hypervisor console.

The infrastructure is now there to take advantage of this to resolve
the console correctly even in multi-head situations in fbcon too.

Thanks to Greg Onufer for the bug report.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ede13d81
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/psr.h> #include <asm/psr.h>
#include <asm/elf.h> #include <asm/elf.h>
#include <asm/prom.h>
#include <asm/unistd.h> #include <asm/unistd.h>
/* /*
...@@ -150,7 +151,7 @@ void machine_halt(void) ...@@ -150,7 +151,7 @@ void machine_halt(void)
local_irq_enable(); local_irq_enable();
mdelay(8); mdelay(8);
local_irq_disable(); local_irq_disable();
if (!serial_console && prom_palette) if (prom_palette)
prom_palette (1); prom_palette (1);
prom_halt(); prom_halt();
panic("Halt failed!"); panic("Halt failed!");
...@@ -166,7 +167,7 @@ void machine_restart(char * cmd) ...@@ -166,7 +167,7 @@ void machine_restart(char * cmd)
p = strchr (reboot_command, '\n'); p = strchr (reboot_command, '\n');
if (p) *p = 0; if (p) *p = 0;
if (!serial_console && prom_palette) if (prom_palette)
prom_palette (1); prom_palette (1);
if (cmd) if (cmd)
prom_reboot(cmd); prom_reboot(cmd);
...@@ -179,7 +180,8 @@ void machine_restart(char * cmd) ...@@ -179,7 +180,8 @@ void machine_restart(char * cmd)
void machine_power_off(void) void machine_power_off(void)
{ {
#ifdef CONFIG_SUN_AUXIO #ifdef CONFIG_SUN_AUXIO
if (auxio_power_register && (!serial_console || scons_pwroff)) if (auxio_power_register &&
(strcmp(of_console_device->type, "serial") || scons_pwroff))
*auxio_power_register |= AUXIO_POWER_OFF; *auxio_power_register |= AUXIO_POWER_OFF;
#endif #endif
machine_halt(); machine_halt();
......
...@@ -397,6 +397,135 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl ...@@ -397,6 +397,135 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
return dp; return dp;
} }
struct device_node *of_console_device;
EXPORT_SYMBOL(of_console_device);
char *of_console_path;
EXPORT_SYMBOL(of_console_path);
char *of_console_options;
EXPORT_SYMBOL(of_console_options);
extern void restore_current(void);
static void __init of_console_init(void)
{
char *msg = "OF stdout device is: %s\n";
struct device_node *dp;
unsigned long flags;
const char *type;
phandle node;
int skip, fd;
of_console_path = prom_early_alloc(256);
switch (prom_vers) {
case PROM_V0:
case PROM_SUN4:
skip = 0;
switch (*romvec->pv_stdout) {
case PROMDEV_SCREEN:
type = "display";
break;
case PROMDEV_TTYB:
skip = 1;
/* FALLTHRU */
case PROMDEV_TTYA:
type = "serial";
break;
default:
prom_printf("Invalid PROM_V0 stdout value %u\n",
*romvec->pv_stdout);
prom_halt();
}
for_each_node_by_type(dp, type) {
if (!skip--)
break;
}
if (!dp) {
prom_printf("Cannot find PROM_V0 console node.\n");
prom_halt();
}
of_console_device = dp;
strcpy(of_console_path, dp->full_name);
if (!strcmp(type, "serial")) {
strcat(of_console_path,
(skip ? ":b" : ":a"));
}
break;
default:
case PROM_V2:
case PROM_V3:
fd = *romvec->pv_v2bootargs.fd_stdout;
spin_lock_irqsave(&prom_lock, flags);
node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
restore_current();
spin_unlock_irqrestore(&prom_lock, flags);
if (!node) {
prom_printf("Cannot resolve stdout node from "
"instance %08x.\n", fd);
prom_halt();
}
dp = of_find_node_by_phandle(node);
type = of_get_property(dp, "device_type", NULL);
if (!type) {
prom_printf("Console stdout lacks "
"device_type property.\n");
prom_halt();
}
if (strcmp(type, "display") && strcmp(type, "serial")) {
prom_printf("Console device_type is neither display "
"nor serial.\n");
prom_halt();
}
of_console_device = dp;
if (prom_vers == PROM_V2) {
strcpy(of_console_path, dp->full_name);
switch (*romvec->pv_stdout) {
case PROMDEV_TTYA:
strcat(of_console_path, ":a");
break;
case PROMDEV_TTYB:
strcat(of_console_path, ":b");
break;
}
} else {
const char *path;
dp = of_find_node_by_path("/");
path = of_get_property(dp, "stdout-path", NULL);
if (!path) {
prom_printf("No stdout-path in root node.\n");
prom_halt();
}
strcpy(of_console_path, path);
}
break;
}
of_console_options = strrchr(of_console_path, ':');
if (of_console_options) {
of_console_options++;
if (*of_console_options == '\0')
of_console_options = NULL;
}
prom_printf(msg, of_console_path);
printk(msg, of_console_path);
}
void __init prom_build_devicetree(void) void __init prom_build_devicetree(void)
{ {
struct device_node **nextp; struct device_node **nextp;
...@@ -409,6 +538,8 @@ void __init prom_build_devicetree(void) ...@@ -409,6 +538,8 @@ void __init prom_build_devicetree(void)
allnodes->child = build_tree(allnodes, allnodes->child = build_tree(allnodes,
prom_getchild(allnodes->node), prom_getchild(allnodes->node),
&nextp); &nextp);
of_console_init();
printk("PROM: Built device tree with %u bytes of memory.\n", printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated); prom_early_allocated);
} }
...@@ -146,31 +146,6 @@ static void __init process_switch(char c) ...@@ -146,31 +146,6 @@ static void __init process_switch(char c)
} }
} }
static void __init process_console(char *commands)
{
serial_console = 0;
commands += 8;
/* Linux-style serial */
if (!strncmp(commands, "ttyS", 4))
serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
else if (!strncmp(commands, "tty", 3)) {
char c = *(commands + 3);
/* Solaris-style serial */
if (c == 'a' || c == 'b')
serial_console = c - 'a' + 1;
/* else Linux-style fbcon, not serial */
}
#if defined(CONFIG_PROM_CONSOLE)
if (!strncmp(commands, "prom", 4)) {
char *p;
for (p = commands - 8; *p && *p != ' '; p++)
*p = ' ';
conswitchp = &prom_con;
}
#endif
}
static void __init boot_flags_init(char *commands) static void __init boot_flags_init(char *commands)
{ {
while (*commands) { while (*commands) {
...@@ -187,9 +162,7 @@ static void __init boot_flags_init(char *commands) ...@@ -187,9 +162,7 @@ static void __init boot_flags_init(char *commands)
process_switch(*commands++); process_switch(*commands++);
continue; continue;
} }
if (!strncmp(commands, "console=", 8)) { if (!strncmp(commands, "mem=", 4)) {
process_console(commands);
} else if (!strncmp(commands, "mem=", 4)) {
/* /*
* "mem=XXX[kKmM] overrides the PROM-reported * "mem=XXX[kKmM] overrides the PROM-reported
* memory size. * memory size.
...@@ -341,41 +314,6 @@ void __init setup_arch(char **cmdline_p) ...@@ -341,41 +314,6 @@ void __init setup_arch(char **cmdline_p)
smp_setup_cpu_possible_map(); smp_setup_cpu_possible_map();
} }
static int __init set_preferred_console(void)
{
int idev, odev;
/* The user has requested a console so this is already set up. */
if (serial_console >= 0)
return -EBUSY;
idev = prom_query_input_device();
odev = prom_query_output_device();
if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
serial_console = 0;
} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
serial_console = 1;
} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
serial_console = 2;
} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
prom_printf("MrCoffee ttya\n");
serial_console = 1;
} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
serial_console = 0;
prom_printf("MrCoffee keyboard\n");
} else {
prom_printf("Confusing console (idev %d, odev %d)\n",
idev, odev);
serial_console = 1;
}
if (serial_console)
return add_preferred_console("ttyS", serial_console - 1, NULL);
return -ENODEV;
}
console_initcall(set_preferred_console);
extern char *sparc_cpu_type; extern char *sparc_cpu_type;
extern char *sparc_fpu_type; extern char *sparc_fpu_type;
...@@ -461,7 +399,6 @@ void sun_do_break(void) ...@@ -461,7 +399,6 @@ void sun_do_break(void)
prom_cmdline(); prom_cmdline();
} }
int serial_console = -1;
int stop_a_enabled = 1; int stop_a_enabled = 1;
static int __init topology_init(void) static int __init topology_init(void)
......
...@@ -102,119 +102,3 @@ prom_putchar(char c) ...@@ -102,119 +102,3 @@ prom_putchar(char c)
while(prom_nbputchar(c) == -1) ; while(prom_nbputchar(c) == -1) ;
return; return;
} }
/* Query for input device type */
enum prom_input_device
prom_query_input_device(void)
{
unsigned long flags;
int st_p;
char propb[64];
char *p;
int propl;
switch(prom_vers) {
case PROM_V0:
case PROM_V2:
case PROM_SUN4:
default:
switch(*romvec->pv_stdin) {
case PROMDEV_KBD: return PROMDEV_IKBD;
case PROMDEV_TTYA: return PROMDEV_ITTYA;
case PROMDEV_TTYB: return PROMDEV_ITTYB;
default:
return PROMDEV_I_UNK;
};
case PROM_V3:
spin_lock_irqsave(&prom_lock, flags);
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
restore_current();
spin_unlock_irqrestore(&prom_lock, flags);
if(prom_node_has_property(st_p, "keyboard"))
return PROMDEV_IKBD;
if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) {
if(strncmp(propb, "keyboard", sizeof("serial")) == 0)
return PROMDEV_IKBD;
}
if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) {
if(strncmp(propb, "serial", sizeof("serial")))
return PROMDEV_I_UNK;
}
propl = prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
if(propl > 2) {
p = propb;
while(*p) p++; p -= 2;
if(p[0] == ':') {
if(p[1] == 'a')
return PROMDEV_ITTYA;
else if(p[1] == 'b')
return PROMDEV_ITTYB;
}
}
return PROMDEV_I_UNK;
}
}
/* Query for output device type */
enum prom_output_device
prom_query_output_device(void)
{
unsigned long flags;
int st_p;
char propb[64];
char *p;
int propl;
switch(prom_vers) {
case PROM_V0:
case PROM_SUN4:
switch(*romvec->pv_stdin) {
case PROMDEV_SCREEN: return PROMDEV_OSCREEN;
case PROMDEV_TTYA: return PROMDEV_OTTYA;
case PROMDEV_TTYB: return PROMDEV_OTTYB;
};
break;
case PROM_V2:
case PROM_V3:
spin_lock_irqsave(&prom_lock, flags);
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
restore_current();
spin_unlock_irqrestore(&prom_lock, flags);
propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
if (propl == sizeof("display") &&
strncmp("display", propb, sizeof("display")) == 0)
{
return PROMDEV_OSCREEN;
}
if(prom_vers == PROM_V3) {
if(propl >= 0 &&
strncmp("serial", propb, sizeof("serial")) != 0)
return PROMDEV_O_UNK;
propl = prom_getproperty(prom_root_node, "stdout-path",
propb, sizeof(propb));
if(propl == CON_SIZE_JMC &&
strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0)
return PROMDEV_OTTYA;
if(propl > 2) {
p = propb;
while(*p) p++; p-= 2;
if(p[0]==':') {
if(p[1] == 'a')
return PROMDEV_OTTYA;
else if(p[1] == 'b')
return PROMDEV_OTTYB;
}
}
} else {
switch(*romvec->pv_stdin) {
case PROMDEV_TTYA: return PROMDEV_OTTYA;
case PROMDEV_TTYB: return PROMDEV_OTTYB;
};
}
break;
default:
;
};
return PROMDEV_O_UNK;
}
...@@ -58,7 +58,7 @@ prom_cmdline(void) ...@@ -58,7 +58,7 @@ prom_cmdline(void)
extern void install_linux_ticker(void); extern void install_linux_ticker(void);
unsigned long flags; unsigned long flags;
if(!serial_console && prom_palette) if (prom_palette)
prom_palette (1); prom_palette (1);
spin_lock_irqsave(&prom_lock, flags); spin_lock_irqsave(&prom_lock, flags);
install_obp_ticker(); install_obp_ticker();
...@@ -69,7 +69,7 @@ prom_cmdline(void) ...@@ -69,7 +69,7 @@ prom_cmdline(void)
#ifdef CONFIG_SUN_AUXIO #ifdef CONFIG_SUN_AUXIO
set_auxio(AUXIO_LED, 0); set_auxio(AUXIO_LED, 0);
#endif #endif
if(!serial_console && prom_palette) if (prom_palette)
prom_palette (0); prom_palette (0);
} }
......
...@@ -46,7 +46,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off; ...@@ -46,7 +46,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off;
void machine_power_off(void) void machine_power_off(void)
{ {
sstate_poweroff(); sstate_poweroff();
if (!serial_console || scons_pwroff) { if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
if (power_reg) { if (power_reg) {
/* Both register bits seem to have the /* Both register bits seem to have the
* same effect, so until I figure out * same effect, so until I figure out
......
...@@ -119,7 +119,7 @@ extern void (*prom_keyboard)(void); ...@@ -119,7 +119,7 @@ extern void (*prom_keyboard)(void);
void machine_halt(void) void machine_halt(void)
{ {
sstate_halt(); sstate_halt();
if (!serial_console && prom_palette) if (prom_palette)
prom_palette (1); prom_palette (1);
if (prom_keyboard) if (prom_keyboard)
prom_keyboard(); prom_keyboard();
...@@ -130,7 +130,7 @@ void machine_halt(void) ...@@ -130,7 +130,7 @@ void machine_halt(void)
void machine_alt_power_off(void) void machine_alt_power_off(void)
{ {
sstate_poweroff(); sstate_poweroff();
if (!serial_console && prom_palette) if (prom_palette)
prom_palette(1); prom_palette(1);
if (prom_keyboard) if (prom_keyboard)
prom_keyboard(); prom_keyboard();
...@@ -145,7 +145,7 @@ void machine_restart(char * cmd) ...@@ -145,7 +145,7 @@ void machine_restart(char * cmd)
sstate_reboot(); sstate_reboot();
p = strchr (reboot_command, '\n'); p = strchr (reboot_command, '\n');
if (p) *p = 0; if (p) *p = 0;
if (!serial_console && prom_palette) if (prom_palette)
prom_palette (1); prom_palette (1);
if (prom_keyboard) if (prom_keyboard)
prom_keyboard(); prom_keyboard();
......
...@@ -1646,6 +1646,60 @@ static void __init of_fill_in_cpu_data(void) ...@@ -1646,6 +1646,60 @@ static void __init of_fill_in_cpu_data(void)
smp_fill_in_sib_core_maps(); smp_fill_in_sib_core_maps();
} }
struct device_node *of_console_device;
EXPORT_SYMBOL(of_console_device);
char *of_console_path;
EXPORT_SYMBOL(of_console_path);
char *of_console_options;
EXPORT_SYMBOL(of_console_options);
static void __init of_console_init(void)
{
char *msg = "OF stdout device is: %s\n";
struct device_node *dp;
const char *type;
phandle node;
of_console_path = prom_early_alloc(256);
if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
prom_printf("Cannot obtain path of stdout.\n");
prom_halt();
}
of_console_options = strrchr(of_console_path, ':');
if (of_console_options) {
of_console_options++;
if (*of_console_options == '\0')
of_console_options = NULL;
}
node = prom_inst2pkg(prom_stdout);
if (!node) {
prom_printf("Cannot resolve stdout node from "
"instance %08x.\n", prom_stdout);
prom_halt();
}
dp = of_find_node_by_phandle(node);
type = of_get_property(dp, "device_type", NULL);
if (!type) {
prom_printf("Console stdout lacks device_type property.\n");
prom_halt();
}
if (strcmp(type, "display") && strcmp(type, "serial")) {
prom_printf("Console device_type is neither display "
"nor serial.\n");
prom_halt();
}
of_console_device = dp;
prom_printf(msg, of_console_path);
printk(msg, of_console_path);
}
void __init prom_build_devicetree(void) void __init prom_build_devicetree(void)
{ {
struct device_node **nextp; struct device_node **nextp;
...@@ -1658,6 +1712,8 @@ void __init prom_build_devicetree(void) ...@@ -1658,6 +1712,8 @@ void __init prom_build_devicetree(void)
allnodes->child = build_tree(allnodes, allnodes->child = build_tree(allnodes,
prom_getchild(allnodes->node), prom_getchild(allnodes->node),
&nextp); &nextp);
of_console_init();
printk("PROM: Built device tree with %u bytes of memory.\n", printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated); prom_early_allocated);
......
...@@ -133,33 +133,6 @@ static void __init process_switch(char c) ...@@ -133,33 +133,6 @@ static void __init process_switch(char c)
} }
} }
static void __init process_console(char *commands)
{
serial_console = 0;
commands += 8;
/* Linux-style serial */
if (!strncmp(commands, "ttyS", 4))
serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
else if (!strncmp(commands, "tty", 3)) {
char c = *(commands + 3);
/* Solaris-style serial */
if (c == 'a' || c == 'b') {
serial_console = c - 'a' + 1;
prom_printf ("Using /dev/tty%c as console.\n", c);
}
/* else Linux-style fbcon, not serial */
}
#if defined(CONFIG_PROM_CONSOLE)
if (!strncmp(commands, "prom", 4)) {
char *p;
for (p = commands - 8; *p && *p != ' '; p++)
*p = ' ';
conswitchp = &prom_con;
}
#endif
}
static void __init boot_flags_init(char *commands) static void __init boot_flags_init(char *commands)
{ {
while (*commands) { while (*commands) {
...@@ -176,9 +149,7 @@ static void __init boot_flags_init(char *commands) ...@@ -176,9 +149,7 @@ static void __init boot_flags_init(char *commands)
process_switch(*commands++); process_switch(*commands++);
continue; continue;
} }
if (!strncmp(commands, "console=", 8)) { if (!strncmp(commands, "mem=", 4)) {
process_console(commands);
} else if (!strncmp(commands, "mem=", 4)) {
/* /*
* "mem=XXX[kKmM]" overrides the PROM-reported * "mem=XXX[kKmM]" overrides the PROM-reported
* memory size. * memory size.
...@@ -378,44 +349,6 @@ void __init setup_arch(char **cmdline_p) ...@@ -378,44 +349,6 @@ void __init setup_arch(char **cmdline_p)
paging_init(); paging_init();
} }
static int __init set_preferred_console(void)
{
int idev, odev;
/* The user has requested a console so this is already set up. */
if (serial_console >= 0)
return -EBUSY;
idev = prom_query_input_device();
odev = prom_query_output_device();
if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
serial_console = 0;
} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
serial_console = 1;
} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
serial_console = 2;
} else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
serial_console = 3;
} else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
/* sunhv_console_init() doesn't check the serial_console
* value anyways...
*/
serial_console = 4;
return add_preferred_console("ttyHV", 0, NULL);
} else {
prom_printf("Inconsistent console: "
"input %d, output %d\n",
idev, odev);
prom_halt();
}
if (serial_console)
return add_preferred_console("ttyS", serial_console - 1, NULL);
return -ENODEV;
}
console_initcall(set_preferred_console);
/* BUFFER is PAGE_SIZE bytes long. */ /* BUFFER is PAGE_SIZE bytes long. */
extern char *sparc_cpu_type; extern char *sparc_cpu_type;
...@@ -508,5 +441,4 @@ void sun_do_break(void) ...@@ -508,5 +441,4 @@ void sun_do_break(void)
prom_cmdline(); prom_cmdline();
} }
int serial_console = -1;
int stop_a_enabled = 1; int stop_a_enabled = 1;
...@@ -330,7 +330,6 @@ EXPORT_SYMBOL(VISenter); ...@@ -330,7 +330,6 @@ EXPORT_SYMBOL(VISenter);
/* for input/keybdev */ /* for input/keybdev */
EXPORT_SYMBOL(sun_do_break); EXPORT_SYMBOL(sun_do_break);
EXPORT_SYMBOL(serial_console);
EXPORT_SYMBOL(stop_a_enabled); EXPORT_SYMBOL(stop_a_enabled);
#ifdef CONFIG_DEBUG_BUGVERBOSE #ifdef CONFIG_DEBUG_BUGVERBOSE
......
...@@ -73,88 +73,3 @@ prom_puts(const char *s, int len) ...@@ -73,88 +73,3 @@ prom_puts(const char *s, int len)
P1275_INOUT(3,1), P1275_INOUT(3,1),
prom_stdout, s, P1275_SIZE(len)); prom_stdout, s, P1275_SIZE(len));
} }
/* Query for input device type */
enum prom_input_device
prom_query_input_device(void)
{
int st_p;
char propb[64];
st_p = prom_inst2pkg(prom_stdin);
if(prom_node_has_property(st_p, "keyboard"))
return PROMDEV_IKBD;
prom_getproperty(st_p, "device_type", propb, sizeof(propb));
if(strncmp(propb, "serial", 6))
return PROMDEV_I_UNK;
/* FIXME: Is there any better way how to find out? */
memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "input-device", propb, sizeof(propb));
/*
* If we get here with propb == 'keyboard', we are on ttya, as
* the PROM defaulted to this due to 'no input device'.
*/
if (!strncmp(propb, "keyboard", 8))
return PROMDEV_ITTYA;
if (!strncmp (propb, "rsc", 3))
return PROMDEV_IRSC;
if (!strncmp (propb, "virtual-console", 3))
return PROMDEV_IVCONS;
if (strncmp (propb, "tty", 3) || !propb[3])
return PROMDEV_I_UNK;
switch (propb[3]) {
case 'a': return PROMDEV_ITTYA;
case 'b': return PROMDEV_ITTYB;
default: return PROMDEV_I_UNK;
}
}
/* Query for output device type */
enum prom_output_device
prom_query_output_device(void)
{
int st_p;
char propb[64];
int propl;
st_p = prom_inst2pkg(prom_stdout);
propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
if (propl >= 0 && propl == sizeof("display") &&
strncmp("display", propb, sizeof("display")) == 0)
return PROMDEV_OSCREEN;
if(strncmp("serial", propb, 6))
return PROMDEV_O_UNK;
/* FIXME: Is there any better way how to find out? */
memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "output-device", propb, sizeof(propb));
/*
* If we get here with propb == 'screen', we are on ttya, as
* the PROM defaulted to this due to 'no input device'.
*/
if (!strncmp(propb, "screen", 6))
return PROMDEV_OTTYA;
if (!strncmp (propb, "rsc", 3))
return PROMDEV_ORSC;
if (!strncmp (propb, "virtual-console", 3))
return PROMDEV_OVCONS;
if (strncmp (propb, "tty", 3) || !propb[3])
return PROMDEV_O_UNK;
switch (propb[3]) {
case 'a': return PROMDEV_OTTYA;
case 'b': return PROMDEV_OTTYB;
default: return PROMDEV_O_UNK;
}
}
...@@ -72,7 +72,7 @@ void prom_cmdline(void) ...@@ -72,7 +72,7 @@ void prom_cmdline(void)
local_irq_save(flags); local_irq_save(flags);
if (!serial_console && prom_palette) if (prom_palette)
prom_palette(1); prom_palette(1);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -85,7 +85,7 @@ void prom_cmdline(void) ...@@ -85,7 +85,7 @@ void prom_cmdline(void)
smp_release(); smp_release();
#endif #endif
if (!serial_console && prom_palette) if (prom_palette)
prom_palette(0); prom_palette(0);
local_irq_restore(flags); local_irq_restore(flags);
......
...@@ -304,3 +304,11 @@ prom_pathtoinode(const char *path) ...@@ -304,3 +304,11 @@ prom_pathtoinode(const char *path)
if (node == -1) return 0; if (node == -1) return 0;
return node; return node;
} }
int prom_ihandle2path(int handle, char *buffer, int bufsize)
{
return p1275_cmd("instance-to-path",
P1275_ARG(1,P1275_ARG_OUT_BUF)|
P1275_INOUT(3, 1),
handle, buffer, P1275_SIZE(bufsize));
}
...@@ -16,9 +16,10 @@ ...@@ -16,9 +16,10 @@
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/serial_core.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/oplib.h> #include <asm/prom.h>
#include "suncore.h" #include "suncore.h"
...@@ -26,92 +27,60 @@ int sunserial_current_minor = 64; ...@@ -26,92 +27,60 @@ int sunserial_current_minor = 64;
EXPORT_SYMBOL(sunserial_current_minor); EXPORT_SYMBOL(sunserial_current_minor);
void int sunserial_console_match(struct console *con, struct device_node *dp,
sunserial_console_termios(struct console *con) struct uart_driver *drv, int line)
{ {
char mode[16], buf[16], *s; int off;
char mode_prop[] = "ttyX-mode";
char cd_prop[] = "ttyX-ignore-cd";
char dtr_prop[] = "ttyX-rts-dtr-off";
char *ssp_console_modes_prop = "ssp-console-modes";
int baud, bits, stop, cflag;
char parity;
int carrier = 0;
int rtsdtr = 1;
int topnd, nd;
if (!serial_console)
return;
switch (serial_console) {
case PROMDEV_OTTYA:
mode_prop[3] = 'a';
cd_prop[3] = 'a';
dtr_prop[3] = 'a';
break;
case PROMDEV_OTTYB:
mode_prop[3] = 'b';
cd_prop[3] = 'b';
dtr_prop[3] = 'b';
break;
case PROMDEV_ORSC:
nd = prom_pathtoinode("rsc");
if (!nd) {
strcpy(mode, "115200,8,n,1,-");
goto no_options;
}
if (!prom_node_has_property(nd, ssp_console_modes_prop)) { if (!con || of_console_device != dp)
strcpy(mode, "115200,8,n,1,-"); return 0;
goto no_options;
}
memset(mode, 0, sizeof(mode)); off = 0;
prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode)); if (of_console_options &&
goto no_options; *of_console_options == 'b')
off = 1;
default: if ((line & 1) != off)
strcpy(mode, "9600,8,n,1,-"); return 0;
goto no_options;
}
topnd = prom_getchild(prom_root_node); con->index = line;
nd = prom_searchsiblings(topnd, "options"); drv->cons = con;
if (!nd) { add_preferred_console(con->name, line, NULL);
strcpy(mode, "9600,8,n,1,-");
goto no_options;
}
if (!prom_node_has_property(nd, mode_prop)) {
strcpy(mode, "9600,8,n,1,-");
goto no_options;
}
memset(mode, 0, sizeof(mode)); return 1;
prom_getstring(nd, mode_prop, mode, sizeof(mode)); }
EXPORT_SYMBOL(sunserial_console_match);
if (prom_node_has_property(nd, cd_prop)) {
memset(buf, 0, sizeof(buf));
prom_getstring(nd, cd_prop, buf, sizeof(buf));
if (!strcmp(buf, "false"))
carrier = 1;
/* XXX: this is unused below. */
}
if (prom_node_has_property(nd, dtr_prop)) { void
memset(buf, 0, sizeof(buf)); sunserial_console_termios(struct console *con)
prom_getstring(nd, dtr_prop, buf, sizeof(buf)); {
if (!strcmp(buf, "false")) struct device_node *dp;
rtsdtr = 0; const char *od, *mode, *s;
char mode_prop[] = "ttyX-mode";
int baud, bits, stop, cflag;
char parity;
/* XXX: this is unused below. */ dp = of_find_node_by_path("/options");
od = of_get_property(dp, "output-device", NULL);
if (!strcmp(od, "rsc")) {
mode = of_get_property(of_console_device,
"ssp-console-modes", NULL);
if (!mode)
mode = "115200,8,n,1,-";
} else {
char c;
c = 'a';
if (of_console_options)
c = *of_console_options;
mode_prop[3] = c;
mode = of_get_property(dp, mode_prop, NULL);
if (!mode)
mode = "9600,8,n,1,-";
} }
no_options:
cflag = CREAD | HUPCL | CLOCAL; cflag = CREAD | HUPCL | CLOCAL;
s = mode; s = mode;
......
...@@ -24,6 +24,8 @@ extern int suncore_mouse_baud_detection(unsigned char, int); ...@@ -24,6 +24,8 @@ extern int suncore_mouse_baud_detection(unsigned char, int);
extern int sunserial_current_minor; extern int sunserial_current_minor;
extern int sunserial_console_match(struct console *, struct device_node *,
struct uart_driver *, int);
extern void sunserial_console_termios(struct console *); extern void sunserial_console_termios(struct console *);
#endif /* !(_SERIAL_SUN_H) */ #endif /* !(_SERIAL_SUN_H) */
...@@ -520,16 +520,6 @@ static struct console sunhv_console = { ...@@ -520,16 +520,6 @@ static struct console sunhv_console = {
.data = &sunhv_reg, .data = &sunhv_reg,
}; };
static inline struct console *SUNHV_CONSOLE(void)
{
if (con_is_present())
return NULL;
sunhv_console.index = 0;
return &sunhv_console;
}
static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match) static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
{ {
struct uart_port *port; struct uart_port *port;
...@@ -582,7 +572,8 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m ...@@ -582,7 +572,8 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
sunserial_current_minor += 1; sunserial_current_minor += 1;
sunhv_reg.cons = SUNHV_CONSOLE(); sunserial_console_match(&sunhv_console, op->node,
&sunhv_reg, port->line);
err = uart_add_one_port(&sunhv_reg, port); err = uart_add_one_port(&sunhv_reg, port);
if (err) if (err)
......
...@@ -968,22 +968,6 @@ static struct console sunsab_console = { ...@@ -968,22 +968,6 @@ static struct console sunsab_console = {
static inline struct console *SUNSAB_CONSOLE(void) static inline struct console *SUNSAB_CONSOLE(void)
{ {
int i;
if (con_is_present())
return NULL;
for (i = 0; i < num_channels; i++) {
int this_minor = sunsab_reg.minor + i;
if ((this_minor - 64) == (serial_console - 1))
break;
}
if (i == num_channels)
return NULL;
sunsab_console.index = i;
return &sunsab_console; return &sunsab_console;
} }
#else #else
...@@ -1080,7 +1064,12 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id * ...@@ -1080,7 +1064,12 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
return err; return err;
} }
sunserial_console_match(SUNSAB_CONSOLE(), op->node,
&sunsab_reg, up[0].port.line);
uart_add_one_port(&sunsab_reg, &up[0].port); uart_add_one_port(&sunsab_reg, &up[0].port);
sunserial_console_match(SUNSAB_CONSOLE(), op->node,
&sunsab_reg, up[1].port.line);
uart_add_one_port(&sunsab_reg, &up[1].port); uart_add_one_port(&sunsab_reg, &up[1].port);
dev_set_drvdata(&op->dev, &up[0]); dev_set_drvdata(&op->dev, &up[0]);
...@@ -1164,7 +1153,6 @@ static int __init sunsab_init(void) ...@@ -1164,7 +1153,6 @@ static int __init sunsab_init(void)
} }
sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64; sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
sunsab_reg.cons = SUNSAB_CONSOLE();
sunserial_current_minor += num_channels; sunserial_current_minor += num_channels;
} }
......
...@@ -1371,28 +1371,12 @@ static struct console sunsu_console = { ...@@ -1371,28 +1371,12 @@ static struct console sunsu_console = {
* Register console. * Register console.
*/ */
static inline struct console *SUNSU_CONSOLE(int num_uart) static inline struct console *SUNSU_CONSOLE(void)
{ {
int i;
if (con_is_present())
return NULL;
for (i = 0; i < num_uart; i++) {
int this_minor = sunsu_reg.minor + i;
if ((this_minor - 64) == (serial_console - 1))
break;
}
if (i == num_uart)
return NULL;
sunsu_console.index = i;
return &sunsu_console; return &sunsu_console;
} }
#else #else
#define SUNSU_CONSOLE(num_uart) (NULL) #define SUNSU_CONSOLE() (NULL)
#define sunsu_serial_console_init() do { } while (0) #define sunsu_serial_console_init() do { } while (0)
#endif #endif
...@@ -1482,6 +1466,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m ...@@ -1482,6 +1466,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
up->port.ops = &sunsu_pops; up->port.ops = &sunsu_pops;
sunserial_console_match(SUNSU_CONSOLE(), dp,
&sunsu_reg, up->port.line);
err = uart_add_one_port(&sunsu_reg, &up->port); err = uart_add_one_port(&sunsu_reg, &up->port);
if (err) if (err)
goto out_unmap; goto out_unmap;
...@@ -1572,7 +1558,6 @@ static int __init sunsu_init(void) ...@@ -1572,7 +1558,6 @@ static int __init sunsu_init(void)
return err; return err;
sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
sunserial_current_minor += num_uart; sunserial_current_minor += num_uart;
sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
} }
err = of_register_driver(&su_driver, &of_bus_type); err = of_register_driver(&su_driver, &of_bus_type);
......
...@@ -1226,23 +1226,6 @@ static struct console sunzilog_console_ops = { ...@@ -1226,23 +1226,6 @@ static struct console sunzilog_console_ops = {
static inline struct console *SUNZILOG_CONSOLE(void) static inline struct console *SUNZILOG_CONSOLE(void)
{ {
int i;
if (con_is_present())
return NULL;
for (i = 0; i < NUM_CHANNELS; i++) {
int this_minor = sunzilog_reg.minor + i;
if ((this_minor - 64) == (serial_console - 1))
break;
}
if (i == NUM_CHANNELS)
return NULL;
sunzilog_console_ops.index = i;
sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
return &sunzilog_console_ops; return &sunzilog_console_ops;
} }
...@@ -1428,12 +1411,18 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m ...@@ -1428,12 +1411,18 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
sunzilog_init_hw(&up[1]); sunzilog_init_hw(&up[1]);
if (!keyboard_mouse) { if (!keyboard_mouse) {
if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
&sunzilog_reg, up[0].port.line))
up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[0].port); err = uart_add_one_port(&sunzilog_reg, &up[0].port);
if (err) { if (err) {
of_iounmap(&op->resource[0], of_iounmap(&op->resource[0],
rp, sizeof(struct zilog_layout)); rp, sizeof(struct zilog_layout));
return err; return err;
} }
if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
&sunzilog_reg, up[1].port.line))
up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[1].port); err = uart_add_one_port(&sunzilog_reg, &up[1].port);
if (err) { if (err) {
uart_remove_one_port(&sunzilog_reg, &up[0].port); uart_remove_one_port(&sunzilog_reg, &up[0].port);
...@@ -1531,7 +1520,6 @@ static int __init sunzilog_init(void) ...@@ -1531,7 +1520,6 @@ static int __init sunzilog_init(void)
goto out_free_tables; goto out_free_tables;
sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
sunzilog_reg.cons = SUNZILOG_CONSOLE();
sunserial_current_minor += uart_count; sunserial_current_minor += uart_count;
} }
......
...@@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, ...@@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
int node, len, i, j, ret; int node, len, i, j, ret;
u32 mem, chip_id; u32 mem, chip_id;
/* Do not attach when we have a serial console. */
if (!con_is_present())
return -ENXIO;
/* /*
* Map memory-mapped registers. * Map memory-mapped registers.
*/ */
......
...@@ -379,10 +379,6 @@ int __init igafb_init(void) ...@@ -379,10 +379,6 @@ int __init igafb_init(void)
if (fb_get_options("igafb", NULL)) if (fb_get_options("igafb", NULL))
return -ENODEV; return -ENODEV;
/* Do not attach when we have a serial console. */
if (!con_is_present())
return -ENXIO;
pdev = pci_get_device(PCI_VENDOR_ID_INTERG, pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
PCI_DEVICE_ID_INTERG_1682, 0); PCI_DEVICE_ID_INTERG_1682, 0);
if (pdev == NULL) { if (pdev == NULL) {
......
...@@ -158,32 +158,6 @@ extern void prom_putchar(char character); ...@@ -158,32 +158,6 @@ extern void prom_putchar(char character);
extern void prom_printf(char *fmt, ...); extern void prom_printf(char *fmt, ...);
extern void prom_write(const char *buf, unsigned int len); extern void prom_write(const char *buf, unsigned int len);
/* Query for input device type */
enum prom_input_device {
PROMDEV_IKBD, /* input from keyboard */
PROMDEV_ITTYA, /* input from ttya */
PROMDEV_ITTYB, /* input from ttyb */
PROMDEV_IRSC, /* input from rsc */
PROMDEV_IVCONS, /* input from virtual-console */
PROMDEV_I_UNK,
};
extern enum prom_input_device prom_query_input_device(void);
/* Query for output device type */
enum prom_output_device {
PROMDEV_OSCREEN, /* to screen */
PROMDEV_OTTYA, /* to ttya */
PROMDEV_OTTYB, /* to ttyb */
PROMDEV_ORSC, /* to rsc */
PROMDEV_OVCONS, /* to virtual-console */
PROMDEV_O_UNK,
};
extern enum prom_output_device prom_query_output_device(void);
/* Multiprocessor operations... */ /* Multiprocessor operations... */
/* Start the CPU with the given device tree node, context table, and context /* Start the CPU with the given device tree node, context table, and context
......
...@@ -85,5 +85,9 @@ static inline void of_node_put(struct device_node *node) ...@@ -85,5 +85,9 @@ static inline void of_node_put(struct device_node *node)
*/ */
#include <linux/of.h> #include <linux/of.h>
extern struct device_node *of_console_device;
extern char *of_console_path;
extern char *of_console_options;
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _SPARC_PROM_H */ #endif /* _SPARC_PROM_H */
...@@ -140,32 +140,6 @@ extern void prom_putchar(char character); ...@@ -140,32 +140,6 @@ extern void prom_putchar(char character);
extern void prom_printf(const char *fmt, ...); extern void prom_printf(const char *fmt, ...);
extern void prom_write(const char *buf, unsigned int len); extern void prom_write(const char *buf, unsigned int len);
/* Query for input device type */
enum prom_input_device {
PROMDEV_IKBD, /* input from keyboard */
PROMDEV_ITTYA, /* input from ttya */
PROMDEV_ITTYB, /* input from ttyb */
PROMDEV_IRSC, /* input from rsc */
PROMDEV_IVCONS, /* input from virtual-console */
PROMDEV_I_UNK,
};
extern enum prom_input_device prom_query_input_device(void);
/* Query for output device type */
enum prom_output_device {
PROMDEV_OSCREEN, /* to screen */
PROMDEV_OTTYA, /* to ttya */
PROMDEV_OTTYB, /* to ttyb */
PROMDEV_ORSC, /* to rsc */
PROMDEV_OVCONS, /* to virtual-console */
PROMDEV_O_UNK,
};
extern enum prom_output_device prom_query_output_device(void);
/* Multiprocessor operations... */ /* Multiprocessor operations... */
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* Start the CPU with the given device tree node at the passed program /* Start the CPU with the given device tree node at the passed program
...@@ -319,6 +293,8 @@ extern int prom_inst2pkg(int); ...@@ -319,6 +293,8 @@ extern int prom_inst2pkg(int);
extern int prom_service_exists(const char *service_name); extern int prom_service_exists(const char *service_name);
extern void prom_sun4v_guest_soft_state(void); extern void prom_sun4v_guest_soft_state(void);
extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
/* Client interface level routines. */ /* Client interface level routines. */
extern void prom_set_trap_table(unsigned long tba); extern void prom_set_trap_table(unsigned long tba);
extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa); extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
......
...@@ -94,5 +94,9 @@ static inline void of_node_put(struct device_node *node) ...@@ -94,5 +94,9 @@ static inline void of_node_put(struct device_node *node)
*/ */
#include <linux/of.h> #include <linux/of.h>
extern struct device_node *of_console_device;
extern char *of_console_path;
extern char *of_console_options;
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _SPARC64_PROM_H */ #endif /* _SPARC64_PROM_H */
...@@ -115,14 +115,8 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ ...@@ -115,14 +115,8 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern void sun_do_break(void); extern void sun_do_break(void);
extern int serial_console;
extern int stop_a_enabled; extern int stop_a_enabled;
static __inline__ int con_is_present(void)
{
return serial_console ? 0 : 1;
}
extern void synchronize_user_stack(void); extern void synchronize_user_stack(void);
extern void __flushw_user(void); extern void __flushw_user(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment