Install sccs headers and copyright notices.
[unix-history] / usr / src / usr.bin / tn3270 / ctlr / api.c
CommitLineData
992de934
GM
1/*
2 * Copyright (c) 1984-1987 by the Regents of the
3 * University of California and by Gregory Glenn Minshall.
4 *
5 * Permission to use, copy, modify, and distribute these
6 * programs and their documentation for any purpose and
7 * without fee is hereby granted, provided that this
8 * copyright and permission appear on all copies and
9 * supporting documentation, the name of the Regents of
10 * the University of California not be used in advertising
11 * or publicity pertaining to distribution of the programs
12 * without specific prior permission, and notice be given in
13 * supporting documentation that copying and distribution is
14 * by permission of the Regents of the University of California
15 * and by Gregory Glenn Minshall. Neither the Regents of the
16 * University of California nor Gregory Glenn Minshall make
17 * representations about the suitability of this software
18 * for any purpose. It is provided "as is" without
19 * express or implied warranty.
20 */
21
22#ifndef lint
23static char sccsid[] = "@(#)api.c 1.15 (Berkeley) %G%";
24#endif /* not lint */
25
abd201e9
GM
26/*
27 * This file implements the API used in the PC version.
28 */
29
30#include <stdio.h>
abd201e9 31
abd201e9 32#include "api.h"
d4967272 33#include "../general/general.h"
abd201e9 34
4718d085 35#include "../api/disp_asc.h"
6376f1f2 36
4718d085
GM
37#include "screen.h"
38#include "oia.h"
92f7501a 39
d4967272 40#include "../general/globals.h"
65c9fa1f 41
92f7501a
GM
42/*
43 * General utility routines.
44 */
45
46#if defined(MSDOS)
ffff8f6a
GM
47
48#if defined(LINT_ARGS)
49static void movetous(char *, int, int, int);
50static void movetothem(int, int, char *, int);
51#endif /* defined(LINT_ARGS) */
92f7501a 52
ec5b8360
GM
53#define access_api(foo,length,copyin) (foo)
54#define unaccess_api(foo,goo,length,copyout)
6376f1f2 55
92f7501a
GM
56static void
57movetous(parms, es, di, length)
58char *parms;
ffff8f6a 59int es, di, length;
92f7501a 60{
ffff8f6a 61 char far *farparms = parms;
92f7501a 62
ffff8f6a 63 movedata(es, di, (int) FP_SEG(farparms), (int) FP_OFF(farparms), length);
92f7501a
GM
64}
65
66static void
ffff8f6a
GM
67movetothem(es, di, parms, length)
68int es, di;
69char *parms;
70int length;
92f7501a 71{
ffff8f6a 72 char far *farparms = parms;
92f7501a 73
ffff8f6a 74 movedata((int) FP_SEG(farparms), (int) FP_OFF(farparms), es, di, length);
92f7501a
GM
75}
76#endif /* defined(MSDOS) */
77
6376f1f2 78#if defined(unix)
4604a66c 79extern char *access_api(), *unaccess_api();
6376f1f2 80#endif /* defined(unix) */
92f7501a 81
4604a66c 82
abd201e9
GM
83/*
84 * Supervisor Services.
85 */
86
87static void
92f7501a 88name_resolution(regs, sregs)
abd201e9
GM
89union REGS *regs;
90struct SREGS *sregs;
91{
86057566 92 NameResolveParms parms;
e75c75e7 93
86057566 94 movetous((char *) &parms, sregs->es, regs->x.di, sizeof parms);
e75c75e7
GM
95
96 regs->h.cl = 0;
92f7501a 97 if (memcmp((char *)&parms, NAME_SESSMGR, sizeof parms.gate_name) == 0) {
e75c75e7 98 regs->x.dx = GATE_SESSMGR;
92f7501a
GM
99 } else if (memcmp((char *)&parms, NAME_KEYBOARD,
100 sizeof parms.gate_name) == 0) {
e75c75e7 101 regs->x.dx = GATE_KEYBOARD;
92f7501a 102 } else if (memcmp((char *)&parms, NAME_COPY, sizeof parms.gate_name) == 0) {
e75c75e7 103 regs->x.dx = GATE_COPY;
92f7501a 104 } else if (memcmp((char *)&parms, NAME_OIAM, sizeof parms.gate_name) == 0) {
e75c75e7
GM
105 regs->x.dx = GATE_OIAM;
106 } else {
107 regs->h.cl = 0x2e; /* Name not found */
108 }
109 regs->h.ch = 0x12;
110 regs->h.bh = 7;
abd201e9
GM
111}
112
113/*
114 * Session Information Services.
115 */
116
117static void
118query_session_id(regs, sregs)
119union REGS *regs;
120struct SREGS *sregs;
121{
86057566 122 QuerySessionIdParms parms;
e75c75e7 123
86057566 124 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
e75c75e7 125
ffff8f6a
GM
126 if ((parms.rc != 0) || (parms.function_id != 0)) {
127 parms.rc = 0x0c;
128 } else if (parms.option_code != 0x01) {
129 parms.rc = 0x0d; /* Invalid option code */
86057566 130 } else if (parms.data_code != 0x45) {
ffff8f6a 131 parms.rc = 0x0b;
e75c75e7 132 } else {
65c9fa1f 133 NameArray list;
86057566
GM
134 NameArrayElement element;
135
136 movetous((char *)&list, FP_SEG(parms.name_array),
92f7501a 137 FP_OFF(parms.name_array), sizeof list);
65c9fa1f 138 if ((list.length < 14) || (list.length > 170)) {
86057566 139 parms.rc = 0x12;
e75c75e7 140 } else {
86057566
GM
141 list.number_matching_session = 1;
142 list.name_array_element.short_name = parms.data_code;
143 list.name_array_element.type = TYPE_DFT;
144 list.name_array_element.session_id = 23;
145 memcpy(list.name_array_element.long_name, "ONLYSESS",
146 sizeof list.name_array_element.long_name);
147 movetothem(FP_SEG(parms.name_array),
92f7501a 148 FP_OFF(parms.name_array), (char *)&list, sizeof list);
86057566 149 parms.rc = 0;
e75c75e7
GM
150 }
151 }
ffff8f6a 152 parms.function_id = 0x6b;
86057566 153 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
abd201e9
GM
154}
155
156static void
157query_session_parameters(regs, sregs)
158union REGS *regs;
159struct SREGS *sregs;
160{
86057566
GM
161 QuerySessionParametersParms parms;
162
163 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
164
65c9fa1f 165 if ((parms.rc !=0) || (parms.function_id != 0)) {
ffff8f6a
GM
166 parms.rc = 0x0c;
167 } else if (parms.session_id != 23) {
168 parms.rc = 0x02;
86057566 169 } else {
ffff8f6a 170 parms.rc = 0;
86057566
GM
171 parms.session_type = TYPE_DFT;
172 parms.session_characteristics = 0; /* Neither EAB nor PSS */
173 parms.rows = MaxNumberLines;
174 parms.columns = MaxNumberColumns;
175 parms.presentation_space = 0;
176 }
ffff8f6a 177 parms.function_id = 0x6b;
65c9fa1f 178 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
abd201e9
GM
179}
180
181static void
182query_session_cursor(regs, sregs)
183union REGS *regs;
184struct SREGS *sregs;
185{
86057566
GM
186 QuerySessionCursorParms parms;
187
188 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
189
190 if ((parms.rc != 0) || (parms.function_id != 0)) {
191 parms.rc = 0x0c;
192 } else if (parms.session_id != 23) {
193 parms.rc = 0x02;
194 } else {
195 parms.rc = 0;
86057566
GM
196 parms.cursor_type = CURSOR_BLINKING; /* XXX what is inhibited? */
197 parms.row_address = ScreenLine(CursorAddress);
198 parms.column_address = ScreenLineOffset(CursorAddress);
199 }
200
ffff8f6a
GM
201 parms.function_id = 0x6b;
202 movetothem(sregs->es, regs->x.di, (char *) &parms, sizeof parms);
abd201e9
GM
203}
204
205/*
206 * Keyboard Services.
207 */
208
209
210static void
211connect_to_keyboard(regs, sregs)
212union REGS *regs;
213struct SREGS *sregs;
214{
86057566
GM
215 ConnectToKeyboardParms parms;
216
d4967272 217 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
86057566
GM
218
219 if ((parms.rc != 0) || (parms.function_id != 0)) {
220 parms.rc = 0x0c;
221 } else if (parms.session_id != 23) {
222 parms.rc = 0x02;
223 } else if (parms.intercept_options != 0) {
224 parms.rc = 0x01;
225 } else {
226 parms.rc = 0;
227 parms.first_connection_identifier = 0;
228 }
229 parms.function_id = 0x62;
230
231 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
abd201e9
GM
232}
233
234static void
86057566 235disconnect_from_keyboard(regs, sregs)
abd201e9
GM
236union REGS *regs;
237struct SREGS *sregs;
238{
86057566
GM
239 DisconnectFromKeyboardParms parms;
240
241 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
242
243 if ((parms.rc != 0) || (parms.function_id != 0)) {
244 parms.rc = 0x0c;
245 } else if (parms.session_id != 23) {
246 parms.rc = 0x02;
247 } else if (parms.connectors_task_id != 0) {
248 parms.rc = 04; /* XXX */
249 } else {
250 parms.rc = 0;
251 }
252 parms.function_id = 0x62;
253
254 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
abd201e9
GM
255}
256
257static void
258write_keystroke(regs, sregs)
259union REGS *regs;
260struct SREGS *sregs;
261{
cbdd0b03
GM
262 WriteKeystrokeParms parms;
263
264 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
265
266 if ((parms.rc != 0) || (parms.function_id != 0)) {
267 parms.rc = 0x0c;
268 } else if (parms.session_id != 23) {
269 parms.rc = 0x02;
270 } else if (parms.connectors_task_id != 0) {
271 parms.rc = 0x04;
272 } else {
273 parms.number_of_keys_sent = 0;
274 parms.rc = 0;
275 if (parms.options == OPTION_SINGLE_KEYSTROKE) {
276 KeystrokeEntry *entry = &parms.keystroke_specifier.keystroke_entry;
277
278 if (AcceptKeystroke(entry->scancode, entry->shift_state) == 0) {
279 parms.rc = 0x10; /* XXX needs 0x12 too! */
280 }
281 parms.number_of_keys_sent++;
282 } else if (parms.options == OPTION_MULTIPLE_KEYSTROKES) {
283 KeystrokeList
284 list,
285 far *atlist = parms.keystroke_specifier.keystroke_list;
286 KeystrokeEntry
287 entry[10], /* 10 at a time */
288 *ourentry,
289 far *theirentry;
290 int
291 todo;
292
293 movetous((char *)&list, FP_SEG(atlist),
294 FP_OFF(atlist), sizeof *atlist);
295 todo = list.length/2;
296 ourentry = entry+(highestof(entry)+1);
297
298 while (todo) {
299 if (ourentry > &entry[highestof(entry)]) {
300 int thistime;
301
302 thistime = todo;
303 if (thistime > numberof(entry)) {
304 thistime = numberof(entry);
305 }
306 movetous((char *)entry, FP_SEG(theirentry),
307 FP_OFF(theirentry), thistime*sizeof *theirentry);
308 theirentry += thistime;
309 ourentry = entry;
310 }
311 if (AcceptKeystroke(ourentry->scancode,
312 ourentry->shift_state) == 0) {
313 parms.rc = 0x10; /* XXX needs 0x12 too! */
314 break;
315 }
316 parms.number_of_keys_sent++;
317 ourentry++;
318 todo--;
319 }
320 } else {
321 parms.rc = 0x01;
322 }
323 }
324 parms.function_id = 0x62;
325
326 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
86057566
GM
327/* XXX */
328}
329
330
331static void
332disable_input(regs, sregs)
333union REGS *regs;
334struct SREGS *sregs;
335{
336 DisableInputParms parms;
337
338 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
339
340 if ((parms.rc != 0) || (parms.function_id != 0)) {
341 parms.rc = 0x0c;
342 } else if (parms.session_id != 23) {
343 parms.rc = 0x02;
344 } else if (parms.connectors_task_id != 0) {
345 parms.rc = 0x04;
346 } else {
ffff8f6a 347 SetOiaApiInhibit(&OperatorInformationArea);
86057566
GM
348 parms.rc = 0;
349 }
350 parms.function_id = 0x62;
351
352 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
abd201e9
GM
353}
354
355static void
356enable_input(regs, sregs)
357union REGS *regs;
358struct SREGS *sregs;
359{
86057566
GM
360 EnableInputParms parms;
361
362 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
363
364 if ((parms.rc != 0) || (parms.function_id != 0)) {
365 parms.rc = 0x0c;
366 } else if (parms.session_id != 23) {
367 parms.rc = 0x02;
368 } else if (parms.connectors_task_id != 0) {
369 parms.rc = 0x04;
370 } else {
ffff8f6a 371 ResetOiaApiInhibit(&OperatorInformationArea);
86057566
GM
372 parms.rc = 0;
373 }
374 parms.function_id = 0x62;
375
376 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
abd201e9
GM
377}
378
379/*
380 * Copy Services.
381 */
382
ec5b8360
GM
383static
384copy_subroutine(target, source, parms, what_is_user, length)
6376f1f2
GM
385BufferDescriptor *target, *source;
386CopyStringParms *parms;
387int what_is_user;
388#define USER_IS_TARGET 0
389#define USER_IS_SOURCE 1
390{
391#define TARGET_NO_EAB 1
392#define SOURCE_NO_EAB 2
393#define TARGET_PC 4
394#define SOURCE_PC 8
395#define NO_FIELD_ATTRIBUTES 16
396 int needtodo = 0;
6376f1f2
GM
397 int access_length;
398 char far *input;
399 char far *output;
400 char far *access_pointer;
401
402 if ((target->characteristics^source->characteristics)
403 &CHARACTERISTIC_EAB) {
404 if (target->characteristics&CHARACTERISTIC_EAB) {
405 needtodo |= TARGET_NO_EAB; /* Need to bump for EAB in target */
406 } else {
407 needtodo |= SOURCE_NO_EAB; /* Need to bump for EAB in source */
408 }
409 }
410 if (target->session_type != source->session_type) {
411 if (target->session_type == TYPE_PC) {
412 needtodo |= TARGET_PC; /* scan codes to PC */
413 } else {
414 needtodo |= SOURCE_PC; /* PC to scan codes */
415 }
416 }
417 if ((parms->copy_mode&COPY_MODE_FIELD_ATTRIBUTES) == 0) {
418 needtodo |= NO_FIELD_ATTRIBUTES;
419 }
ec5b8360 420 access_length = length;
6376f1f2
GM
421 if (what_is_user == USER_IS_TARGET) {
422 if (target->characteristics&CHARACTERISTIC_EAB) {
423 access_length *= 2;
424 }
425 input = (char far *) &Host[source->begin];
426 access_pointer = target->buffer;
ec5b8360 427 output = access_api(target->buffer, access_length, 0);
6376f1f2
GM
428 } else {
429 if (source->characteristics&CHARACTERISTIC_EAB) {
430 access_length *= 2;
431 }
432 access_pointer = source->buffer;
ec5b8360 433 input = access_api(source->buffer, access_length, 1);
6376f1f2
GM
434 output = (char far *) &Host[target->begin];
435 }
436 while (length--) {
437 if (needtodo&TARGET_PC) {
438 *output++ = disp_asc[*input++];
439 } else if (needtodo&SOURCE_PC) {
440 *output++ = asc_disp[*input++];
441 } else {
442 *output++ = *input++;
443 }
444 if (needtodo&TARGET_NO_EAB) {
445 *input++;
446 } else if (needtodo&SOURCE_NO_EAB) {
447 *output++ = 0; /* Should figure out good EAB? */
448 }
449 }
450 if (what_is_user == USER_IS_TARGET) {
ec5b8360 451 unaccess_api(target->buffer, access_pointer, access_length, 1);
6376f1f2 452 } else {
ec5b8360 453 unaccess_api(source->buffer, access_pointer, access_length, 0);
6376f1f2
GM
454 }
455}
456
457
abd201e9 458static void
86057566 459copy_string(regs, sregs)
abd201e9
GM
460union REGS *regs;
461struct SREGS *sregs;
462{
86057566 463 CopyStringParms parms;
6376f1f2
GM
464 BufferDescriptor *target = &parms.target, *source = &parms.source;
465 int length;
86057566
GM
466
467 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
abd201e9 468
ec5b8360 469 length = 1+parms.source_end-source->begin;
86057566
GM
470 if ((parms.rc != 0) || (parms.function_id !=0)) {
471 parms.rc = 0x0c;
6376f1f2
GM
472 } else if (target->session_id == 0) { /* Target is buffer */
473 if (source->session_id != 23) { /* A no-no */
474 parms.rc = 0x2;
475 } else {
ec5b8360
GM
476 if ((source->begin < 0) || (source->begin > highestof(Host))) {
477 parms.rc = 0x06; /* invalid source definition */
478 } else {
479 if ((source->begin+length) > highestof(Host)) {
480 length = highestof(Host)-source->begin;
481 parms.rc = 0x0f; /* Truncate */
482 }
483 if ((source->characteristics == target->characteristics) &&
6376f1f2 484 (source->session_type == target->session_type)) {
ec5b8360
GM
485 if (source->characteristics&CHARACTERISTIC_EAB) {
486 length *= 2;
487 }
488 movetothem( (int) FP_SEG(target->buffer),
489 (int) FP_OFF(target->buffer),
490 (char *)&Host[source->begin], length);
491 } else {
492 copy_subroutine(target, source, &parms,
493 USER_IS_TARGET, length);
6376f1f2 494 }
6376f1f2
GM
495 }
496 }
497 } else if (source->session_id != 0) {
498 parms.rc = 0xd;
499 } else {
ec5b8360
GM
500 if ((target->begin < 0) || (source->begin > highestof(Host))) {
501 parms.rc = 0x07; /* invalid source definition */
6376f1f2 502 } else {
ec5b8360
GM
503 if ((source->begin+length) > highestof(Host)) {
504 length = highestof(Host)-source->begin;
505 parms.rc = 0x0f; /* Truncate */
506 }
507 if ((source->characteristics == target->characteristics) &&
508 (source->session_type == target->session_type)) {
509 if (source->characteristics&CHARACTERISTIC_EAB) {
510 length *= 2;
511 }
512 movetous((char *)&Host[target->begin],
513 (int) FP_SEG(source->buffer),
514 (int) FP_OFF(source->buffer), length);
515 } else {
516 copy_subroutine(target, source, &parms, USER_IS_SOURCE, length);
517 }
6376f1f2 518 }
86057566 519 }
d4967272 520 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
86057566 521}
abd201e9
GM
522/*
523 * Operator Information Area Services.
524 */
525
526static void
527read_oia_group(regs, sregs)
528union REGS *regs;
529struct SREGS *sregs;
530{
86057566
GM
531 ReadOiaGroupParms parms;
532
533 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
534
535 if ((parms.rc != 0) || (parms.function_id != 0)) {
536 parms.rc = 0x0c;
537 } else if (parms.session_id != 23) {
538 parms.rc = 0x02;
539 } else {
540 int group = parms.oia_group_number;
92f7501a
GM
541 char *from;
542 int size;
86057566 543
ffff8f6a
GM
544 if ((group != API_OIA_ALL_GROUPS) &&
545 ((group > API_OIA_LAST_LEGAL_GROUP) || (group < 0))) {
92f7501a
GM
546 } else {
547 if (group == API_OIA_ALL_GROUPS) {
548 size = API_OIA_BYTES_ALL_GROUPS;
549 from = (char *)&OperatorInformationArea;
550 } else if (group == API_OIA_INPUT_INHIBITED) {
551 size = sizeof OperatorInformationArea.input_inhibited;
552 from = (char *)&OperatorInformationArea.input_inhibited[0];
553 } else {
554 size = 1;
555 from = ((char *)&OperatorInformationArea)+group;
556 }
557 movetothem(FP_SEG(parms.oia_buffer), FP_OFF(parms.oia_buffer),
558 from, size);
65c9fa1f 559 }
86057566 560 }
65c9fa1f 561 parms.function_id = 0x6d;
86057566 562 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
abd201e9
GM
563}
564\f
565static void
566unknown_op(regs, sregs)
567union REGS *regs;
568struct SREGS *sregs;
569{
570 regs->h.ch = 0x12;
571 regs->h.cl = 0x05;
572}
573
574
575handle_api(regs, sregs)
576union REGS *regs;
577struct SREGS *sregs;
578{
579 if (regs->h.ah == NAME_RESOLUTION) {
580 name_resolution(regs, sregs);
bada4bfa
GM
581#if defined(unix)
582 } else if (regs->h.ah == PS_OR_OIA_MODIFIED) {
583 while ((oia_modified == 0) && (ps_modified == 0)) {
584 (void) Scheduler(1);
585 }
586 oia_modified = ps_modified = 0;
587#endif /* defined(unix) */
65c9fa1f
GM
588 } else if (regs->h.ah != 0x09) {
589 regs->h.ch = 0x12;
590 regs->h.cl = 0x0f; /* XXX Invalid environmental access */
591 } else if (regs->x.bx != 0x8020) {
592 regs->h.ch = 0x12;
593 regs->h.cl = 0x08; /* XXX Invalid wait specified */
594 } else if (regs->h.ch != 0) {
ffff8f6a 595 regs->x.cx = 0x1206; /* XXX Invalid priority */
abd201e9
GM
596 } else {
597 switch (regs->x.dx) {
598 case GATE_SESSMGR:
599 switch (regs->h.al) {
600 case QUERY_SESSION_ID:
65c9fa1f 601 if (regs->h.cl != 0) {
ffff8f6a 602 regs->x.cx = 0x1206;
65c9fa1f 603 } else {
ffff8f6a 604 regs->x.cx = 0x1200;
65c9fa1f
GM
605 query_session_id(regs, sregs);
606 }
abd201e9 607 break;
ffff8f6a 608 case QUERY_SESSION_PARAMETERS:
65c9fa1f 609 if (regs->h.cl != 0) {
ffff8f6a 610 regs->x.cx = 0x1206;
65c9fa1f 611 } else {
ffff8f6a 612 regs->x.cx = 0x1200;
92f7501a 613 query_session_parameters(regs, sregs);
65c9fa1f 614 }
abd201e9
GM
615 break;
616 case QUERY_SESSION_CURSOR:
65c9fa1f 617 if (regs->h.cl != 0xff) {
ffff8f6a 618 regs->x.cx = 0x1206;
65c9fa1f 619 } else {
ffff8f6a 620 regs->x.cx = 0x1200;
65c9fa1f
GM
621 query_session_cursor(regs, sregs);
622 }
abd201e9
GM
623 break;
624 default:
625 unknown_op(regs, sregs);
626 break;
627 }
628 break;
629 case GATE_KEYBOARD:
65c9fa1f 630 if (regs->h.cl != 00) {
ffff8f6a 631 regs->x.cx = 0x1206;
65c9fa1f 632 } else {
ffff8f6a 633 regs->x.cx = 0x1200;
65c9fa1f
GM
634 switch (regs->h.al) {
635 case CONNECT_TO_KEYBOARD:
636 connect_to_keyboard(regs, sregs);
637 break;
638 case DISABLE_INPUT:
639 disable_input(regs, sregs);
640 break;
641 case WRITE_KEYSTROKE:
642 write_keystroke(regs, sregs);
643 break;
644 case ENABLE_INPUT:
645 enable_input(regs, sregs);
646 break;
647 case DISCONNECT_FROM_KEYBOARD:
648 disconnect_from_keyboard(regs, sregs);
649 break;
650 default:
651 unknown_op(regs, sregs);
652 break;
653 }
abd201e9
GM
654 }
655 break;
656 case GATE_COPY:
65c9fa1f 657 if (regs->h.cl != 0xff) {
ffff8f6a 658 regs->x.cx = 0x1206;
65c9fa1f 659 } else {
ffff8f6a 660 regs->x.cx = 0x1200;
65c9fa1f
GM
661 switch (regs->h.al) {
662 case COPY_STRING:
663 copy_string(regs, sregs);
664 break;
665 default:
666 unknown_op(regs, sregs);
667 break;
668 }
abd201e9
GM
669 }
670 break;
671 case GATE_OIAM:
65c9fa1f 672 if (regs->h.cl != 0xff) {
ffff8f6a 673 regs->x.cx = 0x1206;
65c9fa1f 674 } else {
ffff8f6a 675 regs->x.cx = 0x1200;
65c9fa1f
GM
676 switch (regs->h.al) {
677 case READ_OIA_GROUP:
678 read_oia_group(regs, sregs);
679 break;
680 default:
681 unknown_op(regs, sregs);
682 break;
683 }
abd201e9
GM
684 }
685 break;
686 default:
65c9fa1f
GM
687 regs->h.ch = 0x12;
688 regs->h.cl = 0x34; /* Invalid GATE entry */
abd201e9
GM
689 break;
690 }
691 }
692}