/************************************************************************* * * keyboard.c * * This module contains routines for managing the ICA keyboard channel. * * Copyright 1998, Microsoft. * *************************************************************************/ /* * Includes */ #include #pragma hdrstop #include NTSTATUS IcaDeviceControlKeyboard( IN PICA_CHANNEL pChannel, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) /*++ Routine Description: This is the device control routine for the ICA keyboard channel. Arguments: pChannel -- pointer to ICA_CHANNEL object Irp - Pointer to I/O request packet IrpSp - pointer to the stack location to use for this request. Return Value: NTSTATUS -- Indicates whether the request was successfully queued. --*/ { ULONG code; SD_IOCTL SdIoctl; PICA_STACK pStack; NTSTATUS Status; CLONG Method; /* * Extract the IOCTL control code and process the request. */ code = IrpSp->Parameters.DeviceIoControl.IoControlCode; TRACECHANNEL(( pChannel, TC_ICADD, TT_API1, "ICADD: IcaDeviceControlKeyboard, fc %d, ref %u (enter)\n", (code & 0x3fff) >> 2, pChannel->RefCount )); switch ( code ) { #if 0 // no longer used /* * Special IOCTL to allow keyboard input data to be fed * into the keyboard channel. */ case IOCTL_KEYBOARD_ICA_INPUT : /* * Make sure the input data is the correct size. */ if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength % sizeof(KEYBOARD_INPUT_DATA) ) return( STATUS_BUFFER_TOO_SMALL ); /* * We need a stack object to pass to IcaChannelInputInternal. * Any one will do so we grab the head of the stack list. * (There MUST be one for this IOCTL to succeed.) */ IcaLockConnection( pChannel->pConnect ); if ( IsListEmpty( &pChannel->pConnect->StackHead ) ) { IcaUnlockConnection( pChannel->pConnect ); return( STATUS_INVALID_DEVICE_REQUEST ); } pStack = CONTAINING_RECORD( pChannel->pConnect->StackHead.Flink, ICA_STACK, StackEntry ); IcaReferenceStack( pStack ); IcaUnlockConnection( pChannel->pConnect ); /* * Send keyboard input */ IcaChannelInputInternal( pStack, Channel_Keyboard, 0, NULL, (PCHAR)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength ); IcaDereferenceStack( pStack ); Status = STATUS_SUCCESS; break; #endif /* * The following keyboard ioctls use METHOD_NEITHER so get the * input buffer from the DeviceIoControl parameters. */ case IOCTL_KEYBOARD_ICA_LAYOUT : case IOCTL_KEYBOARD_ICA_SCANMAP : case IOCTL_KEYBOARD_ICA_TYPE : if ( Irp->RequestorMode != KernelMode ) { ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, TYPE_ALIGNMENT(BYTE) ); ProbeForWrite( Irp->UserBuffer, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, TYPE_ALIGNMENT(BYTE) ); } SdIoctl.IoControlCode = code; SdIoctl.InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; SdIoctl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; SdIoctl.OutputBuffer = Irp->UserBuffer; SdIoctl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; Status = IcaCallDriver( pChannel, SD$IOCTL, &SdIoctl ); break; /* * All other keyboard ioctls use METHOD_BUFFERED so get the * input buffer from the AssociatedIrp.SystemBuffer field. */ default: // Verify the buffer method. Method = code & 0x03; ASSERT( Method == METHOD_BUFFERED ); if ( Method != METHOD_BUFFERED ) { Status = STATUS_INVALID_DEVICE_REQUEST; } else { SdIoctl.IoControlCode = code; SdIoctl.InputBuffer = Irp->AssociatedIrp.SystemBuffer; SdIoctl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; SdIoctl.OutputBuffer = SdIoctl.InputBuffer; SdIoctl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; Status = IcaCallDriver( pChannel, SD$IOCTL, &SdIoctl ); if (Status == STATUS_SUCCESS ) Irp->IoStatus.Information = SdIoctl.BytesReturned; } break; } TRACECHANNEL(( pChannel, TC_ICADD, TT_API1, "ICADD: IcaDeviceControlKeyboard, fc %d, ref %u, 0x%x\n", (code & 0x3fff) >> 2, pChannel->RefCount, Status )); return( Status ); }