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