]>
Commit | Line | Data |
---|---|---|
0369b2eb AG |
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 | ||
90806fec | 11 | #include "libc.h" |
0369b2eb AG |
12 | #include "s390-ccw.h" |
13 | #include "sclp.h" | |
14 | ||
3639f93f TH |
15 | long write(int fd, const void *str, size_t len); |
16 | ||
0369b2eb AG |
17 | static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096))); |
18 | ||
af3bb73a TH |
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 | ||
0369b2eb AG |
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"); | |
bdc7fe36 | 41 | consume_sclp_int(); |
0369b2eb AG |
42 | if (cc == 3) |
43 | return -EIO; | |
44 | if (cc == 2) | |
45 | return -EBUSY; | |
46 | return 0; | |
47 | } | |
48 | ||
dbf2091a | 49 | void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask) |
0369b2eb | 50 | { |
abd696e4 | 51 | WriteEventMask *sccb = (void *)_sccb; |
0369b2eb AG |
52 | |
53 | sccb->h.length = sizeof(WriteEventMask); | |
54 | sccb->mask_length = sizeof(unsigned int); | |
dbf2091a CW |
55 | sccb->cp_receive_mask = receive_mask; |
56 | sccb->cp_send_mask = send_mask; | |
0369b2eb AG |
57 | |
58 | sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb); | |
59 | } | |
60 | ||
61 | void sclp_setup(void) | |
62 | { | |
dbf2091a | 63 | sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII); |
0369b2eb AG |
64 | } |
65 | ||
3639f93f | 66 | long write(int fd, const void *str, size_t len) |
0369b2eb | 67 | { |
abd696e4 | 68 | WriteEventData *sccb = (void *)_sccb; |
7618c0ae CW |
69 | const char *p = str; |
70 | size_t data_len = 0; | |
71 | size_t i; | |
0369b2eb | 72 | |
3639f93f TH |
73 | if (fd != 1 && fd != 2) { |
74 | return -EIO; | |
75 | } | |
76 | ||
7618c0ae CW |
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; | |
0369b2eb | 94 | sccb->h.function_code = SCLP_FC_NORMAL_WRITE; |
7618c0ae | 95 | sccb->ebh.length = sizeof(EventBufferHeader) + data_len; |
0369b2eb AG |
96 | sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; |
97 | sccb->ebh.flags = 0; | |
0369b2eb AG |
98 | |
99 | sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); | |
3639f93f TH |
100 | |
101 | return len; | |
102 | } | |
103 | ||
104 | void sclp_print(const char *str) | |
105 | { | |
fc0e2087 | 106 | write(1, str, strlen(str)); |
0369b2eb | 107 | } |
9a22473c FA |
108 | |
109 | void 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 = sizeof(ReadInfo); | |
116 | if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) { | |
a0e11b61 | 117 | ebcdic_to_ascii((char *) sccb->loadparm, loadparm, LOADPARM_LEN); |
9a22473c FA |
118 | } |
119 | } | |
ff5dbf1b CW |
120 | |
121 | int 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 | } |