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 49dbf2091aSCollin L. Walling void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask) 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); 55dbf2091aSCollin L. Walling sccb->cp_receive_mask = receive_mask; 56dbf2091aSCollin L. Walling sccb->cp_send_mask = send_mask; 579a22473cSFarhan Ali 589a22473cSFarhan Ali sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb); 599a22473cSFarhan Ali } 609a22473cSFarhan Ali 619a22473cSFarhan Ali void sclp_setup(void) 629a22473cSFarhan Ali { 63dbf2091aSCollin L. Walling sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII); 649a22473cSFarhan Ali } 659a22473cSFarhan Ali 663639f93fSThomas Huth long write(int fd, const void *str, size_t len) 679a22473cSFarhan Ali { 689a22473cSFarhan Ali WriteEventData *sccb = (void *)_sccb; 697618c0aeSCollin L. Walling const char *p = str; 707618c0aeSCollin L. Walling size_t data_len = 0; 717618c0aeSCollin L. Walling size_t i; 729a22473cSFarhan Ali 733639f93fSThomas Huth if (fd != 1 && fd != 2) { 743639f93fSThomas Huth return -EIO; 753639f93fSThomas Huth } 763639f93fSThomas Huth 777618c0aeSCollin L. Walling for (i = 0; i < len; i++) { 787618c0aeSCollin L. Walling if ((data_len + 1) >= SCCB_DATA_LEN) { 797618c0aeSCollin L. Walling /* We would overflow the sccb buffer, abort early */ 807618c0aeSCollin L. Walling len = i; 817618c0aeSCollin L. Walling break; 827618c0aeSCollin L. Walling } 837618c0aeSCollin L. Walling 847618c0aeSCollin L. Walling if (*p == '\n') { 857618c0aeSCollin L. Walling /* Terminal emulators might need \r\n, so generate it */ 867618c0aeSCollin L. Walling sccb->data[data_len++] = '\r'; 877618c0aeSCollin L. Walling } 887618c0aeSCollin L. Walling 897618c0aeSCollin L. Walling sccb->data[data_len++] = *p; 907618c0aeSCollin L. Walling p++; 917618c0aeSCollin L. Walling } 927618c0aeSCollin L. Walling 937618c0aeSCollin L. Walling sccb->h.length = sizeof(WriteEventData) + data_len; 949a22473cSFarhan Ali sccb->h.function_code = SCLP_FC_NORMAL_WRITE; 957618c0aeSCollin L. Walling sccb->ebh.length = sizeof(EventBufferHeader) + data_len; 969a22473cSFarhan Ali sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; 979a22473cSFarhan Ali sccb->ebh.flags = 0; 989a22473cSFarhan Ali 999a22473cSFarhan Ali sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); 1003639f93fSThomas Huth 1013639f93fSThomas Huth return len; 1023639f93fSThomas Huth } 1033639f93fSThomas Huth 1043639f93fSThomas Huth void sclp_print(const char *str) 1053639f93fSThomas Huth { 106fc0e2087SCollin L. Walling write(1, str, strlen(str)); 1079a22473cSFarhan Ali } 1089a22473cSFarhan Ali 1099a22473cSFarhan Ali void sclp_get_loadparm_ascii(char *loadparm) 1109a22473cSFarhan Ali { 1119a22473cSFarhan Ali 1129a22473cSFarhan Ali ReadInfo *sccb = (void *)_sccb; 1139a22473cSFarhan Ali 1149a22473cSFarhan Ali memset((char *)_sccb, 0, sizeof(ReadInfo)); 115*f24ec9feSClaudio Imbrenda sccb->h.length = SCCB_SIZE; 1169a22473cSFarhan Ali if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) { 117a0e11b61SCollin Walling ebcdic_to_ascii((char *) sccb->loadparm, loadparm, LOADPARM_LEN); 1189a22473cSFarhan Ali } 1199a22473cSFarhan Ali } 120ff5dbf1bSCollin L. Walling 121ff5dbf1bSCollin L. Walling int sclp_read(char *str, size_t count) 122ff5dbf1bSCollin L. Walling { 123ff5dbf1bSCollin L. Walling ReadEventData *sccb = (void *)_sccb; 124ff5dbf1bSCollin L. Walling char *buf = (char *)(&sccb->ebh) + 7; 125ff5dbf1bSCollin L. Walling 126ff5dbf1bSCollin L. Walling /* If count exceeds max buffer size, then restrict it to the max size */ 127ff5dbf1bSCollin L. Walling if (count > SCCB_SIZE - 8) { 128ff5dbf1bSCollin L. Walling count = SCCB_SIZE - 8; 129ff5dbf1bSCollin L. Walling } 130ff5dbf1bSCollin L. Walling 131ff5dbf1bSCollin L. Walling sccb->h.length = SCCB_SIZE; 132ff5dbf1bSCollin L. Walling sccb->h.function_code = SCLP_UNCONDITIONAL_READ; 133ff5dbf1bSCollin L. Walling 134ff5dbf1bSCollin L. Walling sclp_service_call(SCLP_CMD_READ_EVENT_DATA, sccb); 135ff5dbf1bSCollin L. Walling memcpy(str, buf, count); 136ff5dbf1bSCollin L. Walling 137ff5dbf1bSCollin L. Walling return sccb->ebh.length - 7; 138ff5dbf1bSCollin L. Walling } 139