541 lines
12 KiB
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;
|
|
|
|
}
|