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