19a22473cSFarhan Ali /* 29a22473cSFarhan Ali * SCLP ASCII access driver 39a22473cSFarhan Ali * 49a22473cSFarhan Ali * Copyright (c) 2013 Alexander Graf <agraf@suse.de> 59a22473cSFarhan Ali * 69a22473cSFarhan Ali * This work is licensed under the terms of the GNU GPL, version 2 or (at 79a22473cSFarhan Ali * your option) any later version. See the COPYING file in the top-level 89a22473cSFarhan Ali * directory. 99a22473cSFarhan Ali */ 109a22473cSFarhan Ali 1190806fecSThomas Huth #include "libc.h" 129a22473cSFarhan Ali #include "s390-ccw.h" 139a22473cSFarhan Ali #include "sclp.h" 149a22473cSFarhan Ali 153639f93fSThomas Huth long write(int fd, const void *str, size_t len); 163639f93fSThomas Huth 179a22473cSFarhan Ali static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096))); 189a22473cSFarhan Ali 19af3bb73aSThomas Huth const unsigned char ebc2asc[256] = 20af3bb73aSThomas Huth /* 0123456789abcdef0123456789abcdef */ 21af3bb73aSThomas Huth "................................" /* 1F */ 22af3bb73aSThomas Huth "................................" /* 3F */ 23af3bb73aSThomas Huth " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */ 24af3bb73aSThomas Huth "-/.........,%_>?.........`:#@'=\""/* 7F */ 25af3bb73aSThomas Huth ".abcdefghi.......jklmnopqr......" /* 9F */ 26af3bb73aSThomas Huth "..stuvwxyz......................" /* BF */ 27af3bb73aSThomas Huth ".ABCDEFGHI.......JKLMNOPQR......" /* DF */ 28af3bb73aSThomas Huth "..STUVWXYZ......0123456789......";/* FF */ 29af3bb73aSThomas Huth 309a22473cSFarhan Ali /* Perform service call. Return 0 on success, non-zero otherwise. */ 319a22473cSFarhan Ali static int sclp_service_call(unsigned int command, void *sccb) 329a22473cSFarhan Ali { 339a22473cSFarhan Ali int cc; 349a22473cSFarhan Ali 359a22473cSFarhan Ali asm volatile( 369a22473cSFarhan Ali " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ 379a22473cSFarhan Ali " ipm %0\n" 389a22473cSFarhan Ali " srl %0,28" 399a22473cSFarhan Ali : "=&d" (cc) : "d" (command), "a" (__pa(sccb)) 409a22473cSFarhan Ali : "cc", "memory"); 419a22473cSFarhan Ali consume_sclp_int(); 429a22473cSFarhan Ali if (cc == 3) 439a22473cSFarhan Ali return -EIO; 449a22473cSFarhan Ali if (cc == 2) 459a22473cSFarhan Ali return -EBUSY; 469a22473cSFarhan Ali return 0; 479a22473cSFarhan Ali } 489a22473cSFarhan Ali 499a22473cSFarhan Ali static void sclp_set_write_mask(void) 509a22473cSFarhan Ali { 519a22473cSFarhan Ali WriteEventMask *sccb = (void *)_sccb; 529a22473cSFarhan Ali 539a22473cSFarhan Ali sccb->h.length = sizeof(WriteEventMask); 549a22473cSFarhan Ali sccb->mask_length = sizeof(unsigned int); 559a22473cSFarhan Ali sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII; 569a22473cSFarhan Ali sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII; 579a22473cSFarhan Ali sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII; 589a22473cSFarhan Ali sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII; 599a22473cSFarhan Ali 609a22473cSFarhan Ali sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb); 619a22473cSFarhan Ali } 629a22473cSFarhan Ali 639a22473cSFarhan Ali void sclp_setup(void) 649a22473cSFarhan Ali { 659a22473cSFarhan Ali sclp_set_write_mask(); 669a22473cSFarhan Ali } 679a22473cSFarhan Ali 683639f93fSThomas Huth long write(int fd, const void *str, size_t len) 699a22473cSFarhan Ali { 709a22473cSFarhan Ali WriteEventData *sccb = (void *)_sccb; 717618c0aeSCollin L. Walling const char *p = str; 727618c0aeSCollin L. Walling size_t data_len = 0; 737618c0aeSCollin L. Walling size_t i; 749a22473cSFarhan Ali 753639f93fSThomas Huth if (fd != 1 && fd != 2) { 763639f93fSThomas Huth return -EIO; 773639f93fSThomas Huth } 783639f93fSThomas Huth 797618c0aeSCollin L. Walling for (i = 0; i < len; i++) { 807618c0aeSCollin L. Walling if ((data_len + 1) >= SCCB_DATA_LEN) { 817618c0aeSCollin L. Walling /* We would overflow the sccb buffer, abort early */ 827618c0aeSCollin L. Walling len = i; 837618c0aeSCollin L. Walling break; 847618c0aeSCollin L. Walling } 857618c0aeSCollin L. Walling 867618c0aeSCollin L. Walling if (*p == '\n') { 877618c0aeSCollin L. Walling /* Terminal emulators might need \r\n, so generate it */ 887618c0aeSCollin L. Walling sccb->data[data_len++] = '\r'; 897618c0aeSCollin L. Walling } 907618c0aeSCollin L. Walling 917618c0aeSCollin L. Walling sccb->data[data_len++] = *p; 927618c0aeSCollin L. Walling p++; 937618c0aeSCollin L. Walling } 947618c0aeSCollin L. Walling 957618c0aeSCollin L. Walling sccb->h.length = sizeof(WriteEventData) + data_len; 969a22473cSFarhan Ali sccb->h.function_code = SCLP_FC_NORMAL_WRITE; 977618c0aeSCollin L. Walling sccb->ebh.length = sizeof(EventBufferHeader) + data_len; 989a22473cSFarhan Ali sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; 999a22473cSFarhan Ali sccb->ebh.flags = 0; 1009a22473cSFarhan Ali 1019a22473cSFarhan Ali sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); 1023639f93fSThomas Huth 1033639f93fSThomas Huth return len; 1043639f93fSThomas Huth } 1053639f93fSThomas Huth 1063639f93fSThomas Huth void sclp_print(const char *str) 1073639f93fSThomas Huth { 108fc0e2087SCollin L. Walling write(1, str, strlen(str)); 1099a22473cSFarhan Ali } 1109a22473cSFarhan Ali 1119a22473cSFarhan Ali void sclp_get_loadparm_ascii(char *loadparm) 1129a22473cSFarhan Ali { 1139a22473cSFarhan Ali 1149a22473cSFarhan Ali ReadInfo *sccb = (void *)_sccb; 1159a22473cSFarhan Ali 1169a22473cSFarhan Ali memset((char *)_sccb, 0, sizeof(ReadInfo)); 1179a22473cSFarhan Ali sccb->h.length = sizeof(ReadInfo); 1189a22473cSFarhan Ali if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) { 1199a22473cSFarhan Ali ebcdic_to_ascii((char *) sccb->loadparm, loadparm, 8); 1209a22473cSFarhan Ali } 1219a22473cSFarhan Ali } 122*ff5dbf1bSCollin L. Walling 123*ff5dbf1bSCollin L. Walling int sclp_read(char *str, size_t count) 124*ff5dbf1bSCollin L. Walling { 125*ff5dbf1bSCollin L. Walling ReadEventData *sccb = (void *)_sccb; 126*ff5dbf1bSCollin L. Walling char *buf = (char *)(&sccb->ebh) + 7; 127*ff5dbf1bSCollin L. Walling 128*ff5dbf1bSCollin L. Walling /* If count exceeds max buffer size, then restrict it to the max size */ 129*ff5dbf1bSCollin L. Walling if (count > SCCB_SIZE - 8) { 130*ff5dbf1bSCollin L. Walling count = SCCB_SIZE - 8; 131*ff5dbf1bSCollin L. Walling } 132*ff5dbf1bSCollin L. Walling 133*ff5dbf1bSCollin L. Walling sccb->h.length = SCCB_SIZE; 134*ff5dbf1bSCollin L. Walling sccb->h.function_code = SCLP_UNCONDITIONAL_READ; 135*ff5dbf1bSCollin L. Walling 136*ff5dbf1bSCollin L. Walling sclp_service_call(SCLP_CMD_READ_EVENT_DATA, sccb); 137*ff5dbf1bSCollin L. Walling memcpy(str, buf, count); 138*ff5dbf1bSCollin L. Walling 139*ff5dbf1bSCollin L. Walling return sccb->ebh.length - 7; 140*ff5dbf1bSCollin L. Walling } 141