Windows-Server-2003/net/irda/comm/vuart/control.c

541 lines
12 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
send.c
Abstract:
This module contains the code that is very specific to initialization
and unload operations in the irenum driver
Author:
Brian Lieuallen, 7-13-2000
Environment:
Kernel mode
Revision History :
--*/
#include "internal.h"
typedef VOID (*CONTROL_CALLBACK)(
PVOID Context,
NTSTATUS Status
);
VOID
SendControlInfo(
CONNECTION_HANDLE ConnectionHandle,
CONTROL_CALLBACK CompletionRoutine,
PVOID Context,
UCHAR PI,
UCHAR PL,
UCHAR *PV
);
VOID
UartStateCompletion(
PVOID Context,
NTSTATUS Status
);
VOID
AccessUartState(
IRDA_HANDLE Handle,
PIRP Irp,
CONNECTION_CALLBACK Callback,
PVOID Context
)
{
PTDI_CONNECTION Connection=Handle;
PIO_STACK_LOCATION IrpSp=IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status=STATUS_SUCCESS;
CONNECTION_HANDLE ConnectionHandle;
PUCHAR SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
Irp->IoStatus.Information=0;
ADD_REFERENCE_TO_CONNECTION(Connection);
ASSERT(Connection->Uart.CompletionRoutine == NULL);
Connection->Uart.CurrentIrp=Irp;
Connection->Uart.CompletionContext=Context;
Connection->Uart.CompletionRoutine=Callback;
ConnectionHandle=GetCurrentConnection(Connection->LinkHandle);
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_SERIAL_SET_RTS:
case IOCTL_SERIAL_CLR_RTS: {
LONG NewState= IrpSp->Parameters.DeviceIoControl.IoControlCode==IOCTL_SERIAL_SET_RTS ? 1 : 0;
LONG OldState;
OldState=InterlockedExchange(&Connection->Uart.RtsState,NewState);
if (NewState != OldState) {
//
// state change
//
UCHAR ControlBuffer[1];
ControlBuffer[0] = PV_DTESetting_Delta_RTS;
ControlBuffer[0] |= NewState ? PV_DTESetting_RTS_High : 0;
ControlBuffer[0] |= Connection->Uart.DtrState ? PV_DTESetting_DTR_High : 0;
Status=STATUS_PENDING;
SendControlInfo(
ConnectionHandle,
UartStateCompletion,
Connection,
PI_DTESettings,
1,
ControlBuffer
);
}
break;
}
case IOCTL_SERIAL_SET_DTR:
case IOCTL_SERIAL_CLR_DTR: {
LONG NewState= IrpSp->Parameters.DeviceIoControl.IoControlCode==IOCTL_SERIAL_SET_DTR ? 1 : 0;
LONG OldState;
OldState=InterlockedExchange(&Connection->Uart.DtrState,NewState);
if (NewState != OldState) {
//
// state change
//
UCHAR ControlBuffer[1];
ControlBuffer[0] = PV_DTESetting_Delta_DTR;
ControlBuffer[0] |= Connection->Uart.RtsState ? PV_DTESetting_RTS_High : 0;
if (NewState) {
ControlBuffer[0] |= PV_DTESetting_DTR_High;
}
Status=STATUS_PENDING;
SendControlInfo(
ConnectionHandle,
UartStateCompletion,
Connection,
PI_DTESettings,
1,
ControlBuffer
);
}
break;
}
case IOCTL_SERIAL_GET_DTRRTS:
(*(PULONG)SystemBuffer) = Connection->Uart.DtrState ? SERIAL_DTR_STATE : 0;
(*(PULONG)SystemBuffer) |= Connection->Uart.RtsState ? SERIAL_RTS_STATE : 0;
Irp->IoStatus.Information=sizeof(ULONG);
Status=STATUS_SUCCESS;
break;
case IOCTL_SERIAL_GET_BAUD_RATE:
(*(PULONG)SystemBuffer) = Connection->Uart.BaudRate;
Irp->IoStatus.Information=sizeof(SERIAL_BAUD_RATE);
Status=STATUS_SUCCESS;
break;
case IOCTL_SERIAL_SET_BAUD_RATE: {
ULONG NewRate=(*(PULONG)SystemBuffer);
if (NewRate != Connection->Uart.BaudRate) {
//
// rate change
//
UCHAR ControlBuffer[4];
Connection->Uart.BaudRate=NewRate;
ControlBuffer[0]=(UCHAR)( NewRate >> 24);
ControlBuffer[1]=(UCHAR)( NewRate >> 16);
ControlBuffer[2]=(UCHAR)( NewRate >> 8);
ControlBuffer[3]=(UCHAR)( NewRate >> 0);
Status=STATUS_PENDING;
SendControlInfo(
ConnectionHandle,
UartStateCompletion,
Connection,
PI_DataRate,
4,
ControlBuffer
);
}
break;
}
case IOCTL_SERIAL_GET_LINE_CONTROL: {
PSERIAL_LINE_CONTROL LineControl=(PSERIAL_LINE_CONTROL)SystemBuffer;
RtlCopyMemory(
LineControl,
&Connection->Uart.LineControl,
sizeof(*LineControl)
);
Irp->IoStatus.Information=sizeof(*LineControl);
Status=STATUS_SUCCESS;
break;
}
case IOCTL_SERIAL_SET_LINE_CONTROL: {
PSERIAL_LINE_CONTROL LineControl=(PSERIAL_LINE_CONTROL)SystemBuffer;
if ((LineControl->StopBits != Connection->Uart.LineControl.StopBits)
||
(LineControl->Parity != Connection->Uart.LineControl.Parity)
||
(LineControl->WordLength != Connection->Uart.LineControl.WordLength)
) {
UCHAR ControlBuffer[1];
RtlCopyMemory(
&Connection->Uart.LineControl,
LineControl,
sizeof(*LineControl)
);
ControlBuffer[0] = (LineControl->WordLength - 5) & 0x03;
ControlBuffer[0] |= (LineControl->Parity == NO_PARITY) ? PV_DataFormat_No_Parity : PV_DataFormat_Yes_Parity;
ControlBuffer[0] |= (LineControl->StopBits == STOP_BIT_1) ? PV_DataFormat_1_Stop : PV_DataFormat_2_Stop;
if (LineControl->Parity != NO_PARITY) {
//
// set the parity type
//
ControlBuffer[0] |= ((LineControl->Parity -1) & 0x03) << 4;
}
Status=STATUS_PENDING;
SendControlInfo(
ConnectionHandle,
UartStateCompletion,
Connection,
PI_DataFormat,
1,
ControlBuffer
);
}
break;
}
case IOCTL_SERIAL_GET_MODEMSTATUS:
*(PULONG)SystemBuffer=Connection->Uart.ModemStatus;
Irp->IoStatus.Information=sizeof(ULONG);
Status=STATUS_SUCCESS;
break;
default:
ASSERT(0);
Status=STATUS_UNSUCCESSFUL;
break;
}
if (Status != STATUS_PENDING) {
Irp->IoStatus.Status=Status;
UartStateCompletion(
Connection,
Status
);
}
if (ConnectionHandle != NULL) {
ReleaseConnection(ConnectionHandle);
}
return;
}
VOID
UartStateCompletion(
PVOID Context,
NTSTATUS Status
)
{
PTDI_CONNECTION Connection = Context;
CONNECTION_CALLBACK Callback = Connection->Uart.CompletionRoutine;
PVOID UartContext= Connection->Uart.CompletionContext;
PIRP Irp = Connection->Uart.CurrentIrp;
Connection->Uart.CompletionRoutine=NULL;
Irp->IoStatus.Status=Status;
(Callback)(
UartContext,
Irp
);
REMOVE_REFERENCE_TO_CONNECTION(Connection);
return;
}
NTSTATUS
SendControlIrpCompletionRoutine(
PDEVICE_OBJECT DeviceObject,
PIRP BufferIrp,
PVOID Context
)
{
PIRCOMM_BUFFER Buffer=Context;
CONTROL_CALLBACK CompletionRoutine=Buffer->Context2;
PVOID CompletionContext=Buffer->Context;
NTSTATUS Status=BufferIrp->IoStatus.Status;
D_TRACE(DbgPrint("IRCOMM: ControlCompletionRoutine\n");)
Buffer->FreeBuffer(Buffer);
(CompletionRoutine)(
CompletionContext,
Status
);
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
SendControlInfo(
CONNECTION_HANDLE ConnectionHandle,
CONTROL_CALLBACK CompletionRoutine,
PVOID Context,
UCHAR PI,
UCHAR PL,
UCHAR *PV
)
{
PFILE_OBJECT FileObject;
PUCHAR Current;
PIRCOMM_BUFFER Buffer;
D_TRACE(
DbgPrint("IRCOMM: send Control, PI=%x, PL=%d, PV= ",PI,PL);
DumpBuffer(PV,PL);
DbgPrint("\n");
)
if (ConnectionHandle == NULL) {
//
// link down
//
(*CompletionRoutine)(
Context,
STATUS_SUCCESS
);
return;
}
Buffer=ConnectionGetBuffer(ConnectionHandle,BUFFER_TYPE_CONTROL);
//
// Make sure the buffer is big enough to actually hold the data that's going
// to be put into it.
//
if (Buffer == NULL || Buffer->BufferLength < ( (ULONG) PL + 3 ) ) {
(*CompletionRoutine)(
Context,
STATUS_INSUFFICIENT_RESOURCES
);
return;
}
FileObject=ConnectionGetFileObject(ConnectionHandle);
//
// actual data starts one byte in, after the length byte
//
Current=&Buffer->Data[1];
*Current=PI;
*(Current+1)=PL;
RtlCopyMemory(
Current+2,
&PV[0],
PL
);
//
// set the length of the control data, 2 bytes for PI and PL plus the length of PV
//
Buffer->Data[0]=2+PL;
//
// Length of the control data plus 1 for the length
//
Buffer->Mdl->ByteCount = Buffer->Data[0] + 1;
Buffer->Context = Context;
Buffer->Context2 = CompletionRoutine;
{
PDEVICE_OBJECT IrdaDeviceObject=IoGetRelatedDeviceObject(FileObject);
ULONG SendLength;
IoReuseIrp(Buffer->Irp,STATUS_SUCCESS);
Buffer->Irp->Tail.Overlay.OriginalFileObject = FileObject;
SendLength = MmGetMdlByteCount(Buffer->Mdl);
TdiBuildSend(
Buffer->Irp,
IrdaDeviceObject,
FileObject,
SendControlIrpCompletionRoutine,
Buffer,
Buffer->Mdl,
0, // send flags
SendLength
);
IoCallDriver(IrdaDeviceObject, Buffer->Irp);
}
ConnectionReleaseFileObject(ConnectionHandle,FileObject);
return;
}
typedef struct _SYNC_COMPLETION_BLOCK {
KEVENT Event;
NTSTATUS Status;
} SYNC_COMPLETION_BLOCK, *PSYNC_COMPLETION_BLOCK;
VOID
SetEventCompletion(
PVOID Context,
NTSTATUS Status
)
{
PSYNC_COMPLETION_BLOCK CompletionBlock=Context;
D_TRACE(DbgPrint("IRCOMM: SetEventCompletionRoutine\n");)
CompletionBlock->Status=Status;
KeSetEvent(&CompletionBlock->Event,IO_NO_INCREMENT,FALSE);
return;
}
NTSTATUS
SendSynchronousControlInfo(
CONNECTION_HANDLE ConnectionHandle,
UCHAR PI,
UCHAR PL,
UCHAR *PV
)
{
SYNC_COMPLETION_BLOCK CompletionBlock;
KeInitializeEvent(
&CompletionBlock.Event,
NotificationEvent,
FALSE
);
SendControlInfo(
ConnectionHandle,
SetEventCompletion,
&CompletionBlock,
PI,
PL,
PV
);
KeWaitForSingleObject(
&CompletionBlock.Event,
Executive,
KernelMode,
FALSE,
NULL
);
return CompletionBlock.Status;
}