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