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