sclp.c (3750B)
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 15long write(int fd, const void *str, size_t len); 16 17static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096))); 18 19const 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. */ 31static 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 49void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask) 50{ 51 WriteEventMask *sccb = (void *)_sccb; 52 53 sccb->h.length = sizeof(WriteEventMask); 54 sccb->mask_length = sizeof(unsigned int); 55 sccb->cp_receive_mask = receive_mask; 56 sccb->cp_send_mask = send_mask; 57 58 sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb); 59} 60 61void sclp_setup(void) 62{ 63 sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII); 64} 65 66long write(int fd, const void *str, size_t len) 67{ 68 WriteEventData *sccb = (void *)_sccb; 69 const char *p = str; 70 size_t data_len = 0; 71 size_t i; 72 73 if (fd != 1 && fd != 2) { 74 return -EIO; 75 } 76 77 for (i = 0; i < len; i++) { 78 if ((data_len + 1) >= SCCB_DATA_LEN) { 79 /* We would overflow the sccb buffer, abort early */ 80 len = i; 81 break; 82 } 83 84 if (*p == '\n') { 85 /* Terminal emulators might need \r\n, so generate it */ 86 sccb->data[data_len++] = '\r'; 87 } 88 89 sccb->data[data_len++] = *p; 90 p++; 91 } 92 93 sccb->h.length = sizeof(WriteEventData) + data_len; 94 sccb->h.function_code = SCLP_FC_NORMAL_WRITE; 95 sccb->ebh.length = sizeof(EventBufferHeader) + data_len; 96 sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; 97 sccb->ebh.flags = 0; 98 99 sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); 100 101 return len; 102} 103 104void sclp_print(const char *str) 105{ 106 write(1, str, strlen(str)); 107} 108 109void sclp_get_loadparm_ascii(char *loadparm) 110{ 111 112 ReadInfo *sccb = (void *)_sccb; 113 114 memset((char *)_sccb, 0, sizeof(ReadInfo)); 115 sccb->h.length = SCCB_SIZE; 116 if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) { 117 ebcdic_to_ascii((char *) sccb->loadparm, loadparm, LOADPARM_LEN); 118 } 119} 120 121int sclp_read(char *str, size_t count) 122{ 123 ReadEventData *sccb = (void *)_sccb; 124 char *buf = (char *)(&sccb->ebh) + 7; 125 126 /* If count exceeds max buffer size, then restrict it to the max size */ 127 if (count > SCCB_SIZE - 8) { 128 count = SCCB_SIZE - 8; 129 } 130 131 sccb->h.length = SCCB_SIZE; 132 sccb->h.function_code = SCLP_UNCONDITIONAL_READ; 133 134 sclp_service_call(SCLP_CMD_READ_EVENT_DATA, sccb); 135 memcpy(str, buf, count); 136 137 return sccb->ebh.length - 7; 138}