diff options
Diffstat (limited to 'sys/arch/hppa64/stand/libsa/cmd_hppa64.c')
-rw-r--r-- | sys/arch/hppa64/stand/libsa/cmd_hppa64.c | 819 |
1 files changed, 819 insertions, 0 deletions
diff --git a/sys/arch/hppa64/stand/libsa/cmd_hppa64.c b/sys/arch/hppa64/stand/libsa/cmd_hppa64.c new file mode 100644 index 00000000000..1aa6117cb07 --- /dev/null +++ b/sys/arch/hppa64/stand/libsa/cmd_hppa64.c @@ -0,0 +1,819 @@ +/* $OpenBSD: cmd_hppa64.c,v 1.1 2005/04/01 10:40:48 mickey Exp $ */ + +/* + * Copyright (c) 2002 Miodrag Vallat + * 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 OR HIS RELATIVES 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 MIND, 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. + */ + +/*#define DEBUG*/ + +#include <sys/param.h> +/* would come from <sys/param.h> if -D_KERNEL */ +#define offsetof(s, e) ((size_t)&((s *)0)->e) + +#include <machine/iomod.h> +#include <machine/pdc.h> + +#include <arch/hppa/dev/cpudevs.h> + +#include <libsa.h> +#include "cmd.h" +#include "dev_hppa64.h" /* pdc */ + +extern struct stable_storage sstor; +extern int sstorsiz; + +/* storage sizes we're interested in */ +#define CONSOLEOFFSET \ + offsetof(struct stable_storage, ss_console) +#define CONSOLESIZE \ + (offsetof(struct stable_storage, ss_console) + \ + sizeof(struct device_path)) + +#define KEYBOARDOFFSET \ + offsetof(struct stable_storage, ss_keyboard) +#define KEYBOARDSIZE \ + (offsetof(struct stable_storage, ss_keyboard) + \ + sizeof(struct device_path)) + +/* + * Table for the possible console devices found during the device walk. + */ +struct consoledev { + struct device_path dp; + int type; + int iodc_type; + int iodc_model; +}; + +#define PS2 1 +#define HIL 2 +#define SERIAL 3 +#define GRAPHICS 4 + +/* max. serial ports */ +#define MAX_SERIALS 4 +/* max. HIL and PS2 */ +#define MAX_KEYBOARDS 2 +/* max. heads */ +#define MAX_GRAPHICS 4 + +struct consoledev serials[MAX_SERIALS]; +struct consoledev keyboards[MAX_KEYBOARDS]; +struct consoledev graphics[MAX_GRAPHICS]; + +/* Relaxed device comparison */ +#define MATCH(dev1, dev2) \ + (dev1).dp_mod == (dev2).dp_mod && \ + (dev1).dp_bc[0] == (dev2).dp_bc[0] && \ + (dev1).dp_bc[1] == (dev2).dp_bc[1] && \ + (dev1).dp_bc[2] == (dev2).dp_bc[2] && \ + (dev1).dp_bc[3] == (dev2).dp_bc[3] && \ + (dev1).dp_bc[4] == (dev2).dp_bc[4] && \ + (dev1).dp_bc[5] == (dev2).dp_bc[5] + +int walked; + +void bus_walk(struct device_path *); +void register_device(struct consoledev *, int, + struct device_path *, struct iodc_data *, int, int); + +int Xconsole(void); +void print_console(void); +int set_graphics(struct device_path *, int, char *); +int set_serial(struct device_path *, int, char *); +int set_console(struct device_path *); + +int Xkeyboard(void); +void print_keyboard(void); +int set_keyboard(struct device_path *); + +struct cmd_table cmd_machine[] = { + { "console", CMDT_CMD, Xconsole }, + { "keyboard", CMDT_CMD, Xkeyboard }, + { NULL, }, +}; + +/* value to console speed table */ +int i_speeds[] = { + 50, + 75, + 110, + 150, + 300, + 600, + 1200, + 2400, + 4800, + 7200, + 9600, + 19200, + 38400, + 57600, + 115200, + 230400, +}; + +char *c_speeds[] = { + "50", + "75", + "110", + "150", + "300", + "600", + "1200", + "2400", + "4800", + "7200", + "9600", + "19200", + "38400", + "57600", + "115200", + "230400", +}; + +/* values to console parity table */ +char *parities[] = { + "none", + "odd", + "<unknown parity>", + "even", +}; + +/* + * C O N S O L E S E T T I N G S + */ + +void +print_console() +{ + int port, mode, speed, parity, bits; + int i; + +#ifdef DEBUG + printf("console flags %x mod %x bc %d/%d/%d/%d/%d/%d\n", + sstor.ss_console.dp_flags, + sstor.ss_console.dp_mod, + sstor.ss_console.dp_bc[0], + sstor.ss_console.dp_bc[1], + sstor.ss_console.dp_bc[2], + sstor.ss_console.dp_bc[3], + sstor.ss_console.dp_bc[4], + sstor.ss_console.dp_bc[5]); + + printf("console path %x/%x/%x/%x/%x/%x\n", + sstor.ss_console.dp_layers[0], + sstor.ss_console.dp_layers[1], + sstor.ss_console.dp_layers[2], + sstor.ss_console.dp_layers[3], + sstor.ss_console.dp_layers[4], + sstor.ss_console.dp_layers[5]); +#endif + + printf("Console path: "); + + /* look for a serial console */ + for (port = i = 0; i < MAX_SERIALS; i++) + if (MATCH(serials[i].dp, sstor.ss_console)) { + port = i + 1; + break; + } + + if (port == 0) { + /* + * Graphics console + */ + + for (port = i = 0; i < MAX_GRAPHICS; i++) + if (MATCH(graphics[i].dp, sstor.ss_console)) { + port = i; + break; + } + + /* + * If the console could still not be identified, consider + * it is a simplified encoding for the default graphics + * console. Hence port == 0, no need to check. + */ + if (port == 0) + printf("graphics"); + else + printf("graphics_%d", port); + + mode = sstor.ss_console.dp_layers[0]; + if (mode != 0) + printf(".%d", mode); + } else { + /* + * Serial console + */ + + if (port == 1) + printf("rs232"); + else + printf("rs232_%d", port); + + speed = PZL_SPEED(sstor.ss_console.dp_layers[0]); + printf(".%d", i_speeds[speed]); + + bits = PZL_BITS(sstor.ss_console.dp_layers[0]); + printf(".%d", bits); + + parity = PZL_PARITY(sstor.ss_console.dp_layers[0]); + printf(".%s", parities[parity]); + } + + printf("\n"); +} + +int +set_graphics(console, port, arg) + struct device_path *console; + int port; + char *arg; +{ + int maxmode, mode = 0; + char *digit; + + /* head */ + if (graphics[port].type == 0) { + printf("no such device found\n"); + return 0; + } + + /* mode */ + if (arg != NULL) { + for (digit = arg; *digit != '\0'; digit++) { + if (*digit >= '0' && *digit <= '9') + mode = 10 * mode + (*digit - '0'); + else { + printf("invalid mode specification, %s\n", + arg); + return 0; + } + } + + if (mode <= 0) { + printf("invalid mode specification, %s\n", + arg); + return 0; + } + } + + /* + * If we are just changing the mode of the same graphics + * console, check that our mode is in the valid range. + */ + if (MATCH(graphics[port].dp, sstor.ss_console)) { + maxmode = sstor.ss_console.dp_layers[1]; + + /* pick back same mode if unspecified */ + if (mode == 0) + mode = sstor.ss_console.dp_layers[0]; + + if (mode > maxmode) { + printf("invalid mode value, available range is 1-%d\n", + maxmode); + return 0; + } + } else { + if (mode == 0) + mode = 1; + maxmode = mode; + } + + *console = graphics[port].dp; + console->dp_layers[0] = mode; + console->dp_layers[1] = maxmode; + console->dp_layers[2] = console->dp_layers[3] = + console->dp_layers[4] = console->dp_layers[5] = 0; + + return 1; +} + +int +set_serial(console, port, arg) + struct device_path *console; + int port; + char *arg; +{ + char *dot; + int i; + int speed, parity, bits; + + /* port */ + port--; + if (serials[port].type == 0) { + printf("no such device found\n"); + return 0; + } + + /* speed */ + dot = strchr(arg, '.'); + if (dot != NULL) + *dot++ = '\0'; + + speed = 0; + if (arg == NULL || *arg == '\0') { + for (i = 0; i < NENTS(i_speeds); i++) + if (i_speeds[i] == 9600) { + speed = i; + break; + } + } else { + for (i = 0; i < NENTS(c_speeds); i++) + if (strcmp(arg, c_speeds[i]) == 0) { + speed = i; + break; + } + if (speed == 0) { + printf("invalid speed specification, %s\n", arg); + return 0; + } + } + + /* data bits */ + arg = dot; + dot = strchr(arg, '.'); + + if (arg == NULL || *arg == '\0') + bits = 8; + else { + if (dot == arg + 1) + bits = *arg - '0'; + else + bits = 0; + + if (bits < 5 || bits > 8) { + printf("invalid bits specification, %s\n", arg); + return 0; + } + } + if (dot != NULL) + *dot++ = '\0'; + + /* parity */ + arg = dot; + if (arg == NULL || *arg == '\0') + parity = 0; /* none */ + else { + parity = -1; + for (i = 0; i <= 3; i++) + if (strcmp(arg, parities[i]) == 0) { + parity = i; + break; + } + if (parity == 2) + parity = -1; /* unknown parity */ + } + if (parity < 0) { + printf("invalid parity specification, %s\n", arg); + return 0; + } + + *console = serials[port].dp; + console->dp_layers[0] = PZL_ENCODE(bits, parity, speed); + + return 1; +} + +int +set_console(console) + struct device_path *console; +{ + char *arg = cmd.argv[1], *dot; + int port; + + /* extract first word */ + dot = strchr(arg, '.'); + if (dot != NULL) + *dot++ = '\0'; + + /* + * Graphics console + */ + if (strcmp(arg, "graphics") == 0) + return set_graphics(console, 0, dot); + if (strncmp(arg, "graphics_", 9) == 0) { + port = arg[9] - '0'; + if (port > 0 && port < MAX_GRAPHICS) + return set_graphics(console, port, dot); + } + + /* + * Serial console + */ + if (strcmp(arg, "rs232") == 0) + return set_serial(console, 1, dot); + if (strncmp(arg, "rs232_", 6) == 0) { + port = arg[6] - '0'; + if (port > 0 && port <= MAX_SERIALS) + return set_serial(console, port, dot); + } + + printf("invalid device specification, %s\n", arg); + return 0; +} + +int +Xconsole() +{ + struct device_path console; + int rc; + + /* walk the device list if not already done */ + if (walked == 0) { + bus_walk(NULL); + walked++; + } + + if (sstorsiz < CONSOLESIZE) { + printf("no console information in stable storage\n"); + return 0; + } + + if (cmd.argc == 1) { + print_console(); + } else { + console = sstor.ss_console; + if (set_console(&console)) { + if (memcmp(&sstor.ss_console, &console, + sizeof console) != 0) { + sstor.ss_console = console; + + /* alea jacta est */ + rc = (*pdc)(PDC_STABLE, PDC_STABLE_WRITE, + CONSOLEOFFSET, &sstor.ss_console, + sizeof(sstor.ss_console)); + if (rc != 0) { + printf("failed to save console settings, error %d\n", + rc); + /* read sstor again for safety */ + (*pdc)(PDC_STABLE, PDC_STABLE_READ, + CONSOLEOFFSET, &sstor.ss_console, + sizeof(sstor.ss_console)); + } else + printf("you will need to power-cycle " + "your machine for the changes " + "to take effect.\n"); + } + print_console(); + } + } + + return 0; +} + +/* + * K E Y B O A R D S E T T I N G S + */ + +void +print_keyboard() +{ + int type; + int i; + +#ifdef DEBUG + printf("keyboard flags %x mod %x bc %d/%d/%d/%d/%d/%d\n", + sstor.ss_keyboard.dp_flags, + sstor.ss_keyboard.dp_mod, + sstor.ss_keyboard.dp_bc[0], + sstor.ss_keyboard.dp_bc[1], + sstor.ss_keyboard.dp_bc[2], + sstor.ss_keyboard.dp_bc[3], + sstor.ss_keyboard.dp_bc[4], + sstor.ss_keyboard.dp_bc[5]); + + printf("keyboard path %x/%x/%x/%x/%x/%x\n", + sstor.ss_keyboard.dp_layers[0], + sstor.ss_keyboard.dp_layers[1], + sstor.ss_keyboard.dp_layers[2], + sstor.ss_keyboard.dp_layers[3], + sstor.ss_keyboard.dp_layers[4], + sstor.ss_keyboard.dp_layers[5]); +#endif + + printf("Keyboard path: "); + + for (type = i = 0; i < MAX_KEYBOARDS; i++) + if (MATCH(keyboards[i].dp, sstor.ss_keyboard)) { + type = keyboards[i].type; + break; + } + + switch (type) { + case HIL: + printf("hil"); + break; + case PS2: + printf("ps2"); + break; + default: + printf("unknown"); + break; + } + + printf("\n"); +} + +int +set_keyboard(keyboard) + struct device_path *keyboard; +{ + int i; + char *arg = cmd.argv[1]; + int type; + + if (strcmp(arg, "hil") == 0) + type = HIL; + else if (strcmp(arg, "ps2") == 0) + type = PS2; + else { + printf("invalid device specification, %s\n", arg); + return 0; + } + + for (i = 0; i < MAX_KEYBOARDS; i++) + if (keyboards[i].type == type) { + *keyboard = keyboards[i].dp; + return 1; + } + + printf("no such device found\n"); + return 0; +} + +int +Xkeyboard() +{ + struct device_path keyboard; + int rc; + + /* walk the device list if not already done */ + if (walked == 0) { + bus_walk(NULL); + walked++; + } + + if (sstorsiz < KEYBOARDSIZE) { + printf("no keyboard information in stable storage\n"); + return 0; + } + + if (cmd.argc == 1) { + print_keyboard(); + } else { + keyboard = sstor.ss_keyboard; + if (set_keyboard(&keyboard)) { + if (memcmp(&sstor.ss_keyboard, &keyboard, + sizeof keyboard) != 0) { + sstor.ss_keyboard = keyboard; + + /* alea jacta est */ + rc = (*pdc)(PDC_STABLE, PDC_STABLE_WRITE, + KEYBOARDOFFSET, &sstor.ss_keyboard, + sizeof(sstor.ss_keyboard)); + if (rc != 0) { + printf("failed to save keyboard settings, error %d\n", + rc); + /* read sstor again for safety */ + (*pdc)(PDC_STABLE, PDC_STABLE_READ, + KEYBOARDOFFSET, &sstor.ss_keyboard, + sizeof(sstor.ss_keyboard)); + } else + printf("you will need to power-cycle " + "your machine for the changes " + "to take effect.\n"); + } + print_keyboard(); + } + } + + return 0; +} + +/* + * U T I L I T I E S + */ + +/* + * Bus walker. + * This routine will walk all the modules on a given bus, registering + * serial ports, keyboard and graphics devices as they are found. + */ +void +bus_walk(struct device_path *idp) +{ + struct device_path dp; + struct pdc_memmap memmap; + struct iodc_data mptr; + int err, i, kluge_ps2 = 0; /* kluge, see below */ + + for (i = 0; i < MAXMODBUS; i++) { + + if (idp) { + dp.dp_bc[0] = idp->dp_bc[1]; + dp.dp_bc[1] = idp->dp_bc[2]; + dp.dp_bc[2] = idp->dp_bc[3]; + dp.dp_bc[3] = idp->dp_bc[4]; + dp.dp_bc[4] = idp->dp_bc[5]; + dp.dp_bc[5] = idp->dp_mod; + } else { + dp.dp_bc[0] = dp.dp_bc[1] = dp.dp_bc[2] = + dp.dp_bc[3] = dp.dp_bc[4] = dp.dp_bc[5] = -1; + } + + dp.dp_mod = i; + if ((pdc)(PDC_MEMMAP, PDC_MEMMAP_HPA, &memmap, &dp) < 0 && + (pdc)(PDC_SYSMAP, PDC_SYSMAP_HPA, &memmap, &dp) < 0) + continue; + + if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, &pdcbuf, memmap.hpa, + IODC_DATA, &mptr, sizeof(mptr))) < 0) + continue; + +#ifdef DEBUG + printf("device %d/%d/%d/%d/%d/%d " + "flags %d mod %x type %x model %x\n", + dp.dp_bc[0], dp.dp_bc[1], dp.dp_bc[2], dp.dp_bc[3], + dp.dp_bc[4], dp.dp_bc[5], dp.dp_flags, dp.dp_mod, + mptr.iodc_type, mptr.iodc_sv_model); +#endif + /* + * If the device can be considered as a valid rs232, + * graphics console or keyboard, register it. + * + * Unfortunately, devices which should be considered as + * ``main'' aren't necessarily seen first. + * The rules we try to enforce here are as follows: + * - GIO PS/2 ports wins over any other PS/2 port. + * - the first GIO serial found wins over any other + * serial port. + * The second rule is a bit tricky to achieve, since on + * some machines (for example, 715/100XC), the two serial + * ports are not seen as attached to the same busses... + */ + switch (mptr.iodc_type) { + case HPPA_TYPE_BCPORT: + bus_walk(&dp); + break; + case HPPA_TYPE_BHA: + case HPPA_TYPE_BRIDGE: + /* if there was no phantomas here */ + if (dp.dp_bc[5] == -1) { + dp.dp_bc[0] = dp.dp_bc[1]; + dp.dp_bc[1] = dp.dp_bc[2]; + dp.dp_bc[2] = dp.dp_bc[3]; + dp.dp_bc[3] = dp.dp_bc[4]; + dp.dp_bc[4] = dp.dp_bc[5]; + dp.dp_bc[5] = dp.dp_mod; + dp.dp_mod = 0; + } + bus_walk(&dp); + break; + case HPPA_TYPE_ADIRECT: + switch (mptr.iodc_sv_model) { + case HPPA_ADIRECT_RS232: + register_device(serials, MAX_SERIALS, + &dp, &mptr, SERIAL, 0); + break; + case HPPA_ADIRECT_HIL: + register_device(keyboards, MAX_KEYBOARDS, + &dp, &mptr, HIL, 0); + break; + case HPPA_ADIRECT_PEACOCK: + case HPPA_ADIRECT_LEONARDO: + register_device(graphics, MAX_GRAPHICS, + &dp, &mptr, GRAPHICS, 0); + break; + } + break; + case HPPA_TYPE_FIO: + switch (mptr.iodc_sv_model) { + case HPPA_FIO_HIL: + register_device(keyboards, MAX_KEYBOARDS, + &dp, &mptr, HIL, 0); + break; + case HPPA_FIO_RS232: + register_device(serials, MAX_SERIALS, + &dp, &mptr, SERIAL, 0); + break; + case HPPA_FIO_DINOPCK: + register_device(keyboards, MAX_KEYBOARDS, + &dp, &mptr, PS2, 0); + break; + case HPPA_FIO_GPCIO: + /* + * KLUGE! At this point, there is no way to + * know if this port is the keyboard port or + * the mouse port. + * Let's assume the first port found is the + * keyboard, and ignore the others. + */ + if (kluge_ps2 != 0) + break; + register_device(keyboards, MAX_KEYBOARDS, + &dp, &mptr, PS2, 1); + kluge_ps2++; + break; + case HPPA_FIO_GRS232: + { + int j, first; + + /* + * If a GIO serial port is already registered, + * register as extra port... + */ + first = 1; + for (j = 0; j < MAX_SERIALS; j++) + if (serials[j].type == SERIAL && + serials[j].iodc_type == + HPPA_TYPE_FIO && + serials[j].iodc_model == + HPPA_FIO_GRS232) { + first = 0; + break; + } + + register_device(serials, MAX_SERIALS, + &dp, &mptr, SERIAL, first); + } + break; + case HPPA_FIO_SGC: + register_device(graphics, MAX_GRAPHICS, + &dp, &mptr, GRAPHICS, 0); + break; + case HPPA_FIO_GSGC: + register_device(graphics, MAX_GRAPHICS, + &dp, &mptr, GRAPHICS, 1); + break; + } + break; + } + } +} + +void +register_device(devlist, cnt, dp, mptr, type, first) + struct consoledev *devlist; + int cnt; + struct device_path *dp; + struct iodc_data *mptr; + int type; + int first; +{ + int i; + struct consoledev *dev; + + for (i = 0, dev = devlist; i < cnt; i++, dev++) + if (dev->type == 0) + break; + + if (i == cnt) { +#ifdef DEBUG + printf("can't register device, need more room!\n"); +#endif + return; + } + + /* + * If this is supposedly the main device, insert on top + */ + if (first != 0) { + memcpy(devlist + 1, devlist, + (cnt - 1) * sizeof(struct consoledev)); + dev = devlist; + } + + dev->dp = *dp; + dev->type = type; + dev->iodc_type = mptr->iodc_type; + dev->iodc_model = mptr->iodc_sv_model; + +#ifdef DEBUG + printf("(registered as type %d)\n", type); +#endif +} |