1
2
3
4
5
6
7
8
9
10
11#include <linux/kmod.h>
12#include <linux/types.h>
13#include <linux/err.h>
14#include <linux/string.h>
15#include <linux/spinlock.h>
16#include <linux/ctype.h>
17#include <asm/uaccess.h>
18
19#include "sclp.h"
20#include "sclp_rw.h"
21
22
23
24
25
26
27#define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
28
29
30static struct sclp_register sclp_rw_event = {
31 .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK
32};
33
34
35
36
37
38
39
40struct sclp_buffer *
41sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
42{
43 struct sclp_buffer *buffer;
44 struct write_sccb *sccb;
45
46 sccb = (struct write_sccb *) page;
47
48
49
50
51 buffer = ((struct sclp_buffer *) ((addr_t) sccb + PAGE_SIZE)) - 1;
52 buffer->sccb = sccb;
53 buffer->retry_count = 0;
54 buffer->mto_number = 0;
55 buffer->mto_char_sum = 0;
56 buffer->current_line = NULL;
57 buffer->current_length = 0;
58 buffer->columns = columns;
59 buffer->htab = htab;
60
61
62 memset(sccb, 0, sizeof(struct write_sccb));
63 sccb->header.length = sizeof(struct write_sccb);
64 sccb->msg_buf.header.length = sizeof(struct msg_buf);
65 sccb->msg_buf.header.type = EVTYP_MSG;
66 sccb->msg_buf.mdb.header.length = sizeof(struct mdb);
67 sccb->msg_buf.mdb.header.type = 1;
68 sccb->msg_buf.mdb.header.tag = 0xD4C4C240;
69 sccb->msg_buf.mdb.header.revision_code = 1;
70 sccb->msg_buf.mdb.go.length = sizeof(struct go);
71 sccb->msg_buf.mdb.go.type = 1;
72
73 return buffer;
74}
75
76
77
78
79
80void *
81sclp_unmake_buffer(struct sclp_buffer *buffer)
82{
83 return buffer->sccb;
84}
85
86
87
88
89
90static int
91sclp_initialize_mto(struct sclp_buffer *buffer, int max_len)
92{
93 struct write_sccb *sccb;
94 struct mto *mto;
95 int mto_size;
96
97
98 mto_size = sizeof(struct mto) + max_len;
99
100
101 sccb = buffer->sccb;
102 if ((MAX_SCCB_ROOM - sccb->header.length) < mto_size)
103 return -ENOMEM;
104
105
106 mto = (struct mto *)(((addr_t) sccb) + sccb->header.length);
107
108
109
110
111
112 memset(mto, 0, sizeof(struct mto));
113 mto->length = sizeof(struct mto);
114 mto->type = 4;
115 mto->line_type_flags = LNTPFLGS_ENDTEXT;
116
117
118 buffer->current_line = (char *) (mto + 1);
119 buffer->current_length = 0;
120
121 return 0;
122}
123
124
125
126
127
128static void
129sclp_finalize_mto(struct sclp_buffer *buffer)
130{
131 struct write_sccb *sccb;
132 struct mto *mto;
133 int str_len, mto_size;
134
135 str_len = buffer->current_length;
136 buffer->current_line = NULL;
137 buffer->current_length = 0;
138
139
140 mto_size = sizeof(struct mto) + str_len;
141
142
143 sccb = buffer->sccb;
144 mto = (struct mto *)(((addr_t) sccb) + sccb->header.length);
145
146
147 mto->length = mto_size;
148
149
150
151
152
153 sccb->header.length += mto_size;
154 sccb->msg_buf.header.length += mto_size;
155 sccb->msg_buf.mdb.header.length += mto_size;
156
157
158
159
160
161
162 buffer->mto_number++;
163 buffer->mto_char_sum += str_len;
164}
165
166
167
168
169
170
171
172
173int
174sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
175{
176 int spaces, i_msg;
177 int rc;
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 for (i_msg = 0; i_msg < count; i_msg++) {
203 switch (msg[i_msg]) {
204 case '\n':
205
206 if (buffer->current_line == NULL) {
207 rc = sclp_initialize_mto(buffer, 0);
208 if (rc)
209 return i_msg;
210 }
211 sclp_finalize_mto(buffer);
212 break;
213 case '\a':
214
215 buffer->sccb->msg_buf.mdb.go.general_msg_flags |=
216 GNRLMSGFLGS_SNDALRM;
217 break;
218 case '\t':
219
220 if (buffer->current_line == NULL) {
221 rc = sclp_initialize_mto(buffer,
222 buffer->columns);
223 if (rc)
224 return i_msg;
225 }
226
227 do {
228 if (buffer->current_length >= buffer->columns)
229 break;
230
231 *buffer->current_line++ = 0x40;
232 buffer->current_length++;
233 } while (buffer->current_length % buffer->htab);
234 break;
235 case '\f':
236 case '\v':
237
238
239 if (buffer->current_line != NULL) {
240 spaces = buffer->current_length;
241 sclp_finalize_mto(buffer);
242 rc = sclp_initialize_mto(buffer,
243 buffer->columns);
244 if (rc)
245 return i_msg;
246 memset(buffer->current_line, 0x40, spaces);
247 buffer->current_line += spaces;
248 buffer->current_length = spaces;
249 } else {
250
251 rc = sclp_initialize_mto(buffer,
252 buffer->columns);
253 if (rc)
254 return i_msg;
255 sclp_finalize_mto(buffer);
256 }
257 break;
258 case '\b':
259
260
261
262 if (buffer->current_line != NULL &&
263 buffer->current_length > 0) {
264 buffer->current_length--;
265 buffer->current_line--;
266 }
267 break;
268 case 0x00:
269
270 if (buffer->current_line != NULL)
271 sclp_finalize_mto(buffer);
272
273 i_msg = count - 1;
274 break;
275 default:
276
277 if (!isprint(msg[i_msg]))
278 break;
279
280 if (buffer->current_line == NULL) {
281 rc = sclp_initialize_mto(buffer,
282 buffer->columns);
283 if (rc)
284 return i_msg;
285 }
286 *buffer->current_line++ = sclp_ascebc(msg[i_msg]);
287 buffer->current_length++;
288 break;
289 }
290
291 if (buffer->current_line != NULL &&
292 buffer->current_length >= buffer->columns)
293 sclp_finalize_mto(buffer);
294 }
295
296
297 return i_msg;
298}
299
300
301
302
303int
304sclp_buffer_space(struct sclp_buffer *buffer)
305{
306 int count;
307
308 count = MAX_SCCB_ROOM - buffer->sccb->header.length;
309 if (buffer->current_line != NULL)
310 count -= sizeof(struct mto) + buffer->current_length;
311 return count;
312}
313
314
315
316
317int
318sclp_chars_in_buffer(struct sclp_buffer *buffer)
319{
320 int count;
321
322 count = buffer->mto_char_sum;
323 if (buffer->current_line != NULL)
324 count += buffer->current_length;
325 return count;
326}
327
328
329
330
331void
332sclp_set_columns(struct sclp_buffer *buffer, unsigned short columns)
333{
334 buffer->columns = columns;
335 if (buffer->current_line != NULL &&
336 buffer->current_length > buffer->columns)
337 sclp_finalize_mto(buffer);
338}
339
340void
341sclp_set_htab(struct sclp_buffer *buffer, unsigned short htab)
342{
343 buffer->htab = htab;
344}
345
346
347
348
349int
350sclp_rw_init(void)
351{
352 static int init_done = 0;
353 int rc;
354
355 if (init_done)
356 return 0;
357
358 rc = sclp_register(&sclp_rw_event);
359 if (rc == 0)
360 init_done = 1;
361 return rc;
362}
363
364#define SCLP_BUFFER_MAX_RETRY 1
365
366
367
368
369
370static void
371sclp_writedata_callback(struct sclp_req *request, void *data)
372{
373 int rc;
374 struct sclp_buffer *buffer;
375 struct write_sccb *sccb;
376
377 buffer = (struct sclp_buffer *) data;
378 sccb = buffer->sccb;
379
380 if (request->status == SCLP_REQ_FAILED) {
381 if (buffer->callback != NULL)
382 buffer->callback(buffer, -EIO);
383 return;
384 }
385
386 switch (sccb->header.response_code) {
387 case 0x0020 :
388
389 rc = 0;
390 break;
391
392 case 0x0340:
393 if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
394 rc = -EIO;
395 break;
396 }
397
398 if (sclp_remove_processed((struct sccb_header *) sccb) > 0) {
399
400 sccb->header.response_code = 0x0000;
401 buffer->request.status = SCLP_REQ_FILLED;
402 rc = sclp_add_request(request);
403 if (rc == 0)
404 return;
405 } else
406 rc = 0;
407 break;
408
409 case 0x0040:
410 case 0x05f0:
411 if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
412 rc = -EIO;
413 break;
414 }
415
416 sccb->header.response_code = 0x0000;
417 buffer->request.status = SCLP_REQ_FILLED;
418 rc = sclp_add_request(request);
419 if (rc == 0)
420 return;
421 break;
422 default:
423 if (sccb->header.response_code == 0x71f0)
424 rc = -ENOMEM;
425 else
426 rc = -EINVAL;
427 break;
428 }
429 if (buffer->callback != NULL)
430 buffer->callback(buffer, rc);
431}
432
433
434
435
436
437
438int
439sclp_emit_buffer(struct sclp_buffer *buffer,
440 void (*callback)(struct sclp_buffer *, int))
441{
442 struct write_sccb *sccb;
443
444
445 if (buffer->current_line != NULL)
446 sclp_finalize_mto(buffer);
447
448
449 if (buffer->mto_number == 0)
450 return -EIO;
451
452 sccb = buffer->sccb;
453 if (sclp_rw_event.sclp_receive_mask & EVTYP_MSG_MASK)
454
455 sccb->msg_buf.header.type = EVTYP_MSG;
456 else if (sclp_rw_event.sclp_receive_mask & EVTYP_PMSGCMD_MASK)
457
458 sccb->msg_buf.header.type = EVTYP_PMSGCMD;
459 else
460 return -ENOSYS;
461 buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
462 buffer->request.status = SCLP_REQ_FILLED;
463 buffer->request.callback = sclp_writedata_callback;
464 buffer->request.callback_data = buffer;
465 buffer->request.sccb = sccb;
466 buffer->callback = callback;
467 return sclp_add_request(&buffer->request);
468}
469