"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "tn3270-5.2.0-glibc/tn3270/ctlr/api.c" of archive tn3270-5.2.0-glibc.tgz:


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