0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kmod.h>
0012 #include <linux/types.h>
0013 #include <linux/err.h>
0014 #include <linux/string.h>
0015 #include <linux/spinlock.h>
0016 #include <linux/ctype.h>
0017 #include <linux/uaccess.h>
0018
0019 #include "sclp.h"
0020 #include "sclp_rw.h"
0021
0022
0023
0024
0025
0026
0027 #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
0028
0029
0030 static struct sclp_register sclp_rw_event = {
0031 .send_mask = EVTYP_MSG_MASK,
0032 };
0033
0034
0035
0036
0037
0038
0039
0040 struct sclp_buffer *
0041 sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
0042 {
0043 struct sclp_buffer *buffer;
0044 struct sccb_header *sccb;
0045
0046 sccb = (struct sccb_header *) page;
0047
0048
0049
0050
0051 buffer = ((struct sclp_buffer *) ((addr_t) sccb + PAGE_SIZE)) - 1;
0052 buffer->sccb = sccb;
0053 buffer->retry_count = 0;
0054 buffer->messages = 0;
0055 buffer->char_sum = 0;
0056 buffer->current_line = NULL;
0057 buffer->current_length = 0;
0058 buffer->columns = columns;
0059 buffer->htab = htab;
0060
0061
0062 memset(sccb, 0, sizeof(struct sccb_header));
0063 sccb->length = sizeof(struct sccb_header);
0064
0065 return buffer;
0066 }
0067
0068
0069
0070
0071
0072 void *
0073 sclp_unmake_buffer(struct sclp_buffer *buffer)
0074 {
0075 return buffer->sccb;
0076 }
0077
0078
0079
0080
0081
0082 static int
0083 sclp_initialize_mto(struct sclp_buffer *buffer, int max_len)
0084 {
0085 struct sccb_header *sccb;
0086 struct msg_buf *msg;
0087 struct mdb *mdb;
0088 struct go *go;
0089 struct mto *mto;
0090 int msg_size;
0091
0092
0093 msg_size = sizeof(struct msg_buf) + max_len;
0094
0095
0096 sccb = buffer->sccb;
0097 if ((MAX_SCCB_ROOM - sccb->length) < msg_size)
0098 return -ENOMEM;
0099
0100 msg = (struct msg_buf *)((addr_t) sccb + sccb->length);
0101 memset(msg, 0, sizeof(struct msg_buf));
0102 msg->header.length = sizeof(struct msg_buf);
0103 msg->header.type = EVTYP_MSG;
0104
0105 mdb = &msg->mdb;
0106 mdb->header.length = sizeof(struct mdb);
0107 mdb->header.type = 1;
0108 mdb->header.tag = 0xD4C4C240;
0109 mdb->header.revision_code = 1;
0110
0111 go = &mdb->go;
0112 go->length = sizeof(struct go);
0113 go->type = 1;
0114
0115 mto = &mdb->mto;
0116 mto->length = sizeof(struct mto);
0117 mto->type = 4;
0118 mto->line_type_flags = LNTPFLGS_ENDTEXT;
0119
0120
0121 buffer->current_msg = msg;
0122 buffer->current_line = (char *) (mto + 1);
0123 buffer->current_length = 0;
0124
0125 return 0;
0126 }
0127
0128
0129
0130
0131
0132 static void
0133 sclp_finalize_mto(struct sclp_buffer *buffer)
0134 {
0135 struct sccb_header *sccb;
0136 struct msg_buf *msg;
0137
0138
0139
0140
0141
0142 sccb = buffer->sccb;
0143 msg = buffer->current_msg;
0144 msg->header.length += buffer->current_length;
0145 msg->mdb.header.length += buffer->current_length;
0146 msg->mdb.mto.length += buffer->current_length;
0147 sccb->length += msg->header.length;
0148
0149
0150
0151
0152
0153
0154 buffer->messages++;
0155 buffer->char_sum += buffer->current_length;
0156
0157 buffer->current_line = NULL;
0158 buffer->current_length = 0;
0159 buffer->current_msg = NULL;
0160 }
0161
0162
0163
0164
0165
0166
0167
0168
0169 int
0170 sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
0171 {
0172 int spaces, i_msg;
0173 int rc;
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198 for (i_msg = 0; i_msg < count; i_msg++) {
0199 switch (msg[i_msg]) {
0200 case '\n':
0201
0202 if (buffer->current_line == NULL) {
0203 rc = sclp_initialize_mto(buffer, 0);
0204 if (rc)
0205 return i_msg;
0206 }
0207 sclp_finalize_mto(buffer);
0208 break;
0209 case '\a':
0210
0211 if (buffer->current_line == NULL) {
0212 rc = sclp_initialize_mto(buffer,
0213 buffer->columns);
0214 if (rc)
0215 return i_msg;
0216 }
0217 buffer->current_msg->mdb.go.general_msg_flags |=
0218 GNRLMSGFLGS_SNDALRM;
0219 break;
0220 case '\t':
0221
0222 if (buffer->current_line == NULL) {
0223 rc = sclp_initialize_mto(buffer,
0224 buffer->columns);
0225 if (rc)
0226 return i_msg;
0227 }
0228
0229 do {
0230 if (buffer->current_length >= buffer->columns)
0231 break;
0232
0233 *buffer->current_line++ = 0x40;
0234 buffer->current_length++;
0235 } while (buffer->current_length % buffer->htab);
0236 break;
0237 case '\f':
0238 case '\v':
0239
0240
0241 if (buffer->current_line != NULL) {
0242 spaces = buffer->current_length;
0243 sclp_finalize_mto(buffer);
0244 rc = sclp_initialize_mto(buffer,
0245 buffer->columns);
0246 if (rc)
0247 return i_msg;
0248 memset(buffer->current_line, 0x40, spaces);
0249 buffer->current_line += spaces;
0250 buffer->current_length = spaces;
0251 } else {
0252
0253 rc = sclp_initialize_mto(buffer,
0254 buffer->columns);
0255 if (rc)
0256 return i_msg;
0257 sclp_finalize_mto(buffer);
0258 }
0259 break;
0260 case '\b':
0261
0262
0263
0264 if (buffer->current_line != NULL &&
0265 buffer->current_length > 0) {
0266 buffer->current_length--;
0267 buffer->current_line--;
0268 }
0269 break;
0270 case 0x00:
0271
0272 if (buffer->current_line != NULL)
0273 sclp_finalize_mto(buffer);
0274
0275 i_msg = count - 1;
0276 break;
0277 default:
0278
0279 if (!isprint(msg[i_msg]))
0280 break;
0281
0282 if (buffer->current_line == NULL) {
0283 rc = sclp_initialize_mto(buffer,
0284 buffer->columns);
0285 if (rc)
0286 return i_msg;
0287 }
0288 *buffer->current_line++ = sclp_ascebc(msg[i_msg]);
0289 buffer->current_length++;
0290 break;
0291 }
0292
0293 if (buffer->current_line != NULL &&
0294 buffer->current_length >= buffer->columns)
0295 sclp_finalize_mto(buffer);
0296 }
0297
0298
0299 return i_msg;
0300 }
0301
0302
0303
0304
0305 int
0306 sclp_buffer_space(struct sclp_buffer *buffer)
0307 {
0308 struct sccb_header *sccb;
0309 int count;
0310
0311 sccb = buffer->sccb;
0312 count = MAX_SCCB_ROOM - sccb->length;
0313 if (buffer->current_line != NULL)
0314 count -= sizeof(struct msg_buf) + buffer->current_length;
0315 return count;
0316 }
0317
0318
0319
0320
0321 unsigned int
0322 sclp_chars_in_buffer(struct sclp_buffer *buffer)
0323 {
0324 unsigned int count;
0325
0326 count = buffer->char_sum;
0327 if (buffer->current_line != NULL)
0328 count += buffer->current_length;
0329 return count;
0330 }
0331
0332
0333
0334
0335 int
0336 sclp_rw_init(void)
0337 {
0338 static int init_done = 0;
0339 int rc;
0340
0341 if (init_done)
0342 return 0;
0343
0344 rc = sclp_register(&sclp_rw_event);
0345 if (rc == 0)
0346 init_done = 1;
0347 return rc;
0348 }
0349
0350 #define SCLP_BUFFER_MAX_RETRY 1
0351
0352
0353
0354
0355
0356 static void
0357 sclp_writedata_callback(struct sclp_req *request, void *data)
0358 {
0359 int rc;
0360 struct sclp_buffer *buffer;
0361 struct sccb_header *sccb;
0362
0363 buffer = (struct sclp_buffer *) data;
0364 sccb = buffer->sccb;
0365
0366 if (request->status == SCLP_REQ_FAILED) {
0367 if (buffer->callback != NULL)
0368 buffer->callback(buffer, -EIO);
0369 return;
0370 }
0371
0372 switch (sccb->response_code) {
0373 case 0x0020 :
0374
0375 rc = 0;
0376 break;
0377
0378 case 0x0340:
0379 if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
0380 rc = -EIO;
0381 break;
0382 }
0383
0384 if (sclp_remove_processed((struct sccb_header *) sccb) > 0) {
0385
0386 sccb->response_code = 0x0000;
0387 buffer->request.status = SCLP_REQ_FILLED;
0388 rc = sclp_add_request(request);
0389 if (rc == 0)
0390 return;
0391 } else
0392 rc = 0;
0393 break;
0394
0395 case 0x0040:
0396 case 0x05f0:
0397 if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
0398 rc = -EIO;
0399 break;
0400 }
0401
0402 sccb->response_code = 0x0000;
0403 buffer->request.status = SCLP_REQ_FILLED;
0404 rc = sclp_add_request(request);
0405 if (rc == 0)
0406 return;
0407 break;
0408 default:
0409 if (sccb->response_code == 0x71f0)
0410 rc = -ENOMEM;
0411 else
0412 rc = -EINVAL;
0413 break;
0414 }
0415 if (buffer->callback != NULL)
0416 buffer->callback(buffer, rc);
0417 }
0418
0419
0420
0421
0422
0423
0424 int
0425 sclp_emit_buffer(struct sclp_buffer *buffer,
0426 void (*callback)(struct sclp_buffer *, int))
0427 {
0428
0429 if (buffer->current_line != NULL)
0430 sclp_finalize_mto(buffer);
0431
0432
0433 if (buffer->messages == 0)
0434 return -EIO;
0435
0436 buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
0437 buffer->request.status = SCLP_REQ_FILLED;
0438 buffer->request.callback = sclp_writedata_callback;
0439 buffer->request.callback_data = buffer;
0440 buffer->request.sccb = buffer->sccb;
0441 buffer->callback = callback;
0442 return sclp_add_request(&buffer->request);
0443 }