1 /* 2 * SCLP ASCII access driver 3 * 4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de> 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or (at 7 * your option) any later version. See the COPYING file in the top-level 8 * directory. 9 */ 10 11 #include "libc.h" 12 #include "s390-ccw.h" 13 #include "sclp.h" 14 15 long write(int fd, const void *str, size_t len); 16 17 static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096))); 18 19 const unsigned char ebc2asc[256] = 20 /* 0123456789abcdef0123456789abcdef */ 21 "................................" /* 1F */ 22 "................................" /* 3F */ 23 " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */ 24 "-/.........,%_>?.........`:#@'=\""/* 7F */ 25 ".abcdefghi.......jklmnopqr......" /* 9F */ 26 "..stuvwxyz......................" /* BF */ 27 ".ABCDEFGHI.......JKLMNOPQR......" /* DF */ 28 "..STUVWXYZ......0123456789......";/* FF */ 29 30 /* Perform service call. Return 0 on success, non-zero otherwise. */ 31 static int sclp_service_call(unsigned int command, void *sccb) 32 { 33 int cc; 34 35 asm volatile( 36 " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ 37 " ipm %0\n" 38 " srl %0,28" 39 : "=&d" (cc) : "d" (command), "a" (__pa(sccb)) 40 : "cc", "memory"); 41 consume_sclp_int(); 42 if (cc == 3) 43 return -EIO; 44 if (cc == 2) 45 return -EBUSY; 46 return 0; 47 } 48 49 static void sclp_set_write_mask(void) 50 { 51 WriteEventMask *sccb = (void *)_sccb; 52 53 sccb->h.length = sizeof(WriteEventMask); 54 sccb->mask_length = sizeof(unsigned int); 55 sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII; 56 sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII; 57 sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII; 58 sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII; 59 60 sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb); 61 } 62 63 void sclp_setup(void) 64 { 65 sclp_set_write_mask(); 66 } 67 68 static int _strlen(const char *str) 69 { 70 int i; 71 for (i = 0; *str; i++) 72 str++; 73 return i; 74 } 75 76 long write(int fd, const void *str, size_t len) 77 { 78 WriteEventData *sccb = (void *)_sccb; 79 const char *p = str; 80 size_t data_len = 0; 81 size_t i; 82 83 if (fd != 1 && fd != 2) { 84 return -EIO; 85 } 86 87 for (i = 0; i < len; i++) { 88 if ((data_len + 1) >= SCCB_DATA_LEN) { 89 /* We would overflow the sccb buffer, abort early */ 90 len = i; 91 break; 92 } 93 94 if (*p == '\n') { 95 /* Terminal emulators might need \r\n, so generate it */ 96 sccb->data[data_len++] = '\r'; 97 } 98 99 sccb->data[data_len++] = *p; 100 p++; 101 } 102 103 sccb->h.length = sizeof(WriteEventData) + data_len; 104 sccb->h.function_code = SCLP_FC_NORMAL_WRITE; 105 sccb->ebh.length = sizeof(EventBufferHeader) + data_len; 106 sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; 107 sccb->ebh.flags = 0; 108 109 sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); 110 111 return len; 112 } 113 114 void sclp_print(const char *str) 115 { 116 write(1, str, _strlen(str)); 117 } 118 119 void sclp_get_loadparm_ascii(char *loadparm) 120 { 121 122 ReadInfo *sccb = (void *)_sccb; 123 124 memset((char *)_sccb, 0, sizeof(ReadInfo)); 125 sccb->h.length = sizeof(ReadInfo); 126 if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) { 127 ebcdic_to_ascii((char *) sccb->loadparm, loadparm, 8); 128 } 129 } 130