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
11*9f427883SJared Rossi #include <string.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. */
sclp_service_call(unsigned int command,void * sccb)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
sclp_set_write_mask(uint32_t receive_mask,uint32_t send_mask)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
sclp_setup(void)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
write(int fd,const void * str,size_t len)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
sclp_get_loadparm_ascii(char * loadparm)1049a22473cSFarhan Ali void sclp_get_loadparm_ascii(char *loadparm)
1059a22473cSFarhan Ali {
1069a22473cSFarhan Ali
1079a22473cSFarhan Ali ReadInfo *sccb = (void *)_sccb;
1089a22473cSFarhan Ali
1099a22473cSFarhan Ali memset((char *)_sccb, 0, sizeof(ReadInfo));
110f24ec9feSClaudio Imbrenda sccb->h.length = SCCB_SIZE;
1119a22473cSFarhan Ali if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
112a0e11b61SCollin Walling ebcdic_to_ascii((char *) sccb->loadparm, loadparm, LOADPARM_LEN);
1139a22473cSFarhan Ali }
1149a22473cSFarhan Ali }
115ff5dbf1bSCollin L. Walling
sclp_read(char * str,size_t count)116ff5dbf1bSCollin L. Walling int sclp_read(char *str, size_t count)
117ff5dbf1bSCollin L. Walling {
118ff5dbf1bSCollin L. Walling ReadEventData *sccb = (void *)_sccb;
119ff5dbf1bSCollin L. Walling char *buf = (char *)(&sccb->ebh) + 7;
120ff5dbf1bSCollin L. Walling
121ff5dbf1bSCollin L. Walling /* If count exceeds max buffer size, then restrict it to the max size */
122ff5dbf1bSCollin L. Walling if (count > SCCB_SIZE - 8) {
123ff5dbf1bSCollin L. Walling count = SCCB_SIZE - 8;
124ff5dbf1bSCollin L. Walling }
125ff5dbf1bSCollin L. Walling
126ff5dbf1bSCollin L. Walling sccb->h.length = SCCB_SIZE;
127ff5dbf1bSCollin L. Walling sccb->h.function_code = SCLP_UNCONDITIONAL_READ;
128ff5dbf1bSCollin L. Walling
129ff5dbf1bSCollin L. Walling sclp_service_call(SCLP_CMD_READ_EVENT_DATA, sccb);
130ff5dbf1bSCollin L. Walling memcpy(str, buf, count);
131ff5dbf1bSCollin L. Walling
132ff5dbf1bSCollin L. Walling return sccb->ebh.length - 7;
133ff5dbf1bSCollin L. Walling }
134