16c9f99dfSJanosch Frank /* SPDX-License-Identifier: GPL-2.0-or-later */ 27ed7df23SJanosch Frank /* 3*78be7ef2SJanosch Frank * SCLP line mode and ASCII console driver 4*78be7ef2SJanosch Frank * Some parts taken from the Linux kernel. 57ed7df23SJanosch Frank * 67ed7df23SJanosch Frank * Copyright (c) 2013 Alexander Graf <agraf@suse.de> 7*78be7ef2SJanosch Frank * 8*78be7ef2SJanosch Frank * Copyright IBM Corp. 1999 9*78be7ef2SJanosch Frank * Author(s): Martin Peschke <mpeschke@de.ibm.com> 10*78be7ef2SJanosch Frank * Martin Schwidefsky <schwidefsky@de.ibm.com> 117ed7df23SJanosch Frank */ 127ed7df23SJanosch Frank 137ed7df23SJanosch Frank #include <libcflat.h> 147ed7df23SJanosch Frank #include <string.h> 157ed7df23SJanosch Frank #include <asm/page.h> 1667bee4eeSJanosch Frank #include <asm/arch_def.h> 1767bee4eeSJanosch Frank #include <asm/io.h> 1804a401ddSJanosch Frank #include <asm/spinlock.h> 1997d4fb30SJanosch Frank #include "hardware.h" 207ed7df23SJanosch Frank #include "sclp.h" 217ed7df23SJanosch Frank 2267bee4eeSJanosch Frank /* 2367bee4eeSJanosch Frank * ASCII (IBM PC 437) -> EBCDIC 037 2467bee4eeSJanosch Frank */ 2567bee4eeSJanosch Frank static uint8_t _ascebc[256] = { 2667bee4eeSJanosch Frank /*00 NUL SOH STX ETX EOT ENQ ACK BEL */ 2767bee4eeSJanosch Frank 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 2867bee4eeSJanosch Frank /*08 BS HT LF VT FF CR SO SI */ 2967bee4eeSJanosch Frank /* ->NL */ 3067bee4eeSJanosch Frank 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 3167bee4eeSJanosch Frank /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 3267bee4eeSJanosch Frank 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 3367bee4eeSJanosch Frank /*18 CAN EM SUB ESC FS GS RS US */ 3467bee4eeSJanosch Frank /* ->IGS ->IRS ->IUS */ 3567bee4eeSJanosch Frank 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, 3667bee4eeSJanosch Frank /*20 SP ! " # $ % & ' */ 3767bee4eeSJanosch Frank 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 3867bee4eeSJanosch Frank /*28 ( ) * + , - . / */ 3967bee4eeSJanosch Frank 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, 4067bee4eeSJanosch Frank /*30 0 1 2 3 4 5 6 7 */ 4167bee4eeSJanosch Frank 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 4267bee4eeSJanosch Frank /*38 8 9 : ; < = > ? */ 4367bee4eeSJanosch Frank 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, 4467bee4eeSJanosch Frank /*40 @ A B C D E F G */ 4567bee4eeSJanosch Frank 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 4667bee4eeSJanosch Frank /*48 H I J K L M N O */ 4767bee4eeSJanosch Frank 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 4867bee4eeSJanosch Frank /*50 P Q R S T U V W */ 4967bee4eeSJanosch Frank 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 5067bee4eeSJanosch Frank /*58 X Y Z [ \ ] ^ _ */ 5167bee4eeSJanosch Frank 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, 5267bee4eeSJanosch Frank /*60 ` a b c d e f g */ 5367bee4eeSJanosch Frank 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 5467bee4eeSJanosch Frank /*68 h i j k l m n o */ 5567bee4eeSJanosch Frank 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 5667bee4eeSJanosch Frank /*70 p q r s t u v w */ 5767bee4eeSJanosch Frank 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 5867bee4eeSJanosch Frank /*78 x y z { | } ~ DL */ 5967bee4eeSJanosch Frank 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, 6067bee4eeSJanosch Frank /*80*/ 6167bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 6267bee4eeSJanosch Frank /*88*/ 6367bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 6467bee4eeSJanosch Frank /*90*/ 6567bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 6667bee4eeSJanosch Frank /*98*/ 6767bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 6867bee4eeSJanosch Frank /*A0*/ 6967bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 7067bee4eeSJanosch Frank /*A8*/ 7167bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 7267bee4eeSJanosch Frank /*B0*/ 7367bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 7467bee4eeSJanosch Frank /*B8*/ 7567bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 7667bee4eeSJanosch Frank /*C0*/ 7767bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 7867bee4eeSJanosch Frank /*C8*/ 7967bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 8067bee4eeSJanosch Frank /*D0*/ 8167bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 8267bee4eeSJanosch Frank /*D8*/ 8367bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 8467bee4eeSJanosch Frank /*E0 sz */ 8567bee4eeSJanosch Frank 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 8667bee4eeSJanosch Frank /*E8*/ 8767bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 8867bee4eeSJanosch Frank /*F0*/ 8967bee4eeSJanosch Frank 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 9067bee4eeSJanosch Frank /*F8*/ 9167bee4eeSJanosch Frank 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF 9267bee4eeSJanosch Frank }; 9367bee4eeSJanosch Frank 94*78be7ef2SJanosch Frank static const uint8_t _ebcasc[] = { 95*78be7ef2SJanosch Frank 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, 96*78be7ef2SJanosch Frank 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 97*78be7ef2SJanosch Frank 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, 98*78be7ef2SJanosch Frank 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 99*78be7ef2SJanosch Frank 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, 100*78be7ef2SJanosch Frank 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, 101*78be7ef2SJanosch Frank 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, 102*78be7ef2SJanosch Frank 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, 103*78be7ef2SJanosch Frank 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, 104*78be7ef2SJanosch Frank 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, 105*78be7ef2SJanosch Frank 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, 106*78be7ef2SJanosch Frank 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, 107*78be7ef2SJanosch Frank 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, 108*78be7ef2SJanosch Frank 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, 109*78be7ef2SJanosch Frank 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 110*78be7ef2SJanosch Frank 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, 111*78be7ef2SJanosch Frank 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 112*78be7ef2SJanosch Frank 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, 113*78be7ef2SJanosch Frank 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 114*78be7ef2SJanosch Frank 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, 115*78be7ef2SJanosch Frank 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 116*78be7ef2SJanosch Frank 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, 117*78be7ef2SJanosch Frank 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, 118*78be7ef2SJanosch Frank 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, 119*78be7ef2SJanosch Frank 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 120*78be7ef2SJanosch Frank 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, 121*78be7ef2SJanosch Frank 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 122*78be7ef2SJanosch Frank 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, 123*78be7ef2SJanosch Frank 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 124*78be7ef2SJanosch Frank 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, 125*78be7ef2SJanosch Frank 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 126*78be7ef2SJanosch Frank 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07, 127*78be7ef2SJanosch Frank }; 128*78be7ef2SJanosch Frank 12997d4fb30SJanosch Frank static bool lpar_ascii_compat; 13097d4fb30SJanosch Frank 13104a401ddSJanosch Frank static char lm_buff[120]; 13204a401ddSJanosch Frank static unsigned char lm_buff_off; 13304a401ddSJanosch Frank static struct spinlock lm_buff_lock; 13404a401ddSJanosch Frank 13542ae7d5bSNico Boehr static char read_buf[4096]; 13642ae7d5bSNico Boehr static int read_index = sizeof(read_buf) - 1; 13742ae7d5bSNico Boehr static int read_buf_length = 0; 13842ae7d5bSNico Boehr 13967bee4eeSJanosch Frank static void sclp_print_ascii(const char *str) 14067bee4eeSJanosch Frank { 14167bee4eeSJanosch Frank int len = strlen(str); 14267bee4eeSJanosch Frank WriteEventData *sccb = (void *)_sccb; 14397d4fb30SJanosch Frank char *str_dest = (char *)&sccb->msg; 14497d4fb30SJanosch Frank int src_ind, dst_ind; 14567bee4eeSJanosch Frank 14667bee4eeSJanosch Frank sclp_mark_busy(); 14767bee4eeSJanosch Frank memset(sccb, 0, sizeof(*sccb)); 14897d4fb30SJanosch Frank 14997d4fb30SJanosch Frank for (src_ind = 0, dst_ind = 0; 15097d4fb30SJanosch Frank src_ind < len && dst_ind < (PAGE_SIZE / 2); 15197d4fb30SJanosch Frank src_ind++, dst_ind++) { 15297d4fb30SJanosch Frank str_dest[dst_ind] = str[src_ind]; 15397d4fb30SJanosch Frank /* Add a \r to the \n for HMC ASCII console */ 15497d4fb30SJanosch Frank if (str[src_ind] == '\n' && lpar_ascii_compat) { 15597d4fb30SJanosch Frank dst_ind++; 15697d4fb30SJanosch Frank str_dest[dst_ind] = '\r'; 15797d4fb30SJanosch Frank } 15897d4fb30SJanosch Frank } 15997d4fb30SJanosch Frank 16097d4fb30SJanosch Frank /* Len might have changed because of the compat behavior */ 16197d4fb30SJanosch Frank len = dst_ind; 16267bee4eeSJanosch Frank sccb->h.length = offsetof(WriteEventData, msg) + len; 16367bee4eeSJanosch Frank sccb->h.function_code = SCLP_FC_NORMAL_WRITE; 16467bee4eeSJanosch Frank sccb->ebh.length = sizeof(EventBufferHeader) + len; 16567bee4eeSJanosch Frank sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; 16667bee4eeSJanosch Frank 16767bee4eeSJanosch Frank sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); 16867bee4eeSJanosch Frank } 16967bee4eeSJanosch Frank 17004a401ddSJanosch Frank static void lm_print(const char *buff, int len) 17167bee4eeSJanosch Frank { 17267bee4eeSJanosch Frank unsigned char *ptr, *end, ch; 17304a401ddSJanosch Frank unsigned int count, offset; 17467bee4eeSJanosch Frank struct WriteEventData *sccb; 17567bee4eeSJanosch Frank struct mdb *mdb; 17667bee4eeSJanosch Frank struct mto *mto; 17767bee4eeSJanosch Frank struct go *go; 17867bee4eeSJanosch Frank 17967bee4eeSJanosch Frank sclp_mark_busy(); 18067bee4eeSJanosch Frank sccb = (struct WriteEventData *) _sccb; 18167bee4eeSJanosch Frank end = (unsigned char *) sccb + 4096 - 1; 18267bee4eeSJanosch Frank memset(sccb, 0, sizeof(*sccb)); 18367bee4eeSJanosch Frank ptr = (unsigned char *) &sccb->msg.mdb.mto; 18467bee4eeSJanosch Frank offset = 0; 18567bee4eeSJanosch Frank do { 18667bee4eeSJanosch Frank for (count = sizeof(*mto); offset < len; count++) { 18704a401ddSJanosch Frank ch = buff[offset++]; 18867bee4eeSJanosch Frank if (ch == 0x0a || ptr + count > end) 18967bee4eeSJanosch Frank break; 19067bee4eeSJanosch Frank ptr[count] = _ascebc[ch]; 19167bee4eeSJanosch Frank } 19267bee4eeSJanosch Frank mto = (struct mto *) ptr; 19367bee4eeSJanosch Frank mto->length = count; 19467bee4eeSJanosch Frank mto->type = 4; 19567bee4eeSJanosch Frank mto->line_type_flags = LNTPFLGS_ENDTEXT; 19667bee4eeSJanosch Frank ptr += count; 19767bee4eeSJanosch Frank } while (offset < len && ptr + sizeof(*mto) <= end); 19867bee4eeSJanosch Frank len = ptr - (unsigned char *) sccb; 19967bee4eeSJanosch Frank sccb->h.length = len - offsetof(struct WriteEventData, h); 20067bee4eeSJanosch Frank sccb->h.function_code = SCLP_FC_NORMAL_WRITE; 20167bee4eeSJanosch Frank sccb->ebh.type = EVTYP_MSG; 20267bee4eeSJanosch Frank sccb->ebh.length = len - offsetof(struct WriteEventData, ebh); 20367bee4eeSJanosch Frank mdb = &sccb->msg.mdb; 20467bee4eeSJanosch Frank mdb->header.type = 1; 20567bee4eeSJanosch Frank mdb->header.tag = 0xD4C4C240; 20667bee4eeSJanosch Frank mdb->header.revision_code = 1; 20767bee4eeSJanosch Frank mdb->header.length = len - offsetof(struct WriteEventData, msg.mdb.header); 20867bee4eeSJanosch Frank go = &mdb->go; 20967bee4eeSJanosch Frank go->length = sizeof(*go); 21067bee4eeSJanosch Frank go->type = 1; 21167bee4eeSJanosch Frank sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); 21267bee4eeSJanosch Frank } 21367bee4eeSJanosch Frank 21404a401ddSJanosch Frank 21504a401ddSJanosch Frank /* 21604a401ddSJanosch Frank * In contrast to the ascii console, linemode produces a new 21704a401ddSJanosch Frank * line with every write of data. The report() function uses 21804a401ddSJanosch Frank * several printf() calls to generate a line of data which 21904a401ddSJanosch Frank * would all end up on different lines. 22004a401ddSJanosch Frank * 22104a401ddSJanosch Frank * Hence we buffer here until we encounter a \n or the buffer 22204a401ddSJanosch Frank * is full. That means that linemode output can look a bit 22304a401ddSJanosch Frank * different from ascii and that it takes a bit longer for 22404a401ddSJanosch Frank * lines to appear. 22504a401ddSJanosch Frank */ 22604a401ddSJanosch Frank static void sclp_print_lm(const char *str) 22704a401ddSJanosch Frank { 22804a401ddSJanosch Frank int i; 22904a401ddSJanosch Frank const int len = strlen(str); 23004a401ddSJanosch Frank 23104a401ddSJanosch Frank spin_lock(&lm_buff_lock); 23204a401ddSJanosch Frank 23304a401ddSJanosch Frank for (i = 0; i < len; i++) { 23404a401ddSJanosch Frank lm_buff[lm_buff_off++] = str[i]; 23504a401ddSJanosch Frank 23604a401ddSJanosch Frank /* Buffer full or newline? */ 23704a401ddSJanosch Frank if (str[i] == '\n' || lm_buff_off == (ARRAY_SIZE(lm_buff) - 1)) { 23804a401ddSJanosch Frank lm_print(lm_buff, lm_buff_off); 23904a401ddSJanosch Frank lm_buff_off = 0; 24004a401ddSJanosch Frank } 24104a401ddSJanosch Frank } 24204a401ddSJanosch Frank spin_unlock(&lm_buff_lock); 24304a401ddSJanosch Frank } 24404a401ddSJanosch Frank 24567bee4eeSJanosch Frank /* 24667bee4eeSJanosch Frank * SCLP needs to be initialized by setting a send and receive mask, 24767bee4eeSJanosch Frank * indicating which messages the control program (we) want(s) to 24867bee4eeSJanosch Frank * send/receive. 24967bee4eeSJanosch Frank */ 25042ae7d5bSNico Boehr static void sclp_write_event_mask(int receive_mask, int send_mask) 2517ed7df23SJanosch Frank { 2527ed7df23SJanosch Frank WriteEventMask *sccb = (void *)_sccb; 2537ed7df23SJanosch Frank 2548ead801eSJanosch Frank sclp_mark_busy(); 25567bee4eeSJanosch Frank memset(_sccb, 0, sizeof(*sccb)); 2567ed7df23SJanosch Frank sccb->h.length = sizeof(WriteEventMask); 25767bee4eeSJanosch Frank sccb->h.function_code = SCLP_FC_NORMAL_WRITE; 25867bee4eeSJanosch Frank sccb->mask_length = sizeof(sccb_mask_t); 25967bee4eeSJanosch Frank 26042ae7d5bSNico Boehr sccb->cp_receive_mask = receive_mask; 26142ae7d5bSNico Boehr sccb->cp_send_mask = send_mask; 2627ed7df23SJanosch Frank 2637ed7df23SJanosch Frank sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb); 26467bee4eeSJanosch Frank assert(sccb->h.response_code == SCLP_RC_NORMAL_COMPLETION); 2657ed7df23SJanosch Frank } 2667ed7df23SJanosch Frank 26742ae7d5bSNico Boehr static void sclp_console_enable_read(void) 26842ae7d5bSNico Boehr { 269*78be7ef2SJanosch Frank sclp_write_event_mask(SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_OPCMD, 270*78be7ef2SJanosch Frank SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG); 27142ae7d5bSNico Boehr } 27242ae7d5bSNico Boehr 27342ae7d5bSNico Boehr static void sclp_console_disable_read(void) 27442ae7d5bSNico Boehr { 27542ae7d5bSNico Boehr sclp_write_event_mask(0, SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG); 27642ae7d5bSNico Boehr } 27742ae7d5bSNico Boehr 2787ed7df23SJanosch Frank void sclp_console_setup(void) 2797ed7df23SJanosch Frank { 28097d4fb30SJanosch Frank lpar_ascii_compat = detect_host() == HOST_IS_LPAR; 28197d4fb30SJanosch Frank 28242ae7d5bSNico Boehr /* We send ASCII and line mode. */ 28342ae7d5bSNico Boehr sclp_write_event_mask(0, SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG); 28497d4fb30SJanosch Frank /* Hard terminal reset to clear screen for HMC ASCII console */ 28597d4fb30SJanosch Frank if (lpar_ascii_compat) 28697d4fb30SJanosch Frank sclp_print_ascii("\ec"); 2877ed7df23SJanosch Frank } 2887ed7df23SJanosch Frank 2897ed7df23SJanosch Frank void sclp_print(const char *str) 2907ed7df23SJanosch Frank { 29167bee4eeSJanosch Frank /* 29267bee4eeSJanosch Frank * z/VM advertises a vt220 console which is not functional: 29367bee4eeSJanosch Frank * (response code 05F0, "not active because of the state of 29467bee4eeSJanosch Frank * the machine"). Hence testing the masks would only work if 29567bee4eeSJanosch Frank * we also use stsi data to distinguish z/VM. 29667bee4eeSJanosch Frank * 29767bee4eeSJanosch Frank * Let's rather print on all available consoles. 29867bee4eeSJanosch Frank */ 29967bee4eeSJanosch Frank if (strlen(str) > (PAGE_SIZE / 2)) { 30067bee4eeSJanosch Frank sclp_print_ascii("Warning: Printing is limited to 2KB of data."); 30167bee4eeSJanosch Frank sclp_print_lm("Warning: Printing is limited to 2KB of data."); 30267bee4eeSJanosch Frank return; 30367bee4eeSJanosch Frank } 30467bee4eeSJanosch Frank sclp_print_ascii(str); 30567bee4eeSJanosch Frank sclp_print_lm(str); 3067ed7df23SJanosch Frank } 30742ae7d5bSNico Boehr 308*78be7ef2SJanosch Frank static char *console_read_ascii(struct EventBufferHeader *ebh, int *len) 309*78be7ef2SJanosch Frank { 310*78be7ef2SJanosch Frank struct ReadEventDataAsciiConsole *evdata = (void *)ebh; 311*78be7ef2SJanosch Frank const int max_event_buffer_len = SCCB_SIZE - offsetof(ReadEventDataAsciiConsole, ebh); 312*78be7ef2SJanosch Frank const int event_buffer_ascii_recv_header_len = offsetof(ReadEventDataAsciiConsole, data); 313*78be7ef2SJanosch Frank 314*78be7ef2SJanosch Frank assert(ebh->length <= max_event_buffer_len); 315*78be7ef2SJanosch Frank assert(ebh->length > event_buffer_ascii_recv_header_len); 316*78be7ef2SJanosch Frank 317*78be7ef2SJanosch Frank *len = ebh->length - event_buffer_ascii_recv_header_len; 318*78be7ef2SJanosch Frank return evdata->data; 319*78be7ef2SJanosch Frank } 320*78be7ef2SJanosch Frank 321*78be7ef2SJanosch Frank 322*78be7ef2SJanosch Frank static struct gds_vector *sclp_find_gds_vector(void *start, void *end, uint16_t id) 323*78be7ef2SJanosch Frank { 324*78be7ef2SJanosch Frank struct gds_vector *v; 325*78be7ef2SJanosch Frank 326*78be7ef2SJanosch Frank for (v = start; (void *)v < end; v = (void *)v + v->length) 327*78be7ef2SJanosch Frank if (v->gds_id == id) 328*78be7ef2SJanosch Frank return v; 329*78be7ef2SJanosch Frank return NULL; 330*78be7ef2SJanosch Frank } 331*78be7ef2SJanosch Frank 332*78be7ef2SJanosch Frank static struct gds_subvector *sclp_eval_selfdeftextmsg(struct gds_subvector *sv) 333*78be7ef2SJanosch Frank { 334*78be7ef2SJanosch Frank void *end; 335*78be7ef2SJanosch Frank 336*78be7ef2SJanosch Frank end = (void *)sv + sv->length; 337*78be7ef2SJanosch Frank for (sv = sv + 1; (void *)sv < end; sv = (void *)sv + sv->length) 338*78be7ef2SJanosch Frank if (sv->key == 0x30) 339*78be7ef2SJanosch Frank return sv; 340*78be7ef2SJanosch Frank return NULL; 341*78be7ef2SJanosch Frank } 342*78be7ef2SJanosch Frank 343*78be7ef2SJanosch Frank static struct gds_subvector *sclp_eval_textcmd(struct gds_vector *v) 344*78be7ef2SJanosch Frank { 345*78be7ef2SJanosch Frank struct gds_subvector *sv; 346*78be7ef2SJanosch Frank void *end; 347*78be7ef2SJanosch Frank 348*78be7ef2SJanosch Frank end = (void *)v + v->length; 349*78be7ef2SJanosch Frank for (sv = (struct gds_subvector *)(v + 1); (void *)sv < end; 350*78be7ef2SJanosch Frank sv = (void *)sv + sv->length) 351*78be7ef2SJanosch Frank if (sv->key == GDS_KEY_SELFDEFTEXTMSG) 352*78be7ef2SJanosch Frank return sclp_eval_selfdeftextmsg(sv); 353*78be7ef2SJanosch Frank return NULL; 354*78be7ef2SJanosch Frank } 355*78be7ef2SJanosch Frank 356*78be7ef2SJanosch Frank static struct gds_subvector *sclp_eval_cpmsu(struct gds_vector *v) 357*78be7ef2SJanosch Frank { 358*78be7ef2SJanosch Frank void *end; 359*78be7ef2SJanosch Frank 360*78be7ef2SJanosch Frank end = (void *)v + v->length; 361*78be7ef2SJanosch Frank for (v = v + 1; (void *)v < end; v = (void *)v + v->length) 362*78be7ef2SJanosch Frank if (v->gds_id == GDS_ID_TEXTCMD) 363*78be7ef2SJanosch Frank return sclp_eval_textcmd(v); 364*78be7ef2SJanosch Frank return NULL; 365*78be7ef2SJanosch Frank } 366*78be7ef2SJanosch Frank 367*78be7ef2SJanosch Frank static struct gds_subvector *sclp_eval_mdsmu(struct gds_vector *v) 368*78be7ef2SJanosch Frank { 369*78be7ef2SJanosch Frank v = sclp_find_gds_vector(v + 1, (void *)v + v->length, GDS_ID_CPMSU); 370*78be7ef2SJanosch Frank if (v) 371*78be7ef2SJanosch Frank return sclp_eval_cpmsu(v); 372*78be7ef2SJanosch Frank return NULL; 373*78be7ef2SJanosch Frank } 374*78be7ef2SJanosch Frank 375*78be7ef2SJanosch Frank static char *console_read_lm(struct EventBufferHeader *ebh, int *len) 376*78be7ef2SJanosch Frank { 377*78be7ef2SJanosch Frank struct gds_vector *v = (void *)ebh + sizeof(*ebh); 378*78be7ef2SJanosch Frank struct gds_subvector *sv; 379*78be7ef2SJanosch Frank 380*78be7ef2SJanosch Frank v = sclp_find_gds_vector(v, (void *)ebh + ebh->length, 381*78be7ef2SJanosch Frank GDS_ID_MDSMU); 382*78be7ef2SJanosch Frank if (!v) 383*78be7ef2SJanosch Frank return NULL; 384*78be7ef2SJanosch Frank 385*78be7ef2SJanosch Frank sv = sclp_eval_mdsmu(v); 386*78be7ef2SJanosch Frank if (!sv) 387*78be7ef2SJanosch Frank return NULL; 388*78be7ef2SJanosch Frank 389*78be7ef2SJanosch Frank *len = sv->length - (sizeof(*sv)); 390*78be7ef2SJanosch Frank return (char *)(sv + 1); 391*78be7ef2SJanosch Frank } 392*78be7ef2SJanosch Frank 393*78be7ef2SJanosch Frank static void ebc_to_asc(char *data, int len) 394*78be7ef2SJanosch Frank { 395*78be7ef2SJanosch Frank int i; 396*78be7ef2SJanosch Frank 397*78be7ef2SJanosch Frank for (i = 0; i < len; i++) 398*78be7ef2SJanosch Frank data[i] = _ebcasc[(uint8_t)data[i]]; 399*78be7ef2SJanosch Frank } 400*78be7ef2SJanosch Frank 40142ae7d5bSNico Boehr static int console_refill_read_buffer(void) 40242ae7d5bSNico Boehr { 403*78be7ef2SJanosch Frank struct SCCBHeader *sccb = (struct SCCBHeader *)_sccb; 404*78be7ef2SJanosch Frank struct EventBufferHeader *ebh = (void *)_sccb + sizeof(struct SCCBHeader); 405*78be7ef2SJanosch Frank char *data; 406*78be7ef2SJanosch Frank int ret = -1, len; 40742ae7d5bSNico Boehr 40842ae7d5bSNico Boehr sclp_console_enable_read(); 40942ae7d5bSNico Boehr 41042ae7d5bSNico Boehr sclp_mark_busy(); 411*78be7ef2SJanosch Frank memset(_sccb, 0, SCCB_SIZE); 412*78be7ef2SJanosch Frank sccb->length = PAGE_SIZE; 413*78be7ef2SJanosch Frank sccb->function_code = SCLP_UNCONDITIONAL_READ; 414*78be7ef2SJanosch Frank sccb->control_mask[2] = SCLP_CM2_VARIABLE_LENGTH_RESPONSE; 41542ae7d5bSNico Boehr 41642ae7d5bSNico Boehr sclp_service_call(SCLP_CMD_READ_EVENT_DATA, sccb); 41742ae7d5bSNico Boehr 418*78be7ef2SJanosch Frank if (sccb->response_code == SCLP_RC_NO_EVENT_BUFFERS_STORED) 419*78be7ef2SJanosch Frank goto out; 420*78be7ef2SJanosch Frank 421*78be7ef2SJanosch Frank switch (ebh->type) { 422*78be7ef2SJanosch Frank case SCLP_EVENT_OP_CMD: 423*78be7ef2SJanosch Frank data = console_read_lm(ebh, &len); 424*78be7ef2SJanosch Frank if (data) 425*78be7ef2SJanosch Frank ebc_to_asc(data, len); 426*78be7ef2SJanosch Frank break; 427*78be7ef2SJanosch Frank case SCLP_EVENT_ASCII_CONSOLE_DATA: 428*78be7ef2SJanosch Frank data = console_read_ascii(ebh, &len); 429*78be7ef2SJanosch Frank break; 430*78be7ef2SJanosch Frank default: 43142ae7d5bSNico Boehr goto out; 43242ae7d5bSNico Boehr } 43342ae7d5bSNico Boehr 434*78be7ef2SJanosch Frank if (!data) 435*78be7ef2SJanosch Frank goto out; 43642ae7d5bSNico Boehr 437*78be7ef2SJanosch Frank assert(len <= sizeof(read_buf)); 438*78be7ef2SJanosch Frank memcpy(read_buf, data, len); 43942ae7d5bSNico Boehr 44042ae7d5bSNico Boehr read_index = 0; 44142ae7d5bSNico Boehr ret = 0; 44242ae7d5bSNico Boehr 44342ae7d5bSNico Boehr out: 44442ae7d5bSNico Boehr sclp_console_disable_read(); 44542ae7d5bSNico Boehr 44642ae7d5bSNico Boehr return ret; 44742ae7d5bSNico Boehr } 44842ae7d5bSNico Boehr 44942ae7d5bSNico Boehr int __getchar(void) 45042ae7d5bSNico Boehr { 45142ae7d5bSNico Boehr int ret; 45242ae7d5bSNico Boehr 45342ae7d5bSNico Boehr if (read_index >= read_buf_length) { 45442ae7d5bSNico Boehr ret = console_refill_read_buffer(); 45542ae7d5bSNico Boehr if (ret < 0) 45642ae7d5bSNico Boehr return ret; 45742ae7d5bSNico Boehr } 45842ae7d5bSNico Boehr 45942ae7d5bSNico Boehr return read_buf[read_index++]; 46042ae7d5bSNico Boehr } 461