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